.card {
  background: var(--paper);
  border: var(--card-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-5);
}

.card--tight {
  padding: var(--space-4) var(--space-4);
}

/* ================= KPI cards (compat, reusable en módulos futuros) ================= */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.kpi-card {
  background: var(--paper);
  border: var(--card-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-4) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.kpi-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.kpi-card__label {
  font-size: var(--text-xs);
  color: var(--gray-500);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}

.kpi-card__icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  background: var(--joal-green-100);
  color: var(--joal-green-ink);
  display: flex;
  align-items: center;
  justify-content: center;
}

.kpi-card__value {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 700;
  color: var(--gray-900);
  letter-spacing: var(--tracking-tight);
}

.kpi-card__value small {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-500);
  margin-left: 4px;
}

.kpi-card__meta {
  font-size: var(--text-xs);
  color: var(--gray-500);
}

/* ================= Dashboard: métricas jerarquizadas ================= */
/* Hero: materia prima / producto terminado disponibles — el ancla visual del dashboard */
.hero-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}

/* Auditoría visual (ronda de pulido): antes tenía una textura de rayas
   diagonales (::before) y un "glow" circular decorativo (::after)
   encima del degradado -- el patrón típico de tarjeta de métrica de
   SaaS/fintech. Se quitan ambas capas decorativas; el degradado se
   acorta a dos tonos vecinos (antes 700->900, un salto notorio) para
   que quede sobrio pero conserve algo de profundidad -- no queda
   plano del todo a propósito. Mismo markup, mismos datos, mismos
   links: solo el fondo cambia. */
.hero-card {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-xl);
  padding: 24px 28px;
  color: var(--white);
  background: linear-gradient(135deg, var(--joal-green-800) 0%, var(--joal-green-900) 100%);
  box-shadow: var(--shadow-md);
}

.hero-card--alt {
  background: linear-gradient(135deg, var(--joal-green-700) 0%, var(--joal-green-800) 100%);
}

.hero-card__icon {
  position: absolute;
  right: 18px;
  top: 18px;
  opacity: 0.22;
  transform: scale(2.1);
  transform-origin: top right;
}

.hero-card__label {
  position: relative;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  color: var(--joal-green-200);
  font-weight: 700;
}

.hero-card__value {
  position: relative;
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  margin-top: 10px;
}

.hero-card__value small {
  font-size: 14px;
  font-weight: 600;
  color: var(--joal-green-200);
  margin-left: 6px;
}

.hero-card__meta {
  font-size: var(--text-sm);
  color: var(--joal-green-200);
  margin-top: 6px;
}

.hero-card__breakdown {
  position: relative;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.hero-card__breakdown-item {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: var(--text-sm);
  color: var(--white);
}

.hero-card__breakdown-name {
  opacity: 0.92;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hero-card__breakdown-qty {
  font-weight: 600;
  flex-shrink: 0;
}

.hero-card__breakdown-more {
  position: relative;
  font-size: var(--text-xs);
  color: var(--joal-green-200);
}

.hero-card__link {
  position: relative;
  display: inline-block;
  margin-top: 12px;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--white);
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.4);
}

.hero-card__link:hover {
  color: var(--white);
  border-bottom-color: var(--white);
}

/* Franja de métricas secundarias — una sola pieza visual, no tarjetas repetidas */
.stat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  background: var(--paper);
  border: var(--border-hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--space-6);
}

.stat-chip {
  padding: var(--space-4) var(--space-5);
  border-right: 1px solid var(--gray-100);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.stat-chip:last-child {
  border-right: none;
}

.stat-chip__top {
  display: flex;
  align-items: center;
  gap: 8px;
}

.stat-chip__icon {
  width: 22px;
  height: 22px;
  border-radius: var(--radius-xs);
  background: var(--joal-green-50);
  color: var(--joal-green-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.stat-chip__label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--gray-500);
  font-weight: 600;
}

.stat-chip__value {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 700;
  color: var(--gray-900);
}

.stat-chip__value small {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--gray-500);
  margin-left: 3px;
}

