/* CxC: densidad visual uniforme para formularios y grids del módulo. */
/* CxP: densidad uniforme para todos los grids de documentos, pagos, detalles y reportes. */
.tp-cxp-grid,
.tp-cxp-grid th,
.tp-cxp-grid td,
.tp-cxp-grid .form-control,
.tp-cxp-grid .form-select,
.tp-cxp-grid .btn {
  font-size: 13px;
}

/* Portal cliente: densidad compacta para grids y formularios, sin alterar el backoffice. */
.tp-portal-cliente .tp-tab-panel,
.tp-portal-cliente .tp-tab-panel table,
.tp-portal-cliente .tp-tab-panel .form-control,
.tp-portal-cliente .tp-tab-panel .form-select,
.tp-portal-cliente .tp-tab-panel .form-check-label,
.tp-portal-cliente .tp-tab-panel .form-text,
.tp-portal-cliente .tp-tab-panel label,
.tp-portal-cliente .tp-tab-panel .btn,
.tp-portal-cliente .tp-tab-panel .table {
  font-size: 13px;
}

#formCliente,
#formCliente .form-control,
#formCliente .form-select,
#formCliente .form-check-label,
#formCliente .form-text,
#formCliente .btn,
#formPagoComplemento,
#formTimbrarPago,
#formPagoComplemento .form-control,
#formPagoComplemento .form-select,
#formPagoComplemento .form-check-label,
#formPagoComplemento .form-text,
#formPagoComplemento .btn,
.tp-cxc-formulario,
.tp-cxc-formulario table,
.tp-cxc-grid,
.tp-cxc-grid table,
.tp-cxc-grid .form-control,
.tp-cxc-grid .form-select,
.tp-cxc-grid .btn {
  font-size: 13px;
}

/* Facturación: misma densidad visual para formularios, grids y reportes operativos. */
#formFactura,
#formFactura .form-control,
#formFactura .form-select,
#formFactura .form-check-label,
#formFactura .form-text,
#formFactura .btn,
#formTimbrar,
#formReenviarCorreo,
#formFiltrosFacturas,
#formFiltrosPorFacturar,
#formFiltrosFacturas .form-control,
#formFiltrosFacturas .form-select,
#formFiltrosPorFacturar .form-control,
#formFiltrosPorFacturar .form-select,
.tp-facturacion-form,
.tp-facturacion-form table,
.tp-facturacion-grid,
.tp-facturacion-grid table,
.tp-facturacion-grid .form-control,
.tp-facturacion-grid .form-select,
.tp-facturacion-grid .btn {
  font-size: 13px;
}

/* Catálogo de productos: misma densidad visual que CxC/Facturación. */
#formProducto,
#formProducto .form-control,
#formProducto .form-select,
#formProducto .form-check-label,
#formProducto .form-text,
#formProducto .btn,
#formProducto label,
#panelProveedoresProducto,
#panelProveedoresProducto table,
#panelProveedoresProducto .form-control,
#panelProveedoresProducto .form-select,
#panelProveedoresProducto .btn {
  font-size: 13px;
}

/* ============================================
   TallerPro - Paleta de colores (tomada de la
   orden de recepción anexa: azul corporativo +
   fondo gris claro + tarjetas blancas)
   ============================================ */
:root {
  --color-primary: #2f5fa8;       /* Azul principal (logo TM, botones, links) */
  --color-primary-dark: #24487f;
  --color-primary-light: #eaf1fb; /* Fondo de badges/estatus */
  --color-bg: #eef1f5;            /* Fondo general de la página */
  --color-card: #ffffff;          /* Fondo de tarjetas/paneles */
  --color-border: #e3e7ed;
  --color-text: #1f2937;
  --color-muted: #6b7280;
  --color-label: #4b5563;         /* antes #8a93a3 — muy claro para leerse rápido en labels/encabezados de mini-tabla */
  --radius-card: 14px;

  /* ===== Contraste de formularios/grids/paneles de filtro (ajuste global, ver conversación) =====
     Un solo set de valores para los 5 temas: el área de contenido (fondo/tarjetas/texto/inputs/
     grids) es compartida entre los 5 temas a propósito (ver comentario de abajo) — --tp-input-*
     y --tp-grid-* no necesitan su propio valor por tema, solo el foco/hover reusan
     --color-primary, que SÍ cambia por tema. */
  --tp-input-text: var(--color-text);        /* casi negro — el valor capturado, máximo contraste */
  --tp-input-border: #cbd2dc;                /* borde visible en reposo (antes heredaba el gris muy tenue de Bootstrap) */
  --tp-input-border-focus: var(--color-primary);
  --tp-input-placeholder: var(--color-muted); /* el gris claro se reserva SOLO para placeholder */

  --tp-grid-header-text: #111827;   /* negro/casi negro — lo primero que se lee en un grid */
  --tp-grid-row-text: var(--color-text);
  --tp-grid-row-hover-bg: #e9edf3; /* neutro (no ligado al tema) para distinguirse tanto de la franja blanca como de la de color */

  --tp-subtotal-bg: #e5e7eb;
  --tp-subtotal-text: #111827;
  --tp-total-general-bg: #d1d5db;  /* un tono más marcado que el subtotal, misma jerarquía visual */
  --tp-total-general-text: #111827;

  /* ===== Tema de color por usuario (ver includes/menu.php picker + UsuarioModel) =====
     Estas son las variables que SÍ cambian entre temas — solo el sidebar y el "acento" (botones
     primarios, badges informativos, nav activo). El área de contenido (--color-bg/--color-card/
     --color-text/--color-border) se queda igual en los 5 temas a propósito: es "sidebar con
     color, contenido siempre legible en claro", no un modo oscuro completo — reescribir tablas,
     inputs y modales de Bootstrap para modo oscuro es un proyecto aparte, no lo que pidió este
     selector. Los valores de acá son los defaults ("actual"); .tema-purple/teal/blue/dark los
     sobreescriben más abajo. */
  --sidebar-bg: var(--color-card);
  --sidebar-border: var(--color-border);
  --sidebar-text: var(--color-text);
  --sidebar-text-muted: var(--color-muted);
  --sidebar-hover-bg: var(--color-primary-light);
  --active-bg: var(--color-primary-light);
  --active-text: var(--color-primary);
}

/* "Actual" == los defaults de :root de arriba, explícito aquí nada más para que quede
   documentado (header.php siempre imprime alguna clase tema-*, incluida esta). */
.tema-actual {
}

.tema-purple {
  --color-primary: #4F46E5;
  --color-primary-dark: #3C3489;
  --color-primary-light: #F4F3FC;
  --sidebar-bg: #1E1B3C;
  --sidebar-border: #1E1B3C;
  --sidebar-text: #C7C4E0;
  --sidebar-text-muted: #9B98B8;
  --sidebar-hover-bg: rgba(255, 255, 255, 0.08);
  --active-bg: #4F46E5;
  --active-text: #FFFFFF;
}

.tema-teal {
  --color-primary: #0F6E56;
  --color-primary-dark: #085041;
  --color-primary-light: #E1F5EE;
  --sidebar-bg: #0C2622;
  --sidebar-border: #0C2622;
  --sidebar-text: #B7D8CF;
  --sidebar-text-muted: #7FA79B;
  --sidebar-hover-bg: rgba(255, 255, 255, 0.08);
  --active-bg: #0F6E56;
  --active-text: #FFFFFF;
}

.tema-blue {
  --color-primary: #185FA5;
  --color-primary-dark: #0C447C;
  --color-primary-light: #E6F1FB;
  --sidebar-bg: #0C233B;
  --sidebar-border: #0C233B;
  --sidebar-text: #B9CBE0;
  --sidebar-text-muted: #7C93AE;
  --sidebar-hover-bg: rgba(255, 255, 255, 0.08);
  --active-bg: #185FA5;
  --active-text: #FFFFFF;
}

/* A diferencia de purple/teal/blue, "dark" en el prompt original oscurecía también el fondo de
   badges/chips del contenido (--color-primary-light casi negro) — aquí NO, porque el área de
   contenido se queda clara en los 5 temas (ver comentario en :root): con --color-primary-light
   oscuro pero la tarjeta/fondo de página blancos, un badge quedaría gris oscuro sobre blanco con
   texto gris oscuro encima — bajo contraste, casi ilegible. Se ajusta a un gris claro neutro para
   que badges/botones seguan legibles sobre el contenido claro; el sidebar sí queda negro/gris
   oscuro como pide el tema. */
.tema-dark {
  --color-primary: #5F5E5A;
  --color-primary-dark: #46453F;
  --color-primary-light: #ECEBE8;
  --sidebar-bg: #000000;
  --sidebar-border: #000000;
  --sidebar-text: #B4B2A9;
  --sidebar-text-muted: #888780;
  --sidebar-hover-bg: rgba(255, 255, 255, 0.06);
  --active-bg: #5F5E5A;
  --active-text: #FFFFFF;
}

body {
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
}

/* ===== Contraste de formularios (inputs/selects/textarea de Bootstrap) — ver variables
   --tp-input-* en :root. Bootstrap ya trae un valor default para color/border, pero sin variable
   propia del proyecto no queda un solo lugar para ajustarlo; esto centraliza el punto único de
   verdad para labels/inputs/grids que pide cualquier pantalla nueva. ===== */
.form-control,
.form-select,
textarea.form-control {
  color: var(--tp-input-text);
  border-color: var(--tp-input-border);
}