.stat-chip__meta {
  font-size: 10.5px;
  color: var(--gray-500);
}

@media (max-width: 720px) {
  .stat-chip {
    border-right: none;
    border-bottom: 1px solid var(--gray-100);
  }
  .stat-chip:last-child {
    border-bottom: none;
  }
}

/* ================= Sections ================= */
.section {
  margin-bottom: var(--space-6);
}

.section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
  gap: var(--space-3);
  flex-wrap: wrap;
}

.section__title {
  font-size: var(--text-md);
  font-weight: 600;
  font-family: var(--font-display);
  letter-spacing: var(--tracking-tight);
}

.section__link {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--joal-green-ink);
}

.dashboard-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: var(--space-5);
  align-items: start;
}

/* Corrección auditoría Playwright (hallazgo AL1): customers/index.html y
   customers/suppliers_index.html fijaban grid-template-columns: repeat(2,
   1fr) con style="" en línea para tener 2 columnas simétricas (a
   diferencia del 2fr/1fr por defecto de arriba) -- eso ganaba siempre
   sobre la media query de abajo y dejaba la página con overflow
   horizontal real en un teléfono. Misma regla, ahora como clase
   modificadora para que el colapso a 1 columna en móvil sí pueda
   aplicar. */
.dashboard-grid--2up {
  grid-template-columns: repeat(2, 1fr);
}

/* min-width:0 en los hijos directos: sin esto, una tabla ancha adentro
   (ver .table-wrapper) sigue forzando su columna de grid más allá del
   ancho disponible incluso ya colapsado a 1fr arriba -- comportamiento
   por defecto de CSS Grid (min-width:auto en los items), no algo que la
   media query por sí sola pueda arreglar. */
.dashboard-grid--2up > * {
  min-width: 0;
}

@media (max-width: 1100px) {
  .dashboard-grid,
  .dashboard-grid--2up {
    grid-template-columns: 1fr;
  }
}

/* Grid 2x2 de bloques temáticos (Supervisión general, FASE 11B): mismo
   principio que .dashboard-grid, pero simétrico -- 4 secciones del mismo
   peso visual (Producción/Merma/Recepción+Piso/Salidas) en vez de una
   columna principal + una lateral. */
.summary-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
  align-items: start;
}

@media (max-width: 860px) {
  .summary-grid {
    grid-template-columns: 1fr;
  }
}

/* ================= Cuartos (R-camaras-cuartos) =================
   Tarjeta simplificada para los 5 Cuartos operativos, reutilizada tanto en
   /camaras/ como en el bloque "Cámaras frías" del Dashboard. Sin anillo/
   porcentaje (no existe capacidad real todavía, ver
   chamber_service.room_summaries), sin código crudo ("CUARTO-A"), sin
   etiqueta materia-prima/producto-terminado. */
.room-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-4);
}

.room-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  border: var(--border-hairline);
  border-top: 3px solid var(--joal-green-500);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  background: var(--paper);
  box-shadow: var(--shadow-sm);
  color: inherit;
  text-decoration: none;
  transition: box-shadow var(--transition-fast), border-color var(--transition-fast),
    transform var(--transition-fast);
}

.room-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--joal-sage-500);
  text-decoration: none;
  transform: translateY(-2px);
}

.room-card__header {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.room-card__icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: var(--joal-green-100);
  color: var(--joal-green-ink);
}

.room-card__title {
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 16px;
  color: var(--gray-900);
  letter-spacing: var(--tracking-tight);
  overflow-wrap: break-word;
  min-width: 0;
}

.room-card__stats {
  display: flex;
  gap: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--gray-100);
  flex-wrap: wrap;
}

.room-card__stat {
  font-size: 11px;
  color: var(--gray-500);
}

.room-card__stat strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-md);
  color: var(--gray-900);
}