.form-control:focus,
.form-select:focus {
  border-color: var(--tp-input-border-focus);
  outline: none;
  /* color-mix (CSS Color 4, soportado en navegadores evergreen): el halo de foco se tiñe con el
     acento del tema activo (--color-primary) sin tener que hardcodear un rgba() distinto por
     cada uno de los 5 temas. */
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tp-input-border-focus) 20%, transparent);
}

.form-control::placeholder {
  color: var(--tp-input-placeholder);
  opacity: 1; /* Firefox baja la opacidad del placeholder por default */
}

/* Botón "Buscar" de paneles de filtro/reportes (ej. Contabilidad > Diario General): antes usaba
   el azul default de Bootstrap (--bs-primary), sin relación con el acento del tema activo del
   usuario. .btn-primary (sólido) ya estaba ligado a --color-primary; faltaba el outline. */
.btn-outline-primary {
  color: var(--color-primary);
  border-color: var(--color-primary);
}
.btn-outline-primary:hover,
.btn-outline-primary:focus {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}

/* ===== Contraste de grids/listados — aplica vía .tp-grid/.tp-tabla-paginada, los envoltorios
   que ya usan ~50 listados del sistema (ver comentario más abajo en este archivo), así que el
   ajuste se propaga solo a toda pantalla existente y nueva sin tocar vista por vista. ===== */
.tp-grid thead th,
.tp-tabla-paginada thead th {
  color: var(--tp-grid-header-text);
}

.tp-grid tbody td,
.tp-tabla-paginada tbody td {
  color: var(--tp-grid-row-text);
}

.tp-grid tbody tr:hover > td,
.tp-tabla-paginada tbody tr:hover > td {
  background-color: var(--tp-grid-row-hover-bg);
}

/* Fila de subtotal (ej. "Total póliza X" del Diario General) y fila de "Total general" al pie de
   un reporte agrupado — mismo patrón reutilizable para pólizas, cortes de caja, estados de
   cuenta, etc. Jerarquía visual: dato normal < subtotal < total general. */
.tp-fila-subtotal > td,
.tp-fila-subtotal > th {
  background-color: var(--tp-subtotal-bg);
  color: var(--tp-subtotal-text);
  font-weight: 700;
}

.tp-fila-total-general > td,
.tp-fila-total-general > th {
  background-color: var(--tp-total-general-bg);
  color: var(--tp-total-general-text);
  font-weight: 700;
}

/* ===== Contención de scroll del layout raíz (sidebar + .tp-content, ver views/layout/
   header.php: <body><div class="d-flex"><aside class="tp-sidebar">...<main class="tp-content">).
   Antes, .tp-sidebar solo tenía min-height:100vh (no height), así que al expandir todos los
   submenús el elemento simplemente crecía más alto que el viewport en vez de activar su propio
   overflow-y:auto — y como body no tenía altura fija, el documento COMPLETO crecía con él
   (bug real: scroll de toda la página en vez de scroll solo del menú). Con html/body/wrapper
   fijos a 100%/100vh + overflow:hidden, cada columna de abajo (.tp-sidebar/.tp-content) sí puede
   scrollear de forma independiente dentro de su propio overflow-y:auto.
   Envuelto en @media screen a propósito: print.css depende de que el documento fluya libre entre
   páginas físicas al imprimir (Recepción/Cotizaciones) — overflow:hidden en pantalla no debe
   tocar ese flujo. No afecta el fix de ancho ya existente en .tp-content (min-width:0, más abajo
   en este archivo) — ese es el eje horizontal, este es el eje vertical, no chocan. ===== */
@media screen {
  html, body {
    height: 100%;
    overflow: hidden;
  }

  body > .d-flex {
    height: 100vh;
    overflow: hidden;
  }
}

/* Ícono real (Logo_mini_saversae.png) del sidebar — mismo ícono en compacto/cerrado y en
   expandido/móvil, reemplaza al antiguo badge de texto "SAE" (".tp-logo", retirado). */
.tp-logo-mini {
  display: flex;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  object-fit: contain;
  flex-shrink: 0;
}

/* Tarjetas / paneles de sección */
.tp-card {
  background: var(--color-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 1.5rem;
  margin-bottom: 1.25rem;
}

/* Número de sección (01, 02, 03...) */
.tp-step-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--color-primary-light);
  color: var(--color-primary);
  font-weight: 700;
  font-size: 0.8rem;
  margin-right: 0.5rem;
}

.tp-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--color-label);
  text-transform: uppercase;
}

/* Ícono "?" de ayuda junto a una label (ver views/catalogos/impuestos/form.php): tooltip de
   Bootstrap con la explicación del campo — normal-case y sin negrita, a diferencia de .tp-label,
   para no verse como parte del texto de la etiqueta. */
.tp-ayuda-icono {
  display: inline-flex;
  cursor: help;
  color: var(--color-label);
  opacity: 0.7;
  vertical-align: middle;
  text-transform: none;
  letter-spacing: normal;
}
.tp-ayuda-icono:hover,
.tp-ayuda-icono:focus {
  opacity: 1;
  outline: none;
}
.tp-ayuda-icono .material-symbols-outlined {
  font-size: 15px;
}

/* Título de sección dentro de un formulario (ej. "Datos fiscales", "Sello digital (CSD)"):
   banda de fondo azul tenue que separa visualmente los bloques de campos. Aplica sobre
   cualquier elemento de bloque (h6, div) que agrupe un tramo del formulario — no se liga a
   <fieldset>/<legend> porque el proyecto no los usa para esto. */
.tp-form-section-title {
  display: block;
  width: 100%;
  box-sizing: border-box;
  background: var(--color-primary-light);
  color: var(--color-primary);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.02em;
  padding: 0.5rem 0.85rem;
  border-left: 4px solid var(--color-primary);
  border-radius: 4px;
  margin-bottom: 0.85rem;
}

/* Select con búsqueda integrada (ej. elegir cliente al capturar un vehículo) */
.tp-select-search {
  position: relative;
}

.tp-select-search-panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 20;
  background: var(--color-card);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  max-height: 280px;
  overflow-y: auto;
}

/* Resaltado por teclado (.tp-resaltado) con el MISMO tratamiento que el hover de mouse —
   reutiliza las variables de Bootstrap en vez de duplicar un color propio. */
.tp-select-search-panel .list-group-item-action:hover,
.tp-select-search-panel .list-group-item-action.tp-resaltado {
  z-index: 1;
  color: var(--bs-list-group-action-hover-color, var(--color-primary));
  background-color: var(--bs-list-group-action-hover-bg, var(--color-primary-light));
}

/* Marco de imagen del producto (catálogo de productos): clic abre el explorador de archivos,
   arrastrar-y-soltar también funciona (.tp-img-producto-marco--dragover resalta el borde). */
.tp-img-producto-marco {
  width: 140px;
  height: 140px;
  border: 2px dashed var(--color-border);
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  cursor: pointer;
  background: var(--color-card);
  flex-shrink: 0;
}

.tp-img-producto-marco img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.tp-img-producto-marco .material-symbols-outlined {
  font-size: 2.5rem;
  color: var(--color-border);
}

.tp-img-producto-marco--dragover {
  border-color: var(--color-primary);
  background: var(--color-primary-light);
}

/* Miniatura del producto en el buscador de POS (Nueva venta) — a propósito más grande que la
   del grid de Catálogos: aquí es lo primero que ayuda a identificar visualmente el producto
   correcto antes de agregarlo al ticket, no importa que la fila del <select> quede más alta. */
.tp-pos-sugerencia-img {
  width: 84px;
  height: 84px;
  object-fit: contain;
  border-radius: 6px;
  border: 1px solid var(--color-border);
  background: var(--color-card);
  flex-shrink: 0;
}

.tp-pos-sugerencia-img--vacia {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.7rem;
  color: var(--color-border);
}

/* Miniatura del producto en el grid de Catálogos > Productos */
.tp-grid-producto-img {
  width: 36px;
  height: 36px;
  object-fit: contain;
  border-radius: 6px;
  border: 1px solid var(--color-border);
  background: var(--color-card);
  cursor: pointer;
}

/* Barra de búsqueda/filtros fija al hacer scroll en listados largos (ej. Lista de precios) —
   clase opt-in, no el default de todos los grids. Sticky es relativo al padding-box del
   contenedor con scroll propio más cercano (.tp-content, ver el bloque "Contención de scroll
   del layout raíz" arriba), así que basta top:0 sin tocar el layout del resto de la página.
   Fondo y sombra propios para que se note la elevación cuando queda pegada sobre la tabla. */
.tp-filtro-sticky {
  position: sticky;
  top: 0;
  z-index: 5;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.06);
}

/* Igual que .tp-filtro-sticky, pero para pegar TODO el encabezado del grid (título + botones de
   acción + barra de búsqueda/filtros) en un solo bloque, no solo la barra de filtros — para
   listados donde se quiere que "Nueva cuenta"/"Excel"/"Buscar" queden siempre a la mano sin
   tener que subir el scroll. A diferencia de .tp-filtro-sticky (que se aplica sobre un .tp-card
   que ya trae su propio fondo), este wrapper normalmente envuelve elementos SIN fondo propio
   (el título va suelto, sin tarjeta), así que necesita su propio background para no dejar ver
   las filas de la tabla debajo al quedar fijo. */