/* Compat: barra lineal, ya no se usa en las tarjetas de cámara pero se
   conserva por si algún módulo futuro la reutiliza como indicador simple. */
.occupancy-bar {
  height: 7px;
  border-radius: var(--radius-full);
  background: var(--gray-100);
  overflow: hidden;
  margin-bottom: 8px;
}

.occupancy-bar__fill {
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--joal-green-500);
  transition: width var(--transition-base);
}

.occupancy-bar__fill.is-high {
  background: var(--amber-500);
}

/* ================= Activity feed (dashboard) ================= */
.activity-list {
  display: flex;
  flex-direction: column;
}

.activity-item {
  display: flex;
  gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid var(--gray-100);
}

.activity-item:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.activity-item__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--joal-green-500);
  margin-top: 6px;
  flex-shrink: 0;
}

.activity-item__dot--in {
  background: var(--joal-green-500);
}

.activity-item__dot--out {
  background: var(--red-500);
}

.activity-item__dot--info {
  background: var(--white);
  border: 1px dashed var(--gray-500);
}

.activity-item__title {
  font-size: 13px;
  font-weight: 600;
  color: var(--gray-900);
}

.activity-item__meta {
  font-size: 11.5px;
  color: var(--gray-500);
}

/* ================= Timeline (ficha de lote) ================= */
.timeline {
  position: relative;
  padding-left: 2px;
}

.timeline::before {
  content: "";
  position: absolute;
  left: 16px;
  top: 8px;
  bottom: 8px;
  width: 2px;
  background: var(--gray-200);
}

.timeline-item {
  position: relative;
  display: flex;
  gap: var(--space-4);
  padding: 13px 0;
}

.timeline-item:first-child {
  padding-top: 2px;
}

.timeline-item:last-child {
  padding-bottom: 2px;
}

.timeline-item__marker {
  position: relative;
  z-index: 1;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  border: 2px solid var(--gray-200);
  color: var(--gray-500);
  flex-shrink: 0;
}

.timeline-item__marker--in {
  border-color: var(--joal-green-500);
  color: var(--joal-green-ink);
  background: var(--joal-green-50);
}

.timeline-item__marker--out {
  border-color: var(--red-500);
  color: var(--red-600);
  background: var(--red-100);
}

.timeline-item__marker--info {
  border-style: dashed;
  border-color: var(--gray-300);
  color: var(--gray-500);
  background: var(--gray-50);
}

.timeline-item__body {
  flex: 1;
  padding-top: 3px;
  min-width: 0;
}

.timeline-item__title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--gray-900);
  flex-wrap: wrap;
}

.timeline-item__qty {
  font-family: var(--font-display);
  font-weight: 700;
}

.timeline-item__qty--in {
  color: var(--joal-green-ink);
}

.timeline-item__qty--out {
  color: var(--red-600);
}

.timeline-item__meta {
  font-size: 11.5px;
  color: var(--gray-500);
  margin-top: 3px;
}

/* ================= Alerts ================= */
.alert-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.alert-item {
  display: flex;
  gap: 10px;
  padding: 11px 12px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
}

.alert-item--warning {
  background: var(--amber-100);
  border-color: rgba(184, 134, 44, 0.25);
}

.alert-item--info {
  background: var(--blue-100);
  border-color: rgba(59, 110, 165, 0.2);
}

.alert-item--error {
  background: var(--red-100);
  border-color: rgba(179, 69, 63, 0.25);
}

.alert-item__title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--gray-900);
}

.alert-item__detail {
  font-size: 12px;
  color: var(--gray-600);
}

/* ================= Banner de prototipo/demo (R-piso-demo) =================
   Discreto a propósito -- informa que la pantalla NO persiste todavía,
   sin parecer un error ni una advertencia real. Reutilizable en cualquier
   flujo futuro que necesite el mismo aviso ("todavía no guarda cambios"). */