.tp-encabezado-sticky {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--color-bg);
  padding-bottom: 0.5rem;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.06);
}

/* Franjas alternadas (zebra), aplicadas por default a TODOS los grids del sistema: cualquier
   tabla dentro de .tp-tabla-paginada (el envoltorio que ya usan los ~50 listados del sistema —
   ver assets/js/paginacion.js) hereda el mismo tratamiento probado primero en Lista de precios.
   .tp-tabla-zebra queda como clase suelta equivalente para el caso excepcional de una tabla que
   no use ese envoltorio.
   La fila par usa --color-primary-light (el mismo "claro" del tema de color que el usuario ya
   eligió — ver el picker de temas en includes/menu.php), así la franja cambia junto con el
   tema en vez de quedar fija; la fila impar es blanca (--color-card) para el contraste.
   Se pinta en las celdas (> td), no en el <tr>: Bootstrap 5.3 aplica su propio
   background-color a cada td/th vía ".table > :not(caption) > * > *", que de otro modo tapa
   por completo cualquier fondo puesto solo en la fila. */
.tp-tabla-paginada table tbody tr:nth-child(odd) > td,
.tp-tabla-zebra tbody tr:nth-child(odd) > td {
  background-color: var(--color-card);
}
.tp-tabla-paginada table tbody tr:nth-child(even) > td,
.tp-tabla-zebra tbody tr:nth-child(even) > td {
  background-color: var(--color-primary-light);
}

/* Resalta brevemente la fila de un grid paginado a la que el usuario vuelve tras editar/eliminar
   un registro (ver assets/js/paginacion.js) — "el puntero" que antes se perdía al regresar.
   box-shadow (no background-color) a propósito: así no compite en especificidad con el zebra
   de arriba ni con ningún otro fondo de fila y se ve igual en filas pares e impares. */
.tp-fila-recordada > td {
  animation: tpFilaRecordadaFade 2.5s ease-out;
}
@keyframes tpFilaRecordadaFade {
  0% { box-shadow: inset 0 0 0 999px rgba(47, 95, 168, 0.18); }
  100% { box-shadow: inset 0 0 0 999px rgba(47, 95, 168, 0); }
}

/* Avatar circular con iniciales (ej. tarjeta de cliente seleccionado) */
.tp-avatar-circle {
  width: 48px;
  height: 48px;
  min-width: 48px;
  border-radius: 50%;
  background: var(--color-primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1rem;
}

.tp-badge-estatus {
  background: var(--color-primary-light);
  color: var(--color-primary);
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-inactivo {
  background: #fde8e8;
  color: #c0392b;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

/* ===== Filas de agrupado/subtotal por producto (views/inventario/balanza) ===== */
.tp-fila-grupo td {
  background: var(--color-primary-light);
  color: var(--color-primary);
}

.tp-fila-subtotal td {
  background: rgba(0, 0, 0, 0.035);
  border-top: 1px solid var(--color-border);
}

/* ===== Badges de estatus de cotización (views/cotizaciones) ===== */
.tp-badge-pendiente {
  background: var(--color-primary-light);
  color: var(--color-primary);
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-aprobada {
  background: #e8f8ef;
  color: #1e8449;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-facturada {
  background: #fff0db;
  color: #a65300;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-rechazada {
  background: #fde8e8;
  color: #c0392b;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-vencida {
  background: #eceff1;
  color: #607d8b;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

/* ===== Estatus derivados del grid de órdenes de compra (views/compras/index.php) ===== */
.tp-badge-retenida {
  background: #fdf1e3;
  color: #d68910;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-parcial-recepcion {
  background: #fef9e7;
  color: #b7950b;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

/* ===== Estatus de Órdenes de servicio (views/srv_ordenes/index.php) — un color por estatus en
   vez del único badge genérico de antes, para distinguirlos de un vistazo. 'Cancelado' en rojo
   (mismo tono que .tp-badge-inactivo/.tp-badge-rechazada) es el caso pedido explícitamente por el
   usuario. 'Aprobado' reutiliza .tp-badge-aprobada (ya definida arriba, mismo significado). ===== */
.tp-badge-srv-cotizacion {
  background: #fdf1dc;
  color: #c9860f;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-srv-enproceso {
  background: var(--color-primary-light);
  color: var(--color-primary);
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-srv-esperando {
  background: #eaeef1;
  color: #5f6b76;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-srv-terminado {
  background: #dcf3ea;
  color: #178a58;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-srv-entregado {
  background: #ede7f6;
  color: #5e35b1;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-srv-facturado {
  background: #fde9d0;
  color: #b9600a;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

.tp-badge-cancelado {
  background: #fde8e8;
  color: #c0392b;
  font-weight: 600;
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  font-size: 0.8rem;
}

/* Ícono de "Nota de la partida" (Cotizaciones/Órdenes de servicio SRV, ver views/srv_cotizaciones/
   form.php y views/srv_ordenes/form.php) — se pinta como post-it amarillo en cuanto la partida
   tiene texto capturado, para detectarla de un vistazo entre las demás filas. */
.tp-cot-btn-nota.tiene-nota {
  background: #fff3cd;
  border-color: #f0c94a;
  color: #8a6d00;
}
.tp-cot-btn-nota.tiene-nota:hover {
  background: #ffe9a8;
  border-color: #f0c94a;
  color: #8a6d00;
}

.btn-primary {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
}
.btn-primary:hover {
  background-color: var(--color-primary-dark);
  border-color: var(--color-primary-dark);
}

/* ===== Sidebar tipo imagen 2 (menú TallerPro) =====
   Modo compacto (solo íconos, 64px) por defecto en escritorio; se expande a 300px con
   :hover o cuando queda fijo (.tp-sidebar--fijo, ver assets/js/sidebar.js). 300px (en vez de
   260px) es el mínimo que evita que textos largos como "Catálogos del sistema" se encimen con
   la flecha de abrir/cerrar. En móvil se comporta como offcanvas (ver medias queries al final
   de este bloque). */
.tp-sidebar {
  width: 300px;
  min-height: 100vh; /* respaldo si @media screen no aplica (ej. algún user-agent raro) */
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  border-right: 1px solid var(--sidebar-border);
  padding: 1rem 0.75rem;
  overflow-x: hidden;
  overflow-y: auto;
  flex-shrink: 0;
}

/* height:100% (no min-height): así overflow-y:auto de arriba sí se activa cuando el menú
   expandido crece más que el viewport, en vez de empujar la altura de todo el documento. */
@media screen {
  .tp-sidebar {
    height: 100%;
  }
}

.tp-sidebar .material-symbols-outlined {
  font-size: 20px;
}

.tp-content {
  padding: 1.5rem;
  min-width: 0; /* evita que el flex item empuje el ancho del layout al colapsar el sidebar */
}

/* Columna de contenido (tabs + panel activo) con scroll propio, independiente del sidebar —
   mismo criterio que .tp-sidebar de arriba, ver el bloque de comentario junto a "html, body"
   al inicio de este archivo. overflow-x:hidden aquí es refuerzo del fix de ancho ya existente
   (min-width:0 arriba): el scroll horizontal real sigue viviendo en cada .table-responsive
   interno, nunca debería necesitarse a este nivel. */
@media screen {
  .tp-content {
    height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
  }
}

.tp-sidebar-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  min-height: 44px;
}

.tp-sidebar-brand {
  flex-grow: 1;
  min-width: 0;
  white-space: nowrap;
}

/* Antes usaba Bootstrap .text-muted (color fijo con !important, no theming posible) — por eso
   "Sistema Administrativo" se veía invisible en los temas de sidebar oscuro (texto oscuro fijo
   sobre fondo oscuro). Clase propia para poder usar --sidebar-text-muted. */
.tp-sidebar-brand-sub {
  color: var(--sidebar-text-muted);
  /* Subtítulo largo ("Sistema Administrativo Empresarial V1.0") — permite que envuelva a una
     segunda línea, a diferencia del título (fw-bold), que sigue en una sola línea por el
     white-space:nowrap heredado de .tp-sidebar-brand. */
  white-space: normal;
  line-height: 1.15;
}

.tp-sidebar-pin {
  background: none;
  border: none;
  color: var(--sidebar-text-muted);
  border-radius: 8px;
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.tp-sidebar-pin:hover {
  background: var(--sidebar-hover-bg);
  color: var(--sidebar-text);
}

.tp-sidebar-pin.active {
  color: var(--active-text);
  background: var(--active-bg);
}

.tp-sidebar-rol {
  white-space: nowrap;
}

/* Contexto operativo: evita capturar, cobrar o facturar sin identificar la sucursal activa. */
.tp-sidebar-sucursal {
  display: flex;
  align-items: flex-start;
  gap: 0.45rem;
  margin: 0.55rem 0 0.7rem;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--sidebar-border);
  border-radius: 8px;
  background: var(--sidebar-hover-bg);
  color: var(--sidebar-text);
  white-space: normal;
}
.tp-sidebar-sucursal .material-symbols-outlined { color: var(--active-text); margin-top: 0.1rem; }
.tp-sidebar-sucursal small, .tp-sidebar-sucursal strong { display: block; overflow: hidden; text-overflow: ellipsis; }
.tp-sidebar-sucursal small { color: var(--sidebar-text-muted); font-size: 0.75rem; }
.tp-sidebar-sucursal strong { max-width: 210px; font-size: 0.8rem; }

/* Bandeja de seguimiento debajo del usuario. En escritorio se oculta junto con el resto
   de la identidad cuando el sidebar está compacto; al expandirse no desplaza el contenido
   porque el panel queda contenido dentro del propio sidebar. */
.tp-avisos {
  position: relative;
  margin: 0.55rem 0 0.7rem;
  white-space: normal;
}

.tp-avisos-boton {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  border: 1px solid var(--sidebar-border);
  border-radius: 8px;
  padding: 0.42rem 0.55rem;
  background: var(--sidebar-hover-bg);
  color: var(--sidebar-text);
  font-size: 0.82rem;
  cursor: pointer;
  text-align: left;
}

.tp-avisos-boton:hover,
.tp-avisos-boton[aria-expanded="true"] {
  background: var(--active-bg);
  color: var(--active-text);
}

.tp-avisos-boton .material-symbols-outlined {
  font-size: 18px;
}

.tp-avisos-contador {
  margin-left: auto;
  min-width: 20px;
  padding: 0.14rem 0.35rem;
  border-radius: 999px;
  background: #dc3545;
  color: #fff;
  font-size: 0.7rem;
  line-height: 1.2;
  font-weight: 700;
  text-align: center;
}

.tp-avisos-menu {
  position: absolute;
  z-index: 1080;
  top: calc(100% + 0.35rem);
  left: 0;
  width: min(360px, calc(100vw - 1.5rem));
  border: 1px solid var(--color-border);
  border-radius: 10px;
  background: var(--color-card);
  color: var(--color-text);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.2);
  overflow: hidden;
}

/* Cuando el sidebar tiene overflow-y:auto, cualquier descendiente absoluto queda
   recortado por sus límites aunque tenga un z-index mayor. El JS convierte el menú
   en un elemento fixed dentro de body al abrirlo, para que pueda invadir el área
   de trabajo sin alterar el ancho ni el scroll del sidebar. */
.tp-avisos-menu.tp-avisos-menu--flotante {
  position: fixed;
  z-index: 2000;
  margin: 0;
}

.tp-avisos-menu-cabecera,
.tp-avisos-ver-todos {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.65rem 0.75rem;
  font-size: 0.8rem;
}

.tp-avisos-menu-cabecera {
  border-bottom: 1px solid var(--color-border);
}

.tp-avisos-lista {
  max-height: 360px;
  overflow-y: auto;
}

.tp-aviso-item,
.tp-aviso-fila {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  color: inherit;
  text-decoration: none;
}

.tp-aviso-item {
  padding: 0.65rem 0.75rem;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.76rem;
}

.tp-aviso-item:hover,
.tp-aviso-fila:hover {
  background: var(--color-hover, rgba(47, 95, 168, 0.08));
}

.tp-aviso-item.no-leido,
.tp-aviso-fila.no-leido {
  background: rgba(47, 95, 168, 0.08);
}

.tp-aviso-item-icono,
.tp-aviso-fila-icono {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(47, 95, 168, 0.12);
  color: var(--color-primary);
}

.tp-aviso-item-icono .material-symbols-outlined,
.tp-aviso-fila-icono .material-symbols-outlined {
  font-size: 17px;
}

.tp-aviso-item-cuerpo,
.tp-aviso-fila-cuerpo {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
}

.tp-aviso-item-cuerpo > span:not(.tp-aviso-item-titulo),
.tp-aviso-fila-cuerpo > span:not(.tp-aviso-fila-titulo) {
  color: var(--color-muted);
  line-height: 1.3;
}

.tp-aviso-item-titulo,
.tp-aviso-fila-titulo {
  font-weight: 700;
  color: var(--color-text);
}

.tp-aviso-item-meta,
.tp-aviso-fila-meta {
  font-size: 0.7rem;
  color: var(--color-muted);
}

.tp-aviso-no-leido {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  margin: 0.35rem 0 0 auto;
  border-radius: 50%;
  background: #dc3545;
}

.tp-avisos-vacio {
  padding: 1rem 0.75rem;
  color: var(--color-muted);
  font-size: 0.78rem;
  text-align: center;
}

.tp-avisos-ver-todos {
  justify-content: center;
  border-top: 1px solid var(--color-border);
  color: var(--color-primary);
  font-weight: 600;
}

.tp-avisos-ver-todos:hover {
  background: var(--color-hover, rgba(47, 95, 168, 0.08));
}

.tp-avisos-pagina {
  overflow: hidden;
}

.tp-avisos-depuracion {
  border-left: 4px solid #d97706;
}

.tp-avisos-depuracion .material-symbols-outlined {
  font-size: 21px;
}

.tp-aviso-fila {
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--color-border);
}

.tp-aviso-fila:last-child {
  border-bottom: 0;
}

.tp-aviso-fila-cuerpo {
  font-size: 0.88rem;
}

.tp-aviso-fila-estado {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  width: fit-content;
  margin-top: 0.2rem;
  padding: 0.14rem 0.42rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
}

.tp-aviso-fila-estado .material-symbols-outlined {
  font-size: 14px;
}

.tp-aviso-fila-estado.leido {
  color: #18794e;
  background: rgba(24, 121, 78, 0.1);
}

.tp-aviso-fila-estado.pendiente {
  color: #a33a2b;
  background: rgba(220, 53, 69, 0.1);
}

/* Selector de tema (swatches redondos) — ver includes/menu.php + assets/js/menu.js. --sw se fija
   inline por swatch (style="--sw:#..."); el aro de selección usa --sidebar-text para que se vea
   bien tanto en el tema claro (aro oscuro) como en los oscuros (aro claro). */
.tp-tema-swatches {
  display: flex;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.tp-tema-swatch {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid transparent;
  background: var(--sw);
  padding: 0;
  cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
}

.tp-tema-swatch.activo {
  border-color: var(--sidebar-text);
}

/* Ocultos por defecto: solo se muestran en la media query móvil de más abajo. */
.tp-sidebar-hamburger,
.tp-sidebar-backdrop {
  display: none;
}

/* ===== Menú de 2 niveles (módulo -> submenú) ===== */
.tp-menu-grupo {
  margin-bottom: 0.25rem;
}

.tp-menu-grupo-header {
  display: flex;
  align-items: stretch;
  border-radius: 10px;
}

.tp-menu-grupo-link {
  flex-grow: 1;
  min-width: 0;
  color: var(--sidebar-text);
  border-radius: 10px;
  padding: 0.6rem 0.75rem;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  /* Ahora es un <button> (ya no navega, solo abre/cierra su submenú): se le quita el
     estilo nativo de botón para que se vea igual que cuando era un <a>. */
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
}

.tp-menu-grupo-link:hover {
  background: var(--sidebar-hover-bg);
  color: var(--sidebar-text);
}

.tp-menu-grupo-link.active {
  background: var(--active-bg);
  color: var(--active-text);
}

.tp-menu-toggle {
  background: none;
  border: none;
  color: var(--sidebar-text-muted);
  padding: 0 0.5rem;
  display: flex;
  align-items: center;
  cursor: pointer;
}

.tp-menu-chevron {
  transition: transform 0.15s ease;
}

/* Combinador ">" a propósito (no descendiente): con el 3er nivel de menú (subgrupo anidado,
   ver includes/menu.php), un subgrupo vive DENTRO del .tp-submenu del grupo raíz — sin el
   ">" aquí, abrir el grupo raíz "filtraría" y giraría también la flecha del subgrupo anidado
   aunque ese siga cerrado. */
.tp-menu-grupo.abierto > .tp-menu-grupo-header .tp-menu-chevron {
  transform: rotate(90deg);
}

.tp-submenu {
  display: none;
  padding-left: 1.6rem;
  margin-top: 0.15rem;
}

.tp-menu-grupo.abierto > .tp-submenu {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

/* Subgrupo anidado (3er nivel, ej. Inventario > Catálogos > Almacenes): mismo componente
   .tp-menu-grupo reutilizado, con un poco menos de énfasis visual por estar un nivel más
   adentro. Su propio .tp-submenu ya hereda el padding-left normal, así los nietos quedan con
   doble indentación acumulada (correcto). */
.tp-menu-grupo--nested {
  margin-top: 0.1rem;
}

.tp-menu-grupo--nested > .tp-menu-grupo-header .tp-menu-grupo-link {
  font-weight: 500;
  font-size: 0.85rem;
  padding: 0.45rem 0.6rem;
}

.tp-menu-grupo--nested > .tp-menu-grupo-header .tp-menu-icono .material-symbols-outlined {
  font-size: 17px;
}

.tp-submenu-link {
  color: var(--sidebar-text-muted);
  border-radius: 8px;
  padding: 0.45rem 0.6rem;
  font-size: 0.85rem;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
}

.tp-submenu-link .material-symbols-outlined {
  font-size: 16px;
}

.tp-submenu-link:hover {
  background: var(--sidebar-hover-bg);
  color: var(--sidebar-text);
}

.tp-submenu-link.active {
  background: var(--active-bg);
  color: var(--active-text);
}

.tp-badge-contador {
  background: var(--color-primary);
  color: #fff;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  line-height: 1;
  padding: 0.25rem 0.45rem;
  white-space: nowrap;
}

.tp-badge-contador--alerta {
  background: #dc3545;
}

/* Envoltura cuadrada del ícono (módulo o submódulo): permite superponer el punto de
   badge en modo compacto y centra el ícono verticalmente en su franja de 64px. */
.tp-menu-icono {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}

/* Punto de color que sustituye al badge numérico cuando el sidebar está compacto. */
.tp-menu-dot {
  position: absolute;
  top: -1px;
  right: -1px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--color-primary);
  border: 2px solid var(--sidebar-bg);
  display: none;
}

.tp-menu-dot--alerta {
  background: #dc3545;
}

.tp-menu-texto {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  /* Salvaguarda: con 300px ya no debería hacer falta, pero si a futuro se agrega una etiqueta
     todavía más larga, que se recorte con "…" en vez de encimarse con la flecha de al lado. */
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ===== Escritorio (>=768px): sidebar compacto auto-ocultable, expande con hover ===== */
@media (min-width: 768px) {
  .tp-sidebar {
    width: 64px;
    transition: width 0.22s ease 0.22s; /* colapsar espera un respiro antes de animar */
  }

  .tp-sidebar:hover,
  .tp-sidebar.tp-sidebar--fijo {
    width: 300px;
    transition: width 0.22s ease 0s; /* expandir es inmediato */
  }

  .tp-sidebar-brand,
  .tp-sidebar-rol,
  .tp-sidebar-pin,
  .tp-menu-texto,
  .tp-menu-toggle {
    display: none;
  }

  .tp-menu-dot {
    display: block;
  }

  .tp-menu-grupo .tp-submenu {
    display: none;
  }

  .tp-sidebar:hover .tp-sidebar-brand,
  .tp-sidebar.tp-sidebar--fijo .tp-sidebar-brand,
  .tp-sidebar:hover .tp-sidebar-rol,
  .tp-sidebar.tp-sidebar--fijo .tp-sidebar-rol {
    display: block;
  }

  .tp-sidebar:hover .tp-sidebar-pin,
  .tp-sidebar.tp-sidebar--fijo .tp-sidebar-pin,
  .tp-sidebar:hover .tp-menu-texto,
  .tp-sidebar.tp-sidebar--fijo .tp-menu-texto,
  .tp-sidebar:hover .tp-menu-toggle,
  .tp-sidebar.tp-sidebar--fijo .tp-menu-toggle {
    display: flex;
  }

  .tp-sidebar:hover .tp-menu-grupo.abierto > .tp-submenu,
  .tp-sidebar.tp-sidebar--fijo .tp-menu-grupo.abierto > .tp-submenu {
    display: flex;
  }

  .tp-sidebar:hover .tp-menu-dot,
  .tp-sidebar.tp-sidebar--fijo .tp-menu-dot {
    display: none;
  }

  .tp-sidebar:not(:hover):not(.tp-sidebar--fijo) .tp-menu-grupo-link,
  .tp-sidebar:not(:hover):not(.tp-sidebar--fijo) .tp-submenu-link {
    justify-content: center;
    padding-left: 0.4rem;
    padding-right: 0.4rem;
  }

  .tp-sidebar-hamburger,
  .tp-sidebar-backdrop {
    display: none !important;
  }
}

/* ===== Móvil/tablet (<768px): sidebar offcanvas, oculto por defecto ===== */
@media (max-width: 767.98px) {
  .tp-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    width: 300px;
    max-width: 82vw;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    z-index: 1050;
  }

  .tp-sidebar.tp-sidebar--movil-abierto {
    transform: translateX(0);
    box-shadow: 8px 0 28px rgba(15, 23, 42, 0.18);
  }

  .tp-sidebar-hamburger {
    position: fixed;
    top: 0.75rem;
    left: 0.75rem;
    z-index: 1030;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    border: 1px solid var(--color-border);
    background: var(--color-card);
    color: var(--color-text);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.1);
  }

  .tp-sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.35);
    z-index: 1040;
  }

  .tp-sidebar.tp-sidebar--movil-abierto ~ .tp-sidebar-backdrop {
    display: block;
  }
}

/* ===== Badges de tipo (Dashboard/Form/Grid/Chart/Control) ===== */
.tp-badge-tipo {
  display: inline-block;
  border-radius: 999px;
  padding: 0.2rem 0.65rem;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.tp-badge-tipo--dashboard { background: #f3e8fd; color: #8e44ad; }
.tp-badge-tipo--form      { background: var(--color-primary-light); color: var(--color-primary); }
.tp-badge-tipo--grid      { background: #e8f8ef; color: #1e8449; }
.tp-badge-tipo--chart     { background: #fde8f1; color: #c2185b; }
.tp-badge-tipo--control   { background: #fdf1e3; color: #d68910; }

/* ===== Tarjetas del dashboard por módulo ===== */
.tp-dash-card {
  background: var(--color-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 1.5rem 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.5rem;
  text-decoration: none;
  color: var(--color-text);
  height: 100%;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.tp-dash-card:hover {
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
  transform: translateY(-2px);
  color: var(--color-text);
}

.tp-dash-card-icono {
  font-size: 2.2rem;
  color: var(--color-primary);
}

.tp-dash-card-titulo {
  font-weight: 600;
}

/* ===== Menú de aplicación agrupado por categoría (hoy solo módulo Inventario) =====
   Diseño importado de Claude Design "Rediseño menú Inventarios" (Menu Inventarios.dc.html),
   adaptado a fondo transparente (deja ver el fondo default de la pestaña) y en columnas
   horizontales responsivas — una por categoría (Mantenimiento/Movimientos/Consultas/
   Configuración/Alertas) — ver tp_agrupar_por_categoria() en includes/menu_helpers.php y su uso
   en views/dashboard.php. */
.tp-menu-app-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.75rem 2.5rem;
  margin-top: 0.25rem;
}

.tp-menu-app-fila {
  display: flex;
  gap: 0.75rem;
  flex: 1 1 220px;
  min-width: 200px;
}

.tp-menu-app-fila-icono {
  flex-shrink: 0;
  width: 1.5rem;
  padding-top: 0.1rem;
  color: #5c5c5c;
}

.tp-menu-app-fila-icono .material-symbols-outlined {
  font-size: 1.3rem;
}

.tp-menu-app-fila-titulo {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--color-primary);
}

.tp-menu-app-fila-flecha {
  font-size: 0.65rem;
}

.tp-menu-app-fila-subtitulo {
  font-size: 0.78rem;
  color: var(--color-muted);
  margin: 0.15rem 0 0.5rem 1rem;
}

.tp-menu-app-fila-links {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-left: 1rem;
}

.tp-menu-app-link {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--color-text);
  text-decoration: none;
  width: fit-content;
}

.tp-menu-app-link:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

.tp-menu-app-badge {
  background: var(--color-primary);
  color: #fff;
  font-size: 0.65rem;
  border-radius: 9px;
  padding: 0.05rem 0.4rem;
}

/* Variante roja de alerta (ej. "Pendientes de entregar" de Punto de venta) — a diferencia del
   resto de los badges de este menú, que solo informan un conteo, este marca algo que requiere
   atención/acción del cajero. */
.tp-menu-app-badge--alerta {
  background: #dc3545;
}

/* Conteo compacto para órdenes que esperan cobro en caja. */
.tp-menu-app-badge--circulo {
  min-width: 1.2rem;
  height: 1.2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.2rem;
  line-height: 1;
  border-radius: 50%;
}

/* ===== Barra de pestañas (ver assets/js/tabs.js) ===== */
.tp-tabs {
  display: flex;
  align-items: flex-end;
  gap: 0.25rem;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 1.25rem;
  overflow-x: auto;
  min-height: 1px; /* evita salto de layout si aún no hay pestañas */
}

.tp-tab {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.75rem;
  background: #e5e9f0;
  color: var(--color-muted);
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 10px 10px 0 0;
  font-size: 0.85rem;
  font-weight: 600;
  font-family: inherit;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  position: relative;
}

.tp-tab[draggable="true"] {
  cursor: grab;
}

.tp-tab.dragging {
  opacity: 0.45;
}

.tp-tab.drop-target {
  border-left: 3px solid var(--color-primary);
}

.tp-tab .material-symbols-outlined {
  font-size: 16px;
}

.tp-tab.active {
  background: var(--color-card);
  color: var(--color-primary);
  border-color: var(--color-border);
  border-bottom: 2px solid var(--color-primary);
  margin-bottom: -1px;
}

.tp-tab-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  font-size: 14px !important;
  color: inherit;
}

.tp-tab-duplicate {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  font-size: 13px !important;
  color: inherit;
}

.tp-tab-duplicate:hover {
  background: rgba(0, 0, 0, 0.12);
}

.tp-tab-close:hover {
  background: rgba(0, 0, 0, 0.12);
}

.tp-tab-panels {
  position: relative;
}

.tp-contexto-sucursal {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 38px;
  margin: -0.65rem 0 1.1rem;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-primary);
  border-radius: 8px;
  background: var(--color-card);
  color: var(--color-text);
  font-size: 0.86rem;
}
.tp-contexto-sucursal > .material-symbols-outlined { color: var(--color-primary); font-size: 20px; }
.tp-contexto-sucursal-texto { display: flex; align-items: baseline; gap: 0.35rem; min-width: 0; }
.tp-contexto-sucursal-etiqueta, .tp-contexto-sucursal-nombre { color: var(--color-muted); }
.tp-contexto-sucursal-texto strong, .tp-contexto-sucursal-nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 575.98px) {
  .tp-contexto-sucursal-texto { flex-wrap: wrap; gap: 0.15rem 0.35rem; }
  .tp-contexto-sucursal-separador { display: none; }
  .tp-contexto-sucursal-nombre { flex-basis: 100%; }
}

.tp-tab-panel {
  display: none;
}

.tp-tab-panel.active {
  display: block;
}

.tp-tab-panel-cargando {
  opacity: 0.5;
  pointer-events: none;
}

.tp-progreso-sincronizacion {
  border-left: 4px solid var(--color-primary, #0d6efd);
}

.tp-progreso-indeterminado {
  width: 42%;
  animation: tp-progreso-sincronizacion 1.15s ease-in-out infinite;
}

.cxp-form-pago {
  font-size: 13px;
}

.cxp-form-pago .form-control,
.cxp-form-pago .form-select,
.cxp-form-pago .btn,
.cxp-form-pago .table,
.cxp-form-pago .tp-label {
  font-size: 13px;
}

.cxp-form-documento {
  font-size: 13px;
}

.cxp-form-documento .form-control,
.cxp-form-documento .form-select,
.cxp-form-documento .btn,
.cxp-form-documento .table,
.cxp-form-documento .tp-label {
  font-size: 13px;
}

@keyframes tp-progreso-sincronizacion {
  0% { transform: translateX(-115%); }
  100% { transform: translateX(255%); }
}

/* ===== Recepción: diagrama interactivo de daños de carrocería ===== */
.tp-danio-diagrama {
  position: relative;
  width: 100%;
  max-width: 220px;
  aspect-ratio: 220 / 420;
  background: #f4f6f9;
  border: 1px dashed var(--color-border);
  border-radius: 16px;
}

.tp-danio-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.tp-danio-overlay {
  position: absolute;
  inset: 0;
  cursor: crosshair;
}

.tp-danio-pin {
  position: absolute;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 1px 5px rgba(0, 0, 0, .45);
  transform: translate(-50%, -50%);
}

.tp-danio-tipo-btn {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1.5px solid var(--color-border);
  background: var(--color-card);
  cursor: pointer;
  text-align: left;
  transition: all .12s;
}

.tp-danio-tipo-btn.active {
  border-color: var(--color-primary);
  background: var(--color-primary-light);
}

.tp-danio-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex: none;
}

.tp-danio-count {
  font-weight: 600;
  font-size: .75rem;
  color: var(--color-muted);
  min-width: 14px;
  text-align: right;
}

.tp-danio-tipo-btn.active .tp-danio-count {
  color: var(--color-primary);
}

.tp-danio-item {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 9px;
}

.tp-danio-chip {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  color: #fff;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
}

.border-dashed {
  border-style: dashed !important;
}

/* ===== Recepción: inventario en botones toggle ===== */
.tp-toggle-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  border-radius: 10px;
  border: 1px solid var(--color-border);
  background: var(--color-card);
  cursor: pointer;
  transition: all .12s;
  margin-bottom: 0;
}

.tp-toggle-item.activo {
  border-color: var(--color-primary);
  background: var(--color-primary-light);
}

.tp-toggle-checkbox {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.tp-toggle-box {
  width: 19px;
  height: 19px;
  border-radius: 6px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--color-muted);
  color: transparent;
}

.tp-toggle-box .material-symbols-outlined {
  font-size: 14px;
}

.tp-toggle-item.activo .tp-toggle-box {
  border-color: var(--color-primary);
  background: var(--color-primary);
  color: #fff;
}

.tp-toggle-label {
  font-size: .85rem;
  font-weight: 500;
}

.tp-toggle-estado {
  font-size: .75rem;
  font-weight: 700;
  color: var(--color-muted);
}

.tp-toggle-item.activo .tp-toggle-estado {
  color: var(--color-primary);
}

/* ===== Recepción: tabla de servicios/cotización ===== */
.tp-svc-header {
  display: grid;
  grid-template-columns: 30px 92px 100px 1fr 70px 120px 120px 34px;
  gap: 10px;
  padding: 0 4px 9px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-label);
}

.tp-svc-row {
  display: grid;
  grid-template-columns: 30px 92px 100px 1fr 70px 120px 120px 34px;
  gap: 10px;
  align-items: center;
}

.tp-svc-importe {
  font-size: .9rem;
}

.tp-svc-codigo {
  font-family: 'IBM Plex Mono', monospace;
  font-size: .78rem;
  background: var(--color-bg);
}

.tp-svc-buscador {
  position: relative;
}

/* ===== Cotizaciones: tabla de servicios/refacciones (con descuento por línea) =====
   Clase dedicada (no se reutiliza .tp-svc-*) para no arriesgar el layout ya probado de
   Recepción: esta tabla tiene una columna más (Descuento). */
.tp-cot-header {
  display: grid;
  grid-template-columns: 30px 90px 1fr 70px 110px 100px 110px 34px;
  gap: 10px;
  padding: 8px 10px;
  margin-bottom: 6px;
  border-radius: 6px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  background: var(--color-primary);
  color: #fff;
}

/* ===== Facturación: tabla de conceptos (encabezado fijo tipo hoja de cálculo, mismo
   tratamiento visual que .tp-cot-header — barra azul sólida, una sola fila de títulos). =====
   Tabla real (no CSS Grid con divs) para que el ancho de columnas se defina en un solo lugar
   (los <th>), sin duplicar grid-template-columns entre encabezado y filas. */
.tp-tabla-conceptos thead th {
  /* Bootstrap pinta el fondo en cada celda (.table > :not(caption) > * > *), no en el <tr>:
     un background en thead tr quedaría tapado por el de cada th. Se pone aquí directo. */
  background: var(--color-primary);
  color: #fff;
  font-weight: 700;
  font-size: .72rem;
  letter-spacing: .03em;
  text-transform: uppercase;
  border: none;
  vertical-align: middle;
  padding: 8px 10px;
}

.tp-tabla-conceptos thead tr:first-child th:first-child {
  border-top-left-radius: 6px;
}

.tp-tabla-conceptos thead tr:first-child th:last-child {
  border-top-right-radius: 6px;
}

.tp-tabla-conceptos tbody td {
  vertical-align: middle;
  padding: 6px 10px;
}

.tp-cot-row {
  display: grid;
  grid-template-columns: 30px 90px 1fr 70px 110px 100px 110px 34px;
  gap: 10px;
  align-items: center;
}

.tp-cot-importe {
  font-size: .9rem;
}

.tp-cot-codigo {
  font-family: 'IBM Plex Mono', monospace;
  font-size: .78rem;
  background: var(--color-bg);
}

.tp-cot-buscador {
  position: relative;
}

/* ===== Inventario: detalle de movimientos (Entradas/Salidas/Ajustes) =====
   Clase dedicada (no se reutiliza .tp-cot-*): una columna más (Ubicación) y sin descuento. */
.tp-inv-header {
  display: grid;
  grid-template-columns: 30px 1fr 190px 90px 90px 110px 110px 34px;
  gap: 10px;
  padding: 0 4px 9px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-label);
}

.tp-inv-row {
  display: grid;
  grid-template-columns: 30px 1fr 190px 90px 90px 110px 110px 34px;
  gap: 10px;
  align-items: start;
}

.tp-inv-importe {
  font-size: .9rem;
  padding-top: .4rem;
}

.tp-inv-buscador {
  position: relative;
}

/* Variante solo de Entradas (views/inventario/entradas/form.php): la razón contable va en su propia
   columna, después de Costo unit., para que cada partida quede en una sola línea. El grid base
   (.tp-inv-header/.tp-inv-row) lo comparte views/inventario/movimientos/form.php y no cambia.
   Producto se acorta (antes ocupaba todo el espacio sobrante) y comparte ese espacio con la razón;
   minmax(0, ...) evita que los campos desborden la tarjeta en pantallas angostas. Debe ir después
   de las reglas base para ganar por orden (misma especificidad). */
.tp-inv-header--razon,
.tp-inv-row--razon {
  grid-template-columns: 30px minmax(0, 1.3fr) 170px 80px 80px 110px minmax(0, 1fr) 110px 34px;
}

.tp-inv-ubicacion-nueva input + input {
  margin-top: 4px;
}

/* ===== Inventario: detalle de Salidas — sin Costo/Importe (se fija hasta Liberar), con
   columna de Disponible en su lugar. Clase dedicada (no se reutiliza .tp-inv-*). */
.tp-sal-header {
  display: grid;
  grid-template-columns: 30px 1fr 190px 90px 100px 34px;
  gap: 10px;
  padding: 0 4px 9px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-label);
}