.demo-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  background: var(--blue-100);
  color: var(--blue-600);
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 16px;
}

.demo-banner svg {
  flex-shrink: 0;
}

/* ================= Badges ================= */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: var(--radius-full);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: var(--tracking-normal);
  border: 1px solid transparent;
}

.badge--success {
  background: var(--joal-green-100);
  color: var(--joal-green-ink);
  border-color: var(--joal-green-200);
}

.badge--warning {
  background: var(--amber-100);
  color: var(--amber-600);
}

.badge--muted {
  background: var(--gray-100);
  color: var(--gray-600);
}

.badge--info {
  background: var(--blue-100);
  color: var(--blue-600);
}

/* ================= Tables ================= */
.table-wrapper {
  overflow-x: auto;
}

table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.data-table th {
  text-align: left;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--gray-500);
  font-weight: 700;
  padding: 10px 12px;
  background: var(--gray-50);
  border-bottom: 1px solid var(--gray-200);
  white-space: nowrap;
}

.data-table th:first-child {
  border-top-left-radius: var(--radius-sm);
}

.data-table th:last-child {
  border-top-right-radius: var(--radius-sm);
}

.data-table td {
  padding: 11px 12px;
  border-bottom: 1px solid var(--gray-100);
  color: var(--gray-800);
  white-space: nowrap;
}

.data-table tbody tr:hover {
  background: var(--joal-green-50);
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

/* ================= Cámaras: tarimas como posiciones físicas ================= */
.location-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
  gap: var(--space-3);
}

.location-card {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-md);
  padding: 14px 14px 12px;
  min-height: 122px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.location-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
}

.location-card--empty {
  border: 1.5px dashed var(--gray-300);
  background: repeating-linear-gradient(
    128deg,
    var(--gray-50),
    var(--gray-50) 7px,
    var(--paper) 7px,
    var(--paper) 15px
  );
}

.location-card--empty::before {
  background: var(--gray-200);
}

.location-card--occupied {
  border: 1px solid var(--gray-200);
  background: var(--paper);
  box-shadow: var(--shadow-sm);
}

.location-card--raw.location-card--occupied::before {
  background: var(--joal-green-500);
}

.location-card--finished.location-card--occupied::before {
  background: var(--joal-gold-500);
}

/* FASE 10C.1: un Cuarto multipropósito puede tener materia prima Y
   producto terminado a la vez en la misma StorageLocation -- la franja
   combina ambos colores en vez de forzar uno solo. */
.location-card--mixed.location-card--occupied::before {
  background: linear-gradient(90deg, var(--joal-green-500) 50%, var(--joal-gold-500) 50%);
}

.location-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.location-card__code {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14.5px;
  color: var(--gray-900);
  letter-spacing: var(--tracking-tight);
}

.location-card__empty-label {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--gray-500);
}

.location-card__empty-icon {
  opacity: 0.55;
  flex-shrink: 0;
}

.location-card__entry {
  border-top: 1px solid var(--gray-100);
  padding-top: 7px;
}

.location-card__entry:first-of-type {
  border-top: none;
  padding-top: 0;
}

.location-card__entry-lot {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--joal-green-ink);
}

.location-card__entry-product {
  font-size: 11.5px;
  color: var(--gray-600);
}

.location-card__entry-qty {
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--gray-900);
}

.location-card__entry-actions {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}

.location-card__entry-actions a {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}

.chamber-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
  font-size: var(--text-xs);
  color: var(--gray-500);
}

.chamber-legend__item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.chamber-legend__swatch {
  width: 20px;
  height: 4px;
  border-radius: var(--radius-full);
}

/* ================= Trazabilidad: diagrama de flujo ================= */
.trace-flow {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  padding: var(--space-4) 0;
}

.trace-row {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
  width: 100%;
}

.trace-arrow {
  display: flex;
  flex-direction: column;
  align-items: center;
  color: var(--gray-400);
  padding: 6px 0;
  min-height: 34px;
  justify-content: center;
}