.tp-sal-row {
  display: grid;
  grid-template-columns: 30px 1fr 190px 90px 100px 34px;
  gap: 10px;
  align-items: start;
}

.tp-sal-buscador {
  position: relative;
}

/* La columna Producto puede crecer a 2 líneas (descripción + botón "Lote/Serie" cuando el
   producto lo exige) — con .tp-sal-row en align-items:start, un <div> de UM con
   align-self-center quedaba centrado en esa altura extra y se veía "flotando" más abajo que el
   <select> de Ubicación y el <input> de Cantidad, que sí se quedan arriba. padding-top iguala su
   línea de base a la de esos controles (mismo truco que .tp-inv-importe). */
.tp-sal-um,
.tp-sal-um-existente {
  align-self: start;
  padding-top: .4rem;
}

.tp-trp-header {
  display: grid;
  grid-template-columns: 30px 1fr 170px 170px 90px 100px 34px;
  gap: 10px;
  padding: 0 4px 9px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-label);
}

.tp-trp-row {
  display: grid;
  grid-template-columns: 30px 1fr 170px 170px 90px 100px 34px;
  gap: 10px;
  align-items: start;
}

.tp-trp-buscador {
  position: relative;
}

/* ===== Recepción: firma del cliente ===== */
.tp-firma-canvas {
  width: 100%;
  height: 170px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 11px;
  touch-action: none;
  cursor: crosshair;
}

/* ===== Catálogos: Configuración general (grid + panel lateral de alta/edición) =====
   Reemplaza la versión anterior "hoja de cálculo" (celdas contenteditable) por un patrón de
   grid con buscador/orden + drawer (offcanvas de Bootstrap) para alta/edición, siguiendo el
   template importado de Claude Design "Grid Editable Template". */
.tp-cfg-clave {
  font-family: 'IBM Plex Mono', 'Courier New', monospace;
  font-size: 0.82rem;
}

.tp-cfg-lock {
  font-size: 15px !important;
  color: var(--color-label);
  vertical-align: middle;
  margin-left: 0.3rem;
}

.tp-cfg-th-sort {
  cursor: pointer;
  user-select: none;
}

.tp-cfg-flecha {
  color: var(--color-primary);
  font-size: 0.75em;
}

/* Miniatura junto a los botones "Logo del menú"/"Logo de impresiones" del encabezado. */
.tp-cfg-logo-preview {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 4px;
  overflow: hidden;
  background: var(--color-bg);
  flex-shrink: 0;
}

.tp-cfg-logo-preview img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.tp-cfg-logo-preview .material-symbols-outlined {
  font-size: 16px;
  color: var(--color-muted);
}

/* ===== Grids editables por fila (catálogos chicos: unidad de medida, almacenes, ubicaciones)
   ===== Genérico y reutilizable (prefijo "tp-ie" = "inline editable"): celdas contenteditable
   con autoguardado al perder foco, clave bloqueada tras crearse, fila "+ Agregar" al final. */