.trace-arrow__label {
  font-size: 10.5px;
  color: var(--gray-500);
  background: var(--gray-50);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-full);
  padding: 2px 10px;
  margin-bottom: 2px;
  white-space: nowrap;
}

.trace-node {
  position: relative;
  border-radius: var(--radius-md);
  padding: 12px 16px;
  min-width: 168px;
  max-width: 220px;
  text-align: center;
  border: 1.5px solid var(--gray-200);
  background: var(--paper);
  box-shadow: var(--shadow-sm);
}

.trace-node--highlight {
  box-shadow: 0 0 0 3px var(--joal-green-100), var(--shadow-md);
}

.trace-node__type {
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  font-weight: 700;
  margin-bottom: 4px;
}

.trace-node__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 13px;
  color: var(--gray-900);
  text-decoration: none;
}

a.trace-node__title:hover {
  text-decoration: underline;
}

.trace-node__meta {
  font-size: 10.5px;
  color: var(--gray-500);
  margin-top: 3px;
}

.trace-node--supplier {
  border-color: var(--joal-sage-500);
}
.trace-node--supplier .trace-node__type {
  color: var(--joal-sage-600);
}

.trace-node--raw {
  border-color: var(--joal-green-500);
}
.trace-node--raw .trace-node__type {
  color: var(--joal-green-ink);
}

.trace-node--production {
  border-color: var(--joal-gold-500);
  background: var(--joal-gold-100);
}
.trace-node--production .trace-node__type {
  color: var(--joal-gold-600);
}

.trace-node--finished {
  border-color: var(--blue-500);
}
.trace-node--finished .trace-node__type {
  color: var(--blue-600);
}

.trace-node--customer {
  border: none;
  background: linear-gradient(135deg, var(--joal-green-700), var(--joal-green-900));
  color: var(--white);
}
.trace-node--customer .trace-node__type {
  color: var(--joal-green-200);
}
.trace-node--customer .trace-node__title {
  color: var(--white);
}
.trace-node--customer .trace-node__meta {
  color: var(--joal-green-200);
}

.trace-node__inventory {
  margin-top: 6px;
  font-size: 10px;
  font-weight: 700;
  color: var(--joal-green-ink);
  background: var(--joal-green-50);
  border-radius: var(--radius-full);
  padding: 2px 8px;
  display: inline-block;
}

/* Bloque de atribución estimada — visualmente distinto de la genealogía exacta */
.estimate-block {
  border: 1.5px dashed var(--amber-500);
  background: var(--amber-100);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}

.estimate-block__label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--amber-600);
  margin-bottom: 8px;
}

.estimate-block__disclaimer {
  font-size: 11px;
  color: var(--gray-600);
  margin-top: 8px;
  font-style: italic;
}

.exact-block {
  border-left: 3px solid var(--joal-green-500);
  padding-left: var(--space-4);
}

/* ================= Banner de identificación (fichas de lote/trazabilidad) ================= */
.entity-banner {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-xl);
  padding: 24px 28px;
  margin-bottom: var(--space-6);
  color: var(--white);
  background: linear-gradient(135deg, var(--joal-green-800) 0%, var(--joal-green-950) 100%);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.entity-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    124deg,
    rgba(255, 255, 255, 0.035) 0px,
    rgba(255, 255, 255, 0.035) 1px,
    transparent 1px,
    transparent 22px
  );
  pointer-events: none;
}

.entity-banner::after {
  content: "";
  position: absolute;
  width: 240px;
  height: 240px;
  border-radius: 50%;
  right: -80px;
  top: -100px;
  background: radial-gradient(circle, rgba(179, 144, 63, 0.2), transparent 70%);
  pointer-events: none;
}

.entity-banner__main {
  position: relative;
}

.entity-banner__eyebrow {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wider);
  color: var(--joal-green-200);
  font-weight: 700;
  margin-bottom: 4px;
}

.entity-banner__code {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 700;
  letter-spacing: var(--tracking-tight);
  color: var(--white);
}

.entity-banner__subtitle {
  position: relative;
  color: var(--joal-green-200);
  font-size: var(--text-sm);
  margin-top: 6px;
}

.entity-banner__actions {
  position: relative;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.entity-banner .btn--outline {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.28);
  color: var(--white);
}

.entity-banner .btn--outline:hover {
  background: rgba(255, 255, 255, 0.16);
}

/* ================= Grid de identificación (clave/valor) ================= */
.kv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: var(--space-4) var(--space-5);
}

.kv-item .kv-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--gray-500);
  font-weight: 700;
  margin-bottom: 3px;
}

.kv-item .kv-value {
  font-size: 14px;
  font-weight: 600;
  color: var(--gray-900);
  font-family: var(--font-display);
}

.detail-header {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* ================= Empty state (placeholders) ================= */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 40px 32px;
  max-width: 520px;
}

.empty-state__icon {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-md);
  background: var(--joal-green-100);
  color: var(--joal-green-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 6px;
}

/* ================= Buttons ================= */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast),
    box-shadow var(--transition-fast);
}

.btn--primary {
  background: var(--joal-green-700);
  color: var(--white);
}

.btn--primary:hover {
  background: var(--joal-green-800);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
}

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

.btn--outline {
  background: var(--paper);
  color: var(--gray-800);
  border: 1px solid var(--gray-300);
}

.btn--outline:hover {
  background: var(--gray-50);
  border-color: var(--gray-500);
  text-decoration: none;
}

/* Fase 9B.2 (hallazgo P1 #6 de la auditoría de usabilidad): estado visual
   de "procesando" -- el texto del botón ya cambia por JS (ver main.js),
   esto solo evita que un botón deshabilitado se vea idéntico a uno
   activo. Nunca depende únicamente del color: el texto es la señal
   principal. */
.btn:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

/* FASE E2B (pulido operativo de Recepción): "Más acciones" -- agrupa
   correcciones/anulaciones (delicadas) separadas de los botones
   rutinarios (imprimir, ver, volver), usando <details> nativo, sin JS.
   .actions-more (default): menú flotante -- para usarse en encabezados
   de página, donde no hay riesgo de recortarse contra un contenedor con
   scroll horizontal. .actions-more--flow: variante segura para dentro de
   tablas con overflow-x (ver reception/detail.html, tabla de tarimas) --
   el menú se abre EN EL FLUJO normal (empuja la fila) en vez de flotar,
   así nunca queda cortado por el scroll de la tabla. */
.actions-more summary {
  list-style: none;
  cursor: pointer;
}

.actions-more summary::-webkit-details-marker {
  display: none;
}

.actions-more__menu {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 6px;
  padding: 10px;
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-sm);
  background: var(--paper);
  position: absolute;
  right: 0;
  z-index: 20;
  min-width: 200px;
}

.actions-more {
  position: relative;
  display: inline-block;
}

.actions-more--flow .actions-more__menu {
  position: static;
  flex-direction: row;
  flex-wrap: wrap;
  margin-top: 8px;
  padding: 0;
  border: none;
  background: transparent;
  min-width: 0;
}

.actions-more__danger {
  color: var(--joal-error-600, #b3261e);
  border-color: var(--joal-error-600, #b3261e);
}

/* ================= Forms ================= */
.field {
  margin-bottom: 18px;
}

.field label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--gray-800);
  margin-bottom: 6px;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--gray-300);
  font-size: 13.5px;
  font-family: inherit;
  background: var(--input-bg);
  color: var(--gray-900);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.field textarea {
  resize: vertical;
  min-height: 72px;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--joal-green-500);
  box-shadow: 0 0 0 3px rgba(51, 120, 88, 0.35);
}

.field-hint {
  font-size: 11.5px;
  color: var(--gray-500);
  margin-top: 5px;
}