.tp-ie-clave {
  font-family: 'IBM Plex Mono', 'Courier New', monospace;
  font-size: 0.82rem;
  white-space: nowrap;
}

.tp-ie-lock {
  font-size: 15px !important;
  color: var(--color-label);
  vertical-align: middle;
  margin-left: 0.3rem;
}

.tp-ie-input-clave {
  border: 1px dashed var(--color-border);
  border-radius: 6px;
  padding: 0.25rem 0.5rem;
  font-family: 'IBM Plex Mono', 'Courier New', monospace;
  font-size: 0.82rem;
  width: 100%;
  background: #fffdf3;
}

.tp-ie-input-clave:focus {
  outline: none;
  border-color: var(--color-primary);
  background: #fff;
}

.tp-ie-cell {
  cursor: text;
  border-radius: 6px;
  outline: none;
  min-width: 100px;
}

.tp-ie-cell:hover {
  background: #f3f6fb;
}

.tp-ie-cell:focus {
  background: #fff;
  box-shadow: inset 0 0 0 2px var(--color-primary);
}

.tp-ie-cell:empty::before {
  content: attr(data-placeholder);
  color: var(--color-label);
  font-style: italic;
}

.tp-ie-select-cell {
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 0.3rem 0.4rem;
  font-size: 0.85rem;
  background: #fff;
}

@keyframes tpIeFlashOk {
  0% { background: #d7f5df; }
  100% { background: transparent; }
}

@keyframes tpIeFlashError {
  0% { background: #fbdada; }
  100% { background: transparent; }
}

.tp-ie-flash-ok {
  animation: tpIeFlashOk 0.9s ease;
}

.tp-ie-flash-error {
  animation: tpIeFlashError 0.9s ease;
}

.tp-ie-fila-nueva td {
  background: #fbf9ee;
}

.tp-ie-btn-eliminar,
.tp-ie-btn-cancelar {
  border: none;
  background: transparent;
  color: var(--color-muted);
  border-radius: 6px;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.tp-ie-btn-eliminar .material-symbols-outlined,
.tp-ie-btn-cancelar .material-symbols-outlined {
  font-size: 18px;
}

.tp-ie-btn-eliminar:hover {
  background: #fde8e8;
  color: #c0392b;
}

.tp-ie-btn-cancelar:hover {
  background: var(--color-bg);
  color: var(--color-text);
}

.tp-ie-fila-agregar td {
  padding: 0;
  border-bottom: none;
}

.tp-ie-btn-agregar {
  width: 100%;
  border: none;
  background: transparent;
  text-align: left;
  padding: 0.65rem 0.75rem;
  color: var(--color-primary);
  font-weight: 600;
  font-size: 0.88rem;
}

.tp-ie-btn-agregar:hover {
  background: var(--color-primary-light);
}

/* ===== Paginación de grids/listados (ver assets/js/paginacion.js) ===== */
.tp-paginacion {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding: 0.65rem 1rem;
  border-top: 1px solid var(--color-border);
}

.tp-pag-tamano-wrap {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
}

.tp-pag-tamano {
  width: auto;
}

.tp-pag-info {
  color: var(--color-muted);
  font-size: 0.82rem;
}

.tp-pag-botones {
  display: flex;
  gap: 0.25rem;
}

.tp-pag-botones .material-symbols-outlined {
  font-size: 18px;
}

.tp-pag-botones button:disabled {
  opacity: 0.4;
}

/* ===== Tamaños compactos estándar para grids/listados con buscador + tabla paginada.
   Envolver el <form> de filtros + la tarjeta de tabla/paginación en <div class="tp-grid">
   (ver views/catalogos/productos/index.php) para heredar automáticamente estos tamaños.
   Aplica a todos los grids actuales y a cualquier grid nuevo que use este mismo patrón. ===== */
.tp-grid thead th,
.tp-tabla-paginada thead th {
  font-size: 13px;
  font-weight: 700;
  padding-top: 0.45rem;
  padding-bottom: 0.45rem;
}

.tp-grid tbody td,
.tp-tabla-paginada tbody td {
  font-size: 13px;
  padding-top: 0.35rem;
  padding-bottom: 0.35rem;
}

/* Listados anteriores que todavía no usan .tp-grid ni .tp-tabla-paginada. */
.tp-card > .table-responsive > .table thead th,
.tp-card > .table-responsive > .table tbody td {
  font-size: 13px;
}

/* Grid de previsualización de CFDI recibidos: lectura compacta y uniforme. */
.tp-cfdi-excel-grid thead th,
.tp-cfdi-excel-grid tbody td,
.tp-cfdi-revision-grid thead th,
.tp-cfdi-revision-grid tbody td {
  font-size: 13px;
}

.tp-grid .tp-label {
  font-size: 11px;
}

.tp-grid input.form-control::placeholder {
  font-size: 13px;
}

.tp-grid .tp-pag-tamano {
  font-size: 13px;
}

.tp-grid .tp-pag-info {
  font-size: 12px;
}

.tp-grid tbody .btn-sm {
  padding: 0.15rem 0.45rem;
  font-size: 12px;
  line-height: 1.4;
}

/* ===== Notas de crédito: UUID de CFDI relacionado, monoespaciado y truncado (mismo tratamiento
   que .tp-cfg-clave/.tp-ie-clave para claves/códigos) — evita que un UUID largo empuje o se
   encime con la columna de Folio contigua. ===== */
.nc-rel-uuid {
  font-family: 'IBM Plex Mono', 'Courier New', monospace;
  font-size: 0.78rem;
}

/* Sin table-layout:fixed ni min-width, un <table> normal deja que el navegador COMPRIMA cada
   columna (select de Tipo de relación, folio, UUID) hasta volverlas ilegibles en vez de activar
   el scroll horizontal de .table-responsive (bug real: en mobile el ancho total de columnas
   nunca superaba el contenedor, así que nunca disparaba overflow-x). min-width fuerza que en
   pantallas angostas se dispare el scroll horizontal real, en vez de comprimir el contenido. */
.nc-tabla-relacionados {
  min-width: 780px;
}

/* ===== Encabezado fijo al hacer scroll vertical — probado primero solo en Configuración,
   ahora generalizado a TODOS los grids. .tp-tabla-paginada es la envoltura común a los 19 grids
   del sistema (los 16 que además traen .tp-grid para los tamaños compactos, y los 3 que no:
   Facturación, Notas de crédito, CxC) — se usa esta clase en vez de .tp-grid para no dejar a
   esos 3 afuera. ===== */
.tp-tabla-paginada thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--color-card);
  box-shadow: 0 1px 0 var(--color-border);
}

/* ===== Quita las flechas nativas de aumentar/disminuir en TODOS los <input type="number">
   (cantidad, importe, precio, descuento, etc. en cualquier formulario del sistema) — el usuario
   captura el valor directo, sin necesidad de esos spinners. ===== */
input[type="number"] {
  -moz-appearance: textfield;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* ===== Patrón estándar de grid con scroll horizontal (generalizado desde Productos a los 19
   grids del sistema — ver GUIA_INSTALACION.md sección 8 para el checklist completo al crear un
   catálogo nuevo):
   - Acciones (editar/eliminar/etc.) como botones de solo ícono en la PRIMERA columna, no la
     última, para que sigan a la vista sin recorrer todo el scroll horizontal.
   - La tabla va envuelta en .table-responsive dentro de .tp-tabla-paginada.
   - Las columnas de texto largo llevan una de las utilidades tp-col-ancho-* de abajo, para que
     el navegador NO las comprima hasta volverlas ilegibles (sin table-layout:fixed ni min-width,
     un <table> normal comprime cada columna en vez de activar el scroll horizontal — bug real
     confirmado primero en Notas de Crédito, ver .nc-tabla-relacionados más arriba).
   - Flechas de scroll (tp-grid-scroll-controles + assets/js/tp-grid-scroll.js) en vez de
     depender solo del scrollbar nativo: en macOS/Chrome es "overlay" e invisible en reposo
     aunque el scroll funcione, así que no es una señal confiable por sí sola. ===== */
.tp-col-acciones-icon {
  min-width: 70px;
  white-space: nowrap;
}

/* Encabezados ordenables (assets/js/tp-tabla-orden.js) — clic para ordenar ascendente/descendente. */
.tp-th-ordenable {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.tp-th-ordenable:hover {
  background-color: rgba(0, 0, 0, 0.04);
}
.tp-th-orden-indicador {
  display: inline-block;
  min-width: 1em;
  color: var(--color-primary);
  font-size: 11px;
}

/* ===== Botones de solo ícono para la columna de Acciones — mismo estilo simple/pequeño que ya
   usaban los grids de edición inline (.tp-ie-btn-eliminar en Almacenes/Ubicaciones/Unidad de
   medida): sin borde ni fondo hasta el hover, 28px, ícono a 18px. Reemplaza el btn-outline de
   Bootstrap que se usaba antes (más grande y con borde permanente) en el resto de los grids. */
.tp-btn-icon {
  border: none;
  background: transparent;
  color: var(--color-muted);
  border-radius: 6px;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.tp-btn-icon .material-symbols-outlined {
  font-size: 18px;
}

.tp-btn-icon:hover {
  background: var(--color-bg);
  color: var(--color-text);
}

.tp-btn-icon--danger:hover {
  background: #fde8e8;
  color: #c0392b;
}

.tp-btn-icon--primary:hover {
  background: var(--color-primary-light);
  color: var(--color-primary);
}

.tp-col-ancho-sm {
  min-width: 110px;
}

.tp-col-ancho-md {
  min-width: 160px;
}

.tp-col-ancho-lg {
  min-width: 220px;
}

/* Modal de resumen de "Por facturar" (views/facturacion/por_facturar.php): más ancho que
   .modal-xl para que la columna de folios de cada grupo (T-000001, T-000003, ...) quepa en una
   sola línea sin partirse — .pf-col-tickets fuerza esa celda a no hacer wrap; si aun así no cabe,
   el .table-responsive que ya envuelve la tabla mete scroll horizontal en vez de encimar texto. */
.tp-modal-resumen-factura {
  max-width: min(96vw, 1400px);
}

.pf-col-tickets {
  white-space: nowrap;
}

/* .table-responsive no hereda el border-radius de .tp-card: sin overflow:hidden aquí, el
   thead sticky (fondo opaco) y la barra de scroll quedan con esquinas cuadradas encimadas sobre
   las esquinas redondeadas de la tarjeta. */
.tp-tabla-paginada {
  overflow: hidden;
}

/* El scroll horizontal nativo de .table-responsive ya funciona cuando las columnas no caben,
   pero con la barra delgada/superpuesta que usan Chrome/Edge/Firefox por defecto no es obvio que
   hay más contenido a la derecha (y en macOS/Chrome ni siquiera se ve en reposo). La engrosamos
   y coloreamos como refuerzo visual — las flechas explícitas (tp-grid-scroll-controles) son el
   mecanismo principal, confiable en cualquier SO/navegador. */
.tp-tabla-paginada .table-responsive {
  scrollbar-width: auto;
  scrollbar-color: var(--color-primary) var(--color-bg);
}

.tp-tabla-paginada .table-responsive::-webkit-scrollbar {
  height: 10px;
}

.tp-tabla-paginada .table-responsive::-webkit-scrollbar-track {
  background: var(--color-bg);
}

.tp-tabla-paginada .table-responsive::-webkit-scrollbar-thumb {
  background-color: var(--color-primary);
  border-radius: 6px;
}

.prod-buscar-campo {
  min-width: 220px;
}

/* Móvil: la fila de acciones (Actualizar/Excel/Nuevo producto) y la de buscador+botones ya
   traían flex-wrap, pero con textos largos + el input de 220px mínimo seguían sin caber en un
   viewport angosto y se cortaban en vez de acomodarse — se detectó al revisar la vista de
   Productos en móvil (no es un problema del grid en sí). Apilar en columna a partir de este
   punto de quiebre es más predecible que ajustar anchos mínimos a mano. Mismo breakpoint
   (767.98px) que ya usa el sidebar para pasar a modo hamburguesa — ver más arriba en este mismo
   archivo — para no introducir un segundo criterio de "móvil" distinto. */
@media (max-width: 767.98px) {
  .prod-fila-acciones,
  .prod-fila-buscar {
    flex-direction: column;
    align-items: stretch !important;
  }

  .prod-fila-acciones .btn {
    width: 100%;
  }

  .prod-buscar-campo {
    min-width: 0;
  }
}

/* ===== Dashboard operativo (Inicio) — ver views/dashboard_panel.php. Colores de los íconos KPI
   y de los puntos de forma de pago son FIJOS (no usan --color-primary/--sidebar-*): son
   categorías semánticas de este panel (ventas/tickets/inventario/mes/CxC, Efectivo/Tarjeta/...),
   no acentos de marca — deben verse igual sin importar el tema de color que el usuario elija
   (mismo criterio que ya aplican los .tp-badge-aprobada/rechazada/etc. de estatus). ===== */
.tp-dash-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: .75rem;
  margin-bottom: 1.25rem;
}

.tp-dash-fecha {
  background: var(--color-primary-light);
  color: var(--color-primary);
  font-weight: 600;
  font-size: .85rem;
  padding: .3rem .75rem;
  border-radius: 999px;
  white-space: nowrap;
}

.tp-kpi-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1rem;
}

@media (max-width: 900px) {
  .tp-kpi-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.tp-kpi-card {
  background: var(--color-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 1.1rem 1.1rem 1rem;
}

.tp-kpi-icon {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: .6rem;
}

.tp-kpi-icon .material-symbols-outlined {
  font-size: 16px;
}

.tp-kpi-icon--azul   { background: #E6F1FB; color: #185FA5; }
.tp-kpi-icon--morado { background: #EEEDFE; color: #534AB7; }
.tp-kpi-icon--teal   { background: #E1F5EE; color: #0F6E56; }
.tp-kpi-icon--coral  { background: #FAECE7; color: #993C1D; }
.tp-kpi-icon--rosa   { background: #FBEAF0; color: #993556; }

.tp-kpi-label {
  font-size: .8rem;
  color: var(--color-muted);
  margin-bottom: .2rem;
}

.tp-kpi-valor {
  font-size: 1.55rem;
  font-weight: 600;
  color: var(--color-text);
  line-height: 1.2;
}

.tp-kpi-sub {
  font-size: .8rem;
  color: var(--color-muted);
  margin-top: .25rem;
}

.tp-kpi-sub--alerta-ambar { color: #B8860B; font-weight: 600; }
.tp-kpi-sub--alerta-rosa  { color: #993556; font-weight: 600; }
.tp-kpi-sub--positivo     { color: #1e8449; font-weight: 600; }
.tp-kpi-sub--negativo     { color: #c0392b; font-weight: 600; }

.tp-panel-titulo {
  font-size: .95rem;
  font-weight: 600;
  margin-bottom: .75rem;
}

.tp-panel-subtitulo {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-label);
  margin: .75rem 0 .5rem;
}

.tp-chip-row {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}

.tp-chip {
  padding: .35rem .75rem;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 600;
}

.tp-chip--ambar { background: #FDF1E3; color: #B8860B; }
.tp-chip--gris  { background: #F1F1EE; color: var(--color-muted); }

.tp-formapago-fila {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .4rem 0;
  border-bottom: 1px solid var(--color-border);
}

.tp-formapago-fila:last-child {
  border-bottom: none;
}

.tp-formapago-punto {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
}

.tp-formapago-nombre {
  flex-grow: 1;
  font-size: .85rem;
}

.tp-formapago-conteo {
  font-size: .75rem;
  color: var(--color-muted);
}

.tp-formapago-monto {
  font-weight: 600;
  font-size: .85rem;
  min-width: 80px;
  text-align: right;
}

.tp-chart-leyenda {
  display: flex;
  gap: 1rem;
  font-size: .8rem;
  color: var(--color-muted);
}

.tp-leyenda-cuadro {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  margin-right: .3rem;
}

/* Muestra de línea punteada para leyendas de gráficas lineales (el color va en border-color inline). */
.tp-leyenda-linea {
  display: inline-block;
  width: 18px;
  border-top: 2px dashed;
  margin-right: .35rem;
  vertical-align: middle;
}

.tp-tabla-dash thead th {
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--color-label);
  font-weight: 700;
  border-bottom: 1px solid var(--color-border);
}

.tp-tabla-dash td,
.tp-tabla-dash th {
  border-bottom: 1px solid var(--color-border);
}

.tp-tabla-dash td.text-end,
.tp-tabla-dash th.text-end {
  font-variant-numeric: tabular-nums;
}

/* Reglas de impresión: ver assets/css/print.css (cargado solo con media="print"). */