.field-error {
  color: var(--red-600);
  font-size: 12px;
  margin-top: 5px;
}

/* Fase 9B.2 (hallazgo P1 #8 de la auditoría de usabilidad): highlight
   ligero de campo con error, generalizado del patrón que ya usaba solo
   reception/new.html (estilo local) -- reutilizable en Piso/Empaque sin
   duplicar CSS por plantilla. Ver main.js para el scroll/focus asociado. */
.field.has-error input,
.field.has-error select,
.field.has-error textarea {
  border-color: var(--red-600);
  box-shadow: 0 0 0 3px var(--red-100);
}

/* Fase 9B.3 (hallazgo P2 #9 de la auditoría de usabilidad): preview de
   neto en vivo (bruto - tara) en formularios de pesaje -- solo
   presentación, el backend sigue siendo quien calcula/valida el neto
   real. Variante --invalid para tara > bruto (advertencia visual, la
   validación real sigue siendo del backend). */
.field-hint--net {
  font-weight: 700;
  color: var(--joal-green-800, var(--gray-800));
}

.field-hint--invalid {
  font-weight: 700;
  color: var(--red-600);
}

/* Fase 9B.3 (hallazgo P2 #10 de la auditoría): mismo patrón "tabla ->
   tarjetas apiladas" que ya usaba, en local, reception/new.html --
   generalizado aquí para reutilizarlo en cualquier tabla marcada con
   data-table--stack + data-label en cada <td>, sin duplicar HTML ni CSS
   por plantilla. Mismo quiebre que layout.css (860px). */
@media (max-width: 860px) {
  .data-table--stack thead {
    display: none;
  }
  .data-table--stack,
  .data-table--stack tbody,
  .data-table--stack tr,
  .data-table--stack td {
    display: block;
    width: 100%;
  }
  .data-table--stack tr {
    border: 1px solid var(--gray-300);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--paper);
  }
  .data-table--stack tr:last-child {
    margin-bottom: 0;
  }
  .data-table--stack td {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 7px 0;
    border: none;
    text-align: right;
  }
  .data-table--stack td:not(:last-child) {
    border-bottom: 1px solid var(--gray-100);
  }
  .data-table--stack td::before {
    content: attr(data-label);
    font-weight: 700;
    color: var(--gray-600);
    font-size: var(--text-sm);
    flex: none;
    text-align: left;
  }
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0 22px;
}

.form-grid .field--full {
  grid-column: 1 / -1;
}

@media (max-width: 720px) {
  .form-grid {
    grid-template-columns: 1fr;
  }
}

/* Formularios de captura táctil (tablet): campos e inputs más grandes que
   el tamaño por defecto de .field, mismo criterio ya usado en Nueva
   Recepción. Clase de utilidad reusable -- agregar class="touch-form" al
   <form> de cualquier pantalla donde el usuario captura datos parado
   frente a una báscula/tarima, sin duplicar CSS por template. */
.touch-form .field label {
  font-size: var(--text-md);
  font-weight: 700;
}

.touch-form .field input,
.touch-form .field select,
.touch-form .field textarea {
  font-size: var(--text-lg);
  padding: 12px 14px;
}

.touch-form .btn {
  font-size: var(--text-md);
  padding: 12px 22px;
}

/* Barra de filtros */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px;
  margin-bottom: var(--space-4);
}

.filter-bar .field {
  margin-bottom: 0;
  min-width: 160px;
}

.filter-bar .field--grow {
  flex: 1;
  min-width: 200px;
}

.flash {
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  margin-bottom: 14px;
  border: 1px solid transparent;
}

.flash--error {
  background: var(--red-100);
  color: var(--red-600);
  border-color: rgba(179, 69, 63, 0.2);
}

.flash--info {
  background: var(--blue-100);
  color: var(--blue-600);
  border-color: rgba(59, 110, 165, 0.18);
}
