/* ==========================================================================
   Chalonet Publicidad - Sistema Interno de Contabilidad e Inventario
   ========================================================================== */

:root {
  /*  Brand Palette */
  --ch-blue: #1277b2;
  --ch-blue-dark: #0d5a8a;
  --ch-blue-light: #1b8dcf;
  --ch-green: #95c230;
  --ch-green-hover: #b5d53b;
  --ch-purple: #6c4796;
  --ch-purple-dark: #523478;
  --ch-cyan: #00d4ff;

  /* Theme - Dark Default for Modern App feel */
  --bg-main: #0f121d;
  --bg-surface: #171b2d;
  --bg-surface-hover: #1f253d;
  --bg-card: rgba(23, 27, 45, 0.85);
  --bg-input: #21273d;
  --border-color: rgba(255, 255, 255, 0.1);
  --border-focus: var(--ch-blue);
  
  --text-main: #f0f3f8;
  --text-muted: #94a3b8;
  --text-inverse: #0f121d;

  /* Status Colors */
  --status-paid: #10b981;
  --status-paid-bg: rgba(16, 185, 129, 0.15);
  --status-partial: #f59e0b;
  --status-partial-bg: rgba(245, 158, 11, 0.15);
  --status-unpaid: #ef4444;
  --status-unpaid-bg: rgba(239, 68, 68, 0.15);

  --font-family: 'Poppins', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-full: 9999px;
  --shadow-sm: 0 2px 8px rgba(0,0,0,0.2);
  --shadow-md: 0 8px 24px rgba(0,0,0,0.3);
  --shadow-glow: 0 0 20px rgba(18, 119, 178, 0.25);
}

/* Light Theme Mode Support */
body.light-theme {
  --bg-main: #f4f6fb;
  --bg-surface: #ffffff;
  --bg-surface-hover: #eef2f8;
  --bg-card: #ffffff;
  --bg-input: #f1f5f9;
  --border-color: #e2e8f0;
  --text-main: #1e293b;
  --text-muted: #64748b;
  --shadow-sm: 0 2px 8px rgba(0,0,0,0.05);
  --shadow-md: 0 8px 24px rgba(0,0,0,0.08);
}

/* ==========================================================================
   ESCALA DE BREAKPOINTS (única fuente de verdad)
   --------------------------------------------------------------------------
   Usar SOLO estos 4 valores. Cualquier media query nueva debe usar uno de
   ellos, para evitar el solapamiento 600/650/651/768 que existía antes.

     480px  → phones pequeños (360-430). Botones y footers a ancho completo.
     768px  → tablets y phones grandes. Formularios a 1 columna, header compacto.
     1024px → portátil pequeño / tablet horizontal. Rejillas a 2-3 columnas.
     1280px → escritorio. Layout completo, sin restricciones.

   Convención: los breakpoints son "max-width" (móvil primero hacia arriba)
   salvo cuando seneecesita una mejora progresiva, en cuyo caso se documenta.
   ========================================================================== */

/* Global Reset */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  min-height: 100vh;
  font-family: var(--font-family);
  background-color: var(--bg-main);
  color: var(--text-main);
  line-height: 1.5;
  /* F8: era `hidden`, luego `clip`. Con F6 (tarjetas OT en filas) y F7
     (tablas como tarjetas) ya no quedan desbordes que recortar, así que se
     devuelve a `visible`.
     Importante: nunca usar `hidden` aquí. `overflow-x: hidden` convierte al
     body en contenedor de scroll, lo que fuerza `overflow-y: auto` y rompe el
     `position: sticky` de `.app-header`. */
  overflow-x: visible;
}

/* RED DE SEGURIDAD CONTRA SCROLL HORIZONTAL.
   `min-width: 0` en .app-content y .toolbar-group ya evitan que los filtros
   desborden, pero cualquier elemento futuro con ancho intrínseco alto (una
   tabla, un <select> nuevo, un título largo) volvería a romper la
   navegación. Estas reglas acotan los candidatos más habituales.
   NO se aplica a .ot-record-grid ni a .table-responsive, que sí necesitan
   su propio scroll horizontal intencionado. */
.app-content img,
.app-content svg,
.app-content canvas,
.card-title-bar {
  max-width: 100%;
}

.content-card,
.card-title-bar {
  min-width: 0;
}

.card-title-bar {
  flex-wrap: wrap;
}

a {
  color: var(--ch-cyan);
  text-decoration: none;
}

button, input, select, textarea {
  font-family: inherit;
  font-size: 14px;
}

/* FIX (F5) — anti-zoom de iOS en campos de formulario.
   En iOS Safari, enfocar un <input> con font-size < 16px provoca un zoom
   automático que desplaza la página y deja al usuario perdido a media
   pantalla, sin forma clara de volver. Es el fallo más grave de usabilidad en
   formularios móviles y NO se puede arreglar con reglas de layout.
   Chrome en Android no hace ese zoom, así que se limita a Safari/iOS. */
@supports (-webkit-touch-callout: none) {
  input, select, textarea {
    font-size: 16px;
  }
}

/* Canvas Background */
#ambient-network {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  opacity: 0.4;
}

/* App Wrapper */
.app-container {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* Header Navbar */
.app-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: 70px;
  background: rgba(15, 18, 29, 0.92);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border-color);
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.brand-wrapper {
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand-logo {
  height: 42px;
  width: auto;
}

.system-badge {
  background: linear-gradient(135deg, var(--ch-blue), var(--ch-purple));
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

/* Luz de estado de sincronizacion. El detalle permanece en title y aria-label. */
.sync-status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  padding: 0;
  border-radius: 50%;
  background: var(--bg-surface);
}

.sync-status::before {
  content: '';
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
  box-shadow: 0 0 0 1px currentColor;
}

.sync-status.sincronizando {
  color: #b8860b;
}

.sync-status.sincronizado {
  color: #1a7f47;
}

.sync-status.error {
  color: #b3261e;
}

/* El texto de los botones del header es lo que impide que quepan en móvil.
   Los botones llevan un emoji identificador y un `title`, así que en
   pantallas estrechas se oculta solo el texto y quedan como iconos. La
   clase `.btn-label` se aplica en F8 sobre el nodo de texto. */
.header-actions .btn-label {
  white-space: nowrap;
}

.btn-icon {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  color: var(--text-main);
  width: 38px;
  height: 38px;
  border-radius: var(--radius-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn-icon:hover {
  background: var(--bg-surface-hover);
  border-color: var(--ch-blue);
  color: var(--ch-cyan);
}

/* Primary CTA Buttons */
.btn-primary {
  background: linear-gradient(135deg, var(--ch-blue), #1898e2);
  color: #fff;
  border: none;
  padding: 8px 18px;
  border-radius: var(--radius-md);
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 4px 12px rgba(18, 119, 178, 0.3);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(18, 119, 178, 0.45);
}

.btn-purple {
  background: linear-gradient(135deg, var(--ch-purple), #8b5cf6);
  color: #fff;
  border: none;
  padding: 8px 18px;
  border-radius: var(--radius-md);
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 4px 12px rgba(108, 71, 150, 0.35);
  transition: transform 0.2s ease, background 0.2s ease;
}

.btn-purple:hover {
  transform: translateY(-2px);
  background: linear-gradient(135deg, #7e4eb1, #9d6afd);
  color: #fff;
}

.btn-green {
  background: linear-gradient(135deg, var(--ch-green), #7ca623);
  color: #0d1e02;
  border: none;
  padding: 8px 18px;
  border-radius: var(--radius-md);
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 4px 12px rgba(149, 194, 48, 0.3);
  transition: transform 0.2s ease;
}

.btn-green:hover {
  transform: translateY(-2px);
  background: var(--ch-green-hover);
}

.btn-secondary {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  color: var(--text-main);
  padding: 8px 16px;
  border-radius: var(--radius-md);
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: background 0.2s ease;
}

.btn-secondary:hover {
  background: var(--bg-surface-hover);
}

/* App Main Navigation Bar */
.app-nav-bar {
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border-color);
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  overflow-x: auto;
  white-space: nowrap;
  -webkit-overflow-scrolling: touch;
}

.nav-tabs {
  display: flex;
  gap: 4px;
  /* `min-width: 0` + `flex-shrink: 0`: sin esto, los tabs se COMPRIMEN dentro
     del contenedor con scroll en vez de desbordarlo. Con ambos, la barra
     gana el scroll horizontal que ya tiene `.app-nav-bar`. */
  min-width: 0;
  flex-shrink: 0;
}

.nav-tab {
  padding: 14px 18px;
  color: var(--text-muted);
  border-bottom: 3px solid transparent;
  font-weight: 500;
  font-size: 14px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.nav-tab:hover {
  color: var(--text-main);
  background: rgba(255, 255, 255, 0.03);
}

.nav-tab.active {
  color: var(--ch-cyan);
  border-bottom-color: var(--ch-cyan);
  font-weight: 600;
  background: rgba(0, 212, 255, 0.05);
}

.tab-badge {
  background: var(--ch-purple);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 10px;
}

/* Main Content Area */
.app-content {
  flex: 1;
  padding: 24px;
  max-width: 1440px;
  margin: 0 auto;
  width: 100%;
  /* `min-width: 0` permite que .app-content se encoja dentro de
     .app-container (flex column) en lugar de desbordar. Sin esto, cualquier
     hijo ancho (los <select> de filtros, las tarjetas, las tablas) genera
     scroll horizontal de página. */
  min-width: 0;
}

.tab-pane {
  display: none;
  animation: fadeIn 0.3s ease-in-out;
}

.tab-pane.active {
  display: block;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Dashboard Filter Bar */
.toolbar-panel {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 16px 20px;
  margin-bottom: 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  box-shadow: var(--shadow-sm);
}

.toolbar-panel.filters-hidden {
  display: none;
}

.clients-pagination {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 16px;
  color: var(--text-muted);
  font-size: 12px;
}

.clients-pagination button:disabled {
  cursor: not-allowed;
  opacity: .45;
}

.toolbar-group {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  /* `min-width: 0` en un flex container permite que sus hijos con ancho
     intrínseco grande (los <select>, cuyo ancho depende del texto de su
     opción más larga) se encojen en lugar de desbordar. Sin esto, un
     <select> con una opción tipo "Histórico Completo (Todos los Meses)"
     empuja el buscador fuera del recuadro y, con `overflow-x: visible` en el
     body, provoca scroll horizontal en toda la página. */
  min-width: 0;
  max-width: 100%;
}

/* Los <select> de la barra de filtros necesitan poder encogerse por debajo
   de su ancho intrínseco. `width: 100%` + `min-width: 0` hace que ocupen todo
   el ancho disponible en móvil y se repartan en 2 columnas en tablet. */
.toolbar-group > .form-select {
  min-width: 0;
  max-width: 100%;
  width: auto;
  flex: 1 1 200px;
}

.search-box {
  position: relative;
  /* `min-width: 0` (no 260px) permite que la caja se encoja por debajo de 260px
     cuando el padre es un flex container estrecho. Combinado con el
     `width:100%` de la media query de 768px, evita el desborde horizontal del
     buscador dentro de la barra de herramientas y de los modales.
     El mínimo de 260px solo se aplica en el breakpoint de 1280px. */
  min-width: 0;
}

/* Autocomplete Suggestions Dropdown */
.suggestions-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  max-height: 200px;
  overflow-y: auto;
  z-index: 1000;
  margin-top: 4px;
}

.suggestion-item {
  padding: 10px 14px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid var(--border-color);
  font-size: 13px;
  transition: background 0.15s ease;
}

.suggestion-item:last-child {
  border-bottom: none;
}

.suggestion-item:hover, .suggestion-item.selected {
  background: var(--bg-surface-hover);
  color: var(--ch-cyan);
}

.suggestion-phone {
  font-size: 11px;
  color: var(--text-muted);
}

.search-box input {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  color: var(--text-main);
  padding: 8px 14px 8px 36px;
  border-radius: var(--radius-md);
  outline: none;
  transition: border-color 0.2s ease;
}

.search-box input:focus {
  border-color: var(--ch-blue);
}

.search-box i {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
}

.form-select, .form-input {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  color: var(--text-main);
  padding: 8px 14px;
  border-radius: var(--radius-md);
  outline: none;
}

.form-select:focus, .form-input:focus {
  border-color: var(--ch-blue);
}

.pill-btn {
  border: none;
  background: transparent;
  color: var(--text-muted);
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all 0.2s ease;
}

.pill-btn.active {
  background: var(--ch-blue);
  color: #fff;
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}

/* KPI Summary Cards Grid */
.kpi-grid {
  display: grid;
  /* `min(240px, 100%)` impide que el mínimo de 240px desborde cuando el
     ancho útil es menor (p.ej. 320px de viewport - 32px de padding = 288px,
     o dentro de un modal con 20px de inset lateral). */
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 20px;
  margin-bottom: 28px;
}

.kpi-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 20px;
  position: relative;
  overflow: hidden;
  transition: transform 0.2s ease, border-color 0.2s ease;
}

.kpi-card:hover {
  transform: translateY(-3px);
  border-color: rgba(18, 119, 178, 0.4);
}

.kpi-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 4px;
  height: 100%;
  background: var(--card-accent, var(--ch-blue));
}

.kpi-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 500;
  margin-bottom: 10px;
}

.kpi-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.05);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  color: var(--card-accent, var(--ch-blue));
}

.kpi-value {
  font-size: 26px;
  font-weight: 700;
  color: var(--text-main);
  letter-spacing: -0.5px;
  margin-bottom: 4px;
}

.kpi-subtext {
  font-size: 12px;
  color: var(--text-muted);
}

.kpi-mini-balance {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border-color);
  color: var(--text-muted);
  font-size: 11px;
}

.kpi-mini-balance strong { color: var(--status-unpaid); }
.kpi-fixed-cost strong { color: var(--status-partial); }
.kpi-card.kpi-hide-context .kpi-context-detail { display: none; }

/* Special Alert Banner for Receivable Problem */
.accounting-insight-banner {
  background: linear-gradient(135deg, rgba(108, 71, 150, 0.2), rgba(18, 119, 178, 0.2));
  border: 1px solid rgba(108, 71, 150, 0.4);
  border-radius: var(--radius-lg);
  padding: 16px 20px;
  margin-bottom: 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.insight-content {
  display: flex;
  align-items: center;
  gap: 14px;
}

.insight-icon {
  font-size: 28px;
}

.insight-title {
  font-weight: 600;
  font-size: 15px;
  color: var(--text-main);
}

.insight-desc {
  font-size: 13px;
  color: var(--text-muted);
}

.content-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 20px;
  margin-bottom: 24px;
}

.card-title-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}

.card-title {
  font-size: 17px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Custom Data Table */
.table-responsive {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* --------------------------------------------------------------------------
   F7 — TARJETAS DE TABLA EN MÓVIL
   `buildTableCards()` en js/sistema.js genera esta versión a partir de la
   propia tabla (leyendo los <th> como etiquetas). El marcado se genera
   SIEMPRE; CSS decide cuál versión se muestra. En escritorio solo se ve la
   tabla, así que el HTML adicional no afecta al escritorio.
   -------------------------------------------------------------------------- */
.table-card-list {
  display: none;
}

.table-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-left: 4px solid var(--ch-cyan);
  border-radius: var(--radius-md);
  padding: 14px;
  margin-bottom: 12px;
}

.table-card-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  border-bottom: 1px dashed var(--border-color);
}

.table-card-item:last-of-type {
  border-bottom: none;
}

.table-card-label {
  flex: 0 0 auto;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}

.table-card-value {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  text-align: right;
  overflow-wrap: anywhere;
}

.table-card-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(72px, 1fr));
  gap: 8px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border-color);
}

.table-card-actions > button,
.table-card-actions > a,
.table-card-actions > div {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 8px 10px;
  font-size: 13px;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
  font-size: 13.5px;
}

.data-table th {
  background: var(--bg-surface);
  color: var(--text-muted);
  font-weight: 600;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-color);
  white-space: nowrap;
}

.data-table td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-color);
  color: var(--text-main);
  vertical-align: middle;
}

.data-table tbody tr {
  transition: background 0.15s ease;
}

.data-table tbody tr:hover {
  background: var(--bg-surface-hover);
}

.data-table .past-due-row td { background: rgba(239, 68, 68, 0.09); }

/* OT Number: compact, single line everywhere */
.ot-num {
  font-size: 12px;
  white-space: nowrap;
}

.ot-card-list {
  display: grid;
  gap: 12px;
}

.ot-record-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-left: 4px solid var(--ch-cyan);
  border-radius: var(--radius-md);
  padding: 14px;
}

/* F6: la tarjeta de OT y Cotización es un flex row con 2 zonas:
     - izquierda: las 2 líneas de datos + el detalle (`.ot-record-body`)
     - derecha:   los botones de acción, en columna (`.ot-record-footer`)
   Así los badges (Línea, Estado) no se salen de su celda y las acciones quedan
   alineadas verticalmente a la derecha.

   El `:has()` limita esto a las tarjetas que TIENEN `.ot-record-body`. Las
   tarjetas de Gastos (renderGastosTab) reutilizan `.ot-record-card` pero con
   su propia grid y deben seguir siendo bloques normales. */
.ot-record-card:has(.ot-record-body) {
  display: flex;
  align-items: stretch;
  gap: 16px;
}

.ot-record-body {
  flex: 1 1 auto;
  min-width: 0;
}

.ot-record-footer {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  border-left: 1px solid var(--border-color);
  padding-left: 16px;
}

.ot-record-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}

.ot-record-grid {
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  gap: 12px;
}

/* La tarjeta de OT/Cotización reparte sus 10 campos en 2 líneas de 5.
   Se limita a las grids dentro de `.ot-record-body` para no tocar los Gastos,
   que traen su propia definición de columnas (`.fixed-cost-grid` y
   `.expense-record-grid`). */
.ot-record-body > .ot-record-grid {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px 12px;
}

/* Las cotizaciones tienen 6 campos, que caben en una sola línea. */
.ot-record-body > .quote-record-fields {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

/* --- Celda de campo: etiqueta + valor como unidad indivisible ---
   Que la etiqueta y su valor vivan en el MISMO contenedor es lo que
   garantiza que cada título caiga sobre su propio dato. Con dos grids
   separadas (una de etiquetas y otra de valores) bastaba un desajuste de
   columnas para que "ENTREGA" acabara encima del total. */
.ot-record-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.ot-record-key {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  /* La etiqueta puede partirse sin desbordar su columna. */
  overflow-wrap: anywhere;
  hyphens: auto;
}

.ot-record-val {
  font-size: 13px;
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.35;
}

/* El badge de "Línea" era el que se salía de su celda. Ahora la columna es
   el doble de ancha y el badge puede partirse en varias líneas en vez de
   desbordar sobre el campo contiguo. */
.ot-record-val .badge {
  max-width: 100%;
  white-space: normal;
  text-align: center;
  overflow-wrap: anywhere;
}

/* Gastos */
.fixed-cost-grid { grid-template-columns: 2fr 1fr 1.2fr 1.2fr; }
.fixed-cost-labels { margin-bottom: 5px; color: var(--text-muted); font-size: 10px; font-weight: 600; text-transform: uppercase; }
.fixed-cost-values { font-size: 13px; padding: 8px 0; border-bottom: 1px dashed var(--border-color); }
.fixed-cost-total { border-bottom: none; border-top: 2px solid var(--border-color); }
.expense-record-grid { grid-template-columns: 1fr 2.4fr 1fr 1fr 1.1fr 0.8fr; }
.expense-record-labels { margin-bottom: 5px; color: var(--text-muted); font-size: 10px; font-weight: 600; text-transform: uppercase; }
.expense-total-value { color: var(--status-unpaid); font-weight: 700; }
.expense-total-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  font-weight: 600;
}
.expense-total-row .expense-total-value { font-size: 20px; }

/* Historial de cambios */
.history-card { margin-bottom: 14px; }
.history-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
  font-size: 12px;
  color: var(--text-muted);
}
.history-row { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 8px; }
.history-row-tag {
  flex: 0 0 82px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding-top: 16px;
}
.history-row-before .history-row-tag { color: var(--status-unpaid); }
.history-row-after .history-row-tag { color: var(--ch-cyan); }
.history-row-body { flex: 1 1 0; min-width: 0; }
.history-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
  gap: 8px 14px;
  width: 100%;
  min-width: 0;
}
.history-field {
  min-width: 0;
  padding: 6px 4px;
  border-bottom: 1px dashed var(--border-color);
}
.history-field-label {
  display: block;
  margin-bottom: 3px;
  color: var(--text-muted);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}
.history-field-value {
  min-width: 0;
  font-size: 13px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}
.history-field-value.history-changed { color: var(--ch-cyan); font-weight: 700; }

.ot-record-detail { margin: 10px 0 0; color: var(--text-main); font-size: 13px; }


/* ---------- 600px: TARJETA OT / COTIZACIÓN COMO TABLA DE 2 COLUMNAS ----
   En móvil cada campo pasa a ser su propia fila:
     [ nombre del dato ] ......... [ información ]
   Es el mismo formato que usan las tarjetas de "Por Cobrar" y las tarjetas
   de tabla generadas en F7, para que el sistema se lea igual en todas las
   pestañas.

   Cada campo (`.ot-record-field`) contiene su etiqueta (`.ot-record-key`) y su
   valor (`.ot-record-val`). En escritorio la celda es una columna con la
   etiqueta encima del valor; aquí la MISMA celda rota a horizontal. Como
   etiqueta y valor viajan en el mismo contenedor, nunca pueden desalinearse.

   El corte se hace a 600px y no a 768px porque a 768 la tarjeta de 5 columnas
   todavía se lee bien con su scroll horizontal. */
@media (max-width: 600px) {
  .history-row { display: block; }
  .history-row-tag { padding-top: 0; margin-bottom: 4px; }
  .history-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 135px), 1fr)); }

  /* La tarjeta vuelve a ser bloque simple: los datos arriba y las acciones
     debajo, en lugar de la columna lateral de escritorio. */
  .ot-record-card:has(.ot-record-body) {
    display: block;
  }

  /* Una sola columna: cada campo ocupa su propia fila. */
  .ot-record-body > .ot-record-grid {
    grid-template-columns: 1fr;
    gap: 0;
    overflow-x: visible;
  }

  /* La celda gira: la etiqueta a la izquierda, el valor a la derecha,
     separados por un borde punteado. */
  .ot-record-field {
    display: flex;
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 7px 0;
    border-bottom: 1px dashed var(--border-color);
  }

  .ot-record-field:last-child {
    border-bottom: none;
  }

  /* La etiqueta deja de estar encima: pasa a ocupar el ancho justo. */
  .ot-record-field .ot-record-key {
    flex: 0 0 auto;
    font-size: 10.5px;
    letter-spacing: 0.5px;
    text-align: left;
  }

  .ot-record-field .ot-record-val {
    flex: 1 1 auto;
    text-align: right;
  }

  /* Badges (Estado, Línea) alineados a la derecha sin desbordar. */
  .ot-record-field .badge {
    white-space: normal;
    font-size: 11px;
    padding: 3px 8px;
  }

  /* --- Botones de acción: debajo de los datos, a ancho completo ---
     Es el requisito explícito: los datos en filas y las acciones abajo.
     Cada botón crece para que sea cómodo de pulsar con el dedo. */
  .ot-record-footer {
    /* En escritorio el footer es una columna lateral con borde izquierdo.
       En móvil vuelve a ser una franja horizontal debajo de los datos. */
    flex-direction: row;
    border-left: none;
    border-top: 1px solid var(--border-color);
    padding-left: 0;
    padding-top: 12px;
    margin-top: 12px;
  }

  .ot-record-actions {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(72px, 1fr));
    gap: 8px;
    width: 100%;
  }

  .ot-record-actions > * {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px 10px;
    font-size: 13px;
    white-space: nowrap;
  }

  /* --- F7: tablas -> tarjetas ---
     A 600px una tabla de 5-9 columnas obliga a un scroll horizontal que en
     la práctica esconde datos y confunde. Aquí la tabla se oculta y se
     muestra la versión tarjeta, con una fila por dato: etiqueta a la
     izquierda, valor a la derecha, y las acciones debajo a ancho completo.

     Se usa un atributo `data-cards` en vez de `.table-responsive` a secas,
     porque la vista de lista del catálogo (`#products-list-view`) alterna su
     `display` con estilos inline desde renderProductsTab(), y los estilos
     inline ganan a esta media query. El atributo lo coloca
     `applyTableCards()` solo en las tablas que sí tienen versión tarjeta. */
  [data-cards] > .table-responsive { display: none; }
  [data-cards] > .table-card-list { display: block; }

  .table-card {
    padding: 12px;
    margin-bottom: 10px;
  }

  /* --- Gastos (F8) ---
     `renderGastosTab` reutiliza `.ot-record-grid` con `.fixed-cost-grid`
     (4 col) y `.expense-record-grid` (6 col), pero NO usa celdas de campo
     (`.ot-record-field`): sus celdas son planas y siguen necesitando la fila
     de encabezados de arriba para saber qué es cada valor. Por eso aquí solo
     se colapsan a una columna, apilando etiqueta y valor. */
  .ot-record-card > .ot-record-grid.fixed-cost-grid,
  .ot-record-card > .ot-record-grid.expense-record-grid {
    grid-template-columns: 1fr;
    gap: 4px;
    overflow-x: visible;
  }

  .fixed-cost-labels,
  .expense-record-labels {
    margin-bottom: 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border-color);
  }

  .fixed-cost-values,
  .expense-record-grid.ot-record-values {
    padding: 8px 0;
    border-bottom: 1px dashed var(--border-color);
    font-size: 13px;
  }
}

/* Status Badges */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.badge-paid {
  background: var(--status-paid-bg);
  color: var(--status-paid);
}

.badge-partial {
  background: var(--status-partial-bg);
  color: var(--status-partial);
}

.badge-unpaid {
  background: var(--status-unpaid-bg);
  color: var(--status-unpaid);
}

.badge-department {
  background: rgba(18, 119, 178, 0.15);
  color: var(--ch-cyan);
  border: 1px solid rgba(0, 212, 255, 0.2);
}

/* WhatsApp Link Button */
.btn-whatsapp-sm {
  background: #25d366;
  color: #fff;
  border: none;
  padding: 5px 10px;
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  text-decoration: none;
}

.btn-whatsapp-sm:hover {
  background: #1eb956;
  color: #fff;
}

/* Catalog View Switcher (Icons vs List) */
.view-mode-toggle {
  display: flex;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 3px;
}

.view-btn {
  border: none;
  background: transparent;
  color: var(--text-muted);
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 14px;
}

.view-btn.active {
  background: var(--ch-purple);
  color: #fff;
}

/* Product Icon Grid View */
.product-grid {
  display: grid;
  /* `min(260px, 100%)` — ver nota en .kpi-grid. Sin esto el mínimo de 260px
     desborda en viewports de 320-360px y dentro de modales estrechos. */
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
  gap: 20px;
  margin-top: 20px;
}

.product-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  transition: transform 0.2s ease, border-color 0.2s ease;
}

.product-card:hover {
  transform: translateY(-4px);
  border-color: var(--ch-green);
}

.product-icon-header {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 14px;
}

.product-icon-box {
  width: 52px;
  height: 52px;
  border-radius: var(--radius-md);
  background: linear-gradient(135deg, rgba(108,71,150,0.3), rgba(18,119,178,0.3));
  border: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  flex-shrink: 0;
}

.product-title-group h3 {
  font-size: 16px;
  font-weight: 600;
  color: var(--text-main);
  line-height: 1.2;
}

.product-category-tag {
  font-size: 11px;
  color: var(--ch-green);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.product-cost-breakdown {
  background: var(--bg-surface);
  border-radius: var(--radius-md);
  padding: 12px;
  margin: 12px 0;
  font-size: 12.5px;
}

.product-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 10px;
}

.price-tag {
  font-size: 20px;
  font-weight: 700;
  color: var(--ch-cyan);
}

/* Modals */
/* ============================================================================
   FUNCTION BUILDER STYLES
   ============================================================================ */

.functions-list {
  margin-top: 12px;
}

.function-item {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}

.function-header {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
}

.function-type {
  background: var(--ch-blue);
  color: #fff;
  padding: 4px 12px;
  border-radius: var(--radius-full);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.function-config {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-color);
}

.function-config-panel {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 16px;
  margin-bottom: 12px;
}

.function-config-panel h4 {
  margin: 0 0 12px;
  font-size: 14px;
  color: var(--ch-cyan);
}

.function-config-panel h5 {
  margin: 12px 0 8px;
  font-size: 13px;
  color: var(--text-muted);
}

/* --- Presets (una sola definición; la duplicada de más abajo se eliminó) --- */
.presets-list {
  margin-bottom: 8px;
}

.preset-item {
  display: flex;
  gap: 8px;
  margin-bottom: 6px;
  align-items: center;
  /* Sin `min-width` en los hijos: dentro de .modal-body el ancho útil a 320px
     es ~280px, y 150px + 90px + botón + gaps no caben. `min-width: 0` permite
     que los campos flex se encojan en lugar de desbordar. */
  min-width: 0;
}

.preset-item input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
}

.preset-item input[type="number"] {
  flex: 0 0 80px;
  width: 80px;
  min-width: 0;
}

.preset-item .btn-sm {
  flex: 0 0 auto;
  padding: 4px 8px;
  font-size: 11px;
}

.function-config-panel .form-group {
  margin-bottom: 8px;
}

.function-config-panel .form-group label {
  font-size: 12px;
}

.function-config-panel .form-group input {
  font-size: 13px;
}

.function-config-panel .form-grid-2,
.function-config-panel .form-grid-3 {
  gap: 8px;
}

.function-config-panel .form-group small {
  font-size: 11px;
  color: var(--text-muted);
}

.functions-list .function-item {
  animation: slideIn 0.2s ease;
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.function-item .btn-sm {
  padding: 4px 10px;
  font-size: 11px;
}

.function-config-panel .btn-sm {
  padding: 4px 10px;
  font-size: 11px;
}

/* NOTA: la segunda definición de .preset-item / .preset-item input (gap:6px
   + min-width:150px + width:90px) que existía más abajo en este archivo fue
   eliminada. Esa versión era la que desbordaba en móvil. La regla canónica
   está arriba, junto al resto de estilos de presets. */

#functions-list .function-item {
  position: relative;
}

#functions-list .function-item .btn-danger {
  background: var(--status-unpaid);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
}

#functions-list .function-item .btn-danger:hover {
  opacity: 0.9;
}

.function-config-panel .presets-list .preset-item {
  background: var(--bg-surface);
  padding: 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-color);
}

.function-config-panel .presets-list .preset-item input {
  font-size: 12px;
}

.function-config-panel .btn-secondary {
  margin-top: 8px;
}

/* Modals */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(6px);
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

.modal-overlay.active {
  opacity: 1;
  pointer-events: auto;
}

.modal-window {
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  width: min(100%, 860px);
  max-height: 90vh;
  overflow-y: auto;
  /* FIX (era `hidden`): `hidden` cortaba el contenido ancho sin dar scroll, lo
     hacía irrecuperable dentro del modal. `auto` permite desplazar en ambos
     ejes sin alterar el comportamiento vertical. */
  overflow-x: auto;
  box-shadow: var(--shadow-md);
  transform: scale(0.95);
  transition: transform 0.25s ease;
}

.modal-overlay.active .modal-window {
  transform: scale(1);
}

/* --------------------------------------------------------------------------
   MODAL — header, close y footer (F4)
   Estructura real: .modal-window > .modal-header + form > (.modal-body + .modal-footer)
   El contenedor de scroll es .modal-window, por lo que `position: sticky` en
   el footer y el header funciona pegado a los bordes de ese scroll.
   -------------------------------------------------------------------------- */
.modal-header {
  padding: 18px 24px;
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* FIX: sin wrap, un título largo + el botón × se solapaban en pantallas
     estrechas. `min-width: 0` en el título le permite partirse en varias
     líneas en vez de empujar la × fuera del modal. */
  gap: 12px;
  flex-wrap: nowrap;
  /* El header se mantiene visible al hacer scroll vertical dentro del modal. */
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-surface);
}

.modal-title {
  font-size: 18px;
  font-weight: 600;
  /* Permite que el título encoja y llegue a partirse; sin esto, un título
     largo (p.ej. "Registrar Nueva Orden de Trabajo (OT)") desborda y empuja
     el botón de cerrar fuera del modal en móvil. */
  min-width: 0;
  flex: 1 1 auto;
  overflow-wrap: break-word;
}

.modal-close {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 22px;
  cursor: pointer;
  /* FIX: el área de toque real era de ~26×26px (solo el glifo &times;).
     Con 38px + padding se acerca al mínimo recomendado de 44px sin alterar
     el aspecto visual del glifo. */
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  transition: background 0.15s ease, color 0.15s ease;
  line-height: 1;
}

.modal-close:hover {
  background: var(--bg-surface-hover);
  color: var(--text-main);
}

.nav-link-tab {
  color: inherit;
  text-decoration: none;
}

.form-input, .form-select {
  box-sizing: border-box;
  max-width: 100%;
}

.modal-body {
  padding: 24px;
  /* FIX (era `hidden`): `hidden` recortaba el contenido ancho sin dar scroll.
     Se cambia a `visible` (no `auto`) a propósito: `.modal-window` ya es el
     contenedor de scroll del modal, así que un segundo contenedor de scroll
     anidado no aportaba nada y sí rompía dos cosas —
       1) `position: sticky` del footer, porque un ancestro con `overflow`
          distinto de `visible` lo anula;
       2) el autocomplete de clientes, que es `position: absolute` y quedaba
          recortado por este `auto`.
     El scroll horizontal real lo aporta ahora `.modal-window`. */
  overflow-x: visible;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
}

.form-grid-3 {
  display: grid;
  grid-template-columns: 2fr 1.2fr 1fr;
  gap: 12px;
}

.form-grid-2 {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.form-grid-1 {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

/* --------------------------------------------------------------------------
   FORMULARIOS OT / EDITAR OT / COTIZACIÓN (F5)
   Los tres forms son isomorfos y comparten estas clases. El JS alterna la
   visibilidad de `.material-group`, `.dimensions-grid`, `.scrap-group` y los
   `.option-panel` con `style.display`, así que aquí NO se debe tocar
   `display` de esos contenedores: solo su comportamiento interno.
   -------------------------------------------------------------------------- */

/* Los campos de un `.form-group` son flexible items. Sin `min-width: 0`, un
   input con `size` por defecto o un placeholder largo empuja al contenedor y
   desborda la celda del grid en móvil. */
.form-group > input,
.form-group > select,
.form-group > textarea,
.form-group > div {
  min-width: 0;
  max-width: 100%;
}

/* El contenedor inline de "Número de OT" + botón 🔄 (`.ot-number-row`,
   HTML 374) tiene `display:flex` inline. En móvil el input + botón se
   aprietan hasta que el texto del correlativo se corta. */
.ot-number-row {
  min-width: 0;
  width: 100%;
}
.ot-number-row > input[type="text"] {
  min-width: 0;
  flex: 1 1 auto;
}

/* Etiquetas: en móvil el texto en mayúsculas con letter-spacing parte en dos
   líneas y descuadra la columna. Se permite el salto pero se reduce el
   interletraje para ganar ancho. */
.form-group label {
  overflow-wrap: break-word;
}

/* El texto de sugerencia de retazos (`.scrap-suggestion-text`) es un hint
   pequeño; en móvil conviene que sea legible y no se corte a media frase. */
.scrap-suggestion-text {
  overflow-wrap: break-word;
  line-height: 1.4;
}

/* Checkboxes de costo extra por cm² (los inyecta `updateProductPanels`).
   El JS genera el markup con estilos inline, así que aquí solo se refuerza
   el área de toque y el wrap, sin tocar `display` del contenedor. */
.extra-cost-item label,
.option-panel label[style*="inline-flex"] {
  min-height: 32px;
  padding: 4px 0;
}

.extra-cost-label {
  overflow-wrap: break-word;
}

@media (min-width: 769px) {
  .dimensions-grid.no-material {
    grid-template-columns: 1.2fr 1fr;
  }
}

/* ---------- 768px: tablets y phones grandes ----------
   (antes era 650px; la escala unificada es 768) */
@media (max-width: 768px) {
  .form-grid, .form-grid-3, .form-grid-2 {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   UTILIDADES (F5)
   Estas clases se usan en sistema.html y las inyecta js/sistema.js (p.ej.
   renderCobranzasTab genera `text-muted`, `text-center` y `text-right`),
   pero NO existían como definiciones. Sin ellas esos elementos heredaban el
   color y la alineación del contenedor, lo que dejaba importes y etiquetas
   visualmente mal alineados, también en móvil.   -------------------------------------------------------------------------- */
.text-muted { color: var(--text-muted); }
.text-center { text-align: center; }
.text-right { text-align: right; }

.form-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-group.full-width {
  grid-column: 1 / -1;
}

.form-group label {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.checkbox-group { display: flex; flex-wrap: wrap; gap: 12px; }
.checkbox-group label { text-transform: none; color: var(--text-main); font-weight: 500; }

.modal-footer {
  padding: 16px 24px;
  border-top: 1px solid var(--border-color);
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  /* FIX (F4): el footer se pegaba al borde de abajo del área de scroll del
     modal, de modo que "Guardar" / "Cancelar" quedaban siempre alcanzables sin
     tener que bajar hasta el final del formulario. En móvil el formulario de
     OT es largo, así que esto era el mayor problema de usabilidad.
     `flex-wrap` evita que 2-3 botones se compriman hasta solaparse. */
  flex-wrap: wrap;
  position: sticky;
  bottom: 0;
  z-index: 2;
  background: var(--bg-surface);
  /* Difuminado para que el contenido que pasa por debajo no compita con los
     botones cuando se hace scroll. */
  box-shadow: 0 -6px 12px -6px rgba(0, 0, 0, 0.25);
}

/* ==========================================================================
   RESPONSIVIDAD — FIN DE ARCHIVO
   Reglas agrupadas por breakpoint, en orden descendente de ancho.
   Cada fase del plan añade sus reglas en su bloque correspondiente.
   ========================================================================== */

/* ---------- 1280px: escritorio ---------- */
@media (min-width: 1280px) {
  /* En escritorio la barra de herramientas tiene sitio de sobra, así que el
     buscador recupera su ancho mínimo cómodo. */
  .search-box { min-width: 260px; }
}

/* ---------- 1024px: portátil pequeño / tablet horizontal ---------- */
@media (max-width: 1024px) {
  .kpi-grid { gap: 16px; }
  .app-content { padding: 20px; }
}

/* ---------- 768px: tablets y phones grandes ---------- */
@media (max-width: 768px) {
  .app-header {
    padding: 0 16px;
    height: 60px;
  }
  .app-content {
    padding: 16px;
  }
  .toolbar-panel {
    flex-direction: column;
    align-items: stretch;
    padding: 14px;
    gap: 12px;
  }
  .toolbar-group {
    width: 100%;
    gap: 10px;
  }
  .search-box {
    width: 100%;
    flex: 1 1 100%;
  }
  /* Cada filtro ocupa una línea completa. Con `min-width: 0` se encojan al
     ancho disponible en vez de desbordar por su opción más larga. */
  .toolbar-group > .form-select {
    flex: 1 1 100%;
    width: 100%;
  }
  .kpi-grid { gap: 12px; }

  /* --- Header y navegación (F8) ---
     El header tiene altura fija y 5 acciones con texto largo. A 768px el
     logo (42px) + badge + 5 botones no caben, y como la altura es fija el
     contenido se recorta en lugar de desbordar. */
  .app-header {
    height: auto;
    min-height: 60px;
    padding: 8px 16px;
    gap: 12px;
  }

  .brand-logo { height: 34px; }
  .brand-wrapper { gap: 8px; min-width: 0; }

  /* El badge "Sistema Interno" es decorativo: roba ancho en móvil. */
  .system-badge { display: none; }

  .header-actions { gap: 8px; }

  /* A 768px todavía hay sitio para el texto de los botones, pero se les
     reduce el padding para ganar margen. */
  .header-actions .btn-purple,
  .header-actions .btn-green,
  .header-actions .btn-secondary {
    padding: 8px 12px;
    font-size: 13px;
  }

  /* La barra de pestañas ya tiene scroll horizontal. Se le da padding
     lateral y se evita que su alto crezca por el badge. */
  .app-nav-bar { padding: 0 12px; }
  .nav-tab { padding: 12px 14px; font-size: 13px; }

  /* --- KPIs (F8) ---
     `.kpi-mini-balance` no tenía wrap: con dos textos y un gap se salía de
     la tarjeta en anchos estrechos. */
  .kpi-mini-balance { flex-wrap: wrap; }
  .kpi-card { padding: 16px; }
  .kpi-value { font-size: 22px; }

  /* --- Modales (F4) ---
     A 768px el inset lateral de 20px + padding de 24px dejaba solo ~320px
     útiles en una tablet de 768px. Se reduce para ganar ancho real. */
  .modal-overlay { padding: 12px; }
  .modal-header { padding: 14px 16px; }
  .modal-body { padding: 18px 16px; }
  .modal-footer { padding: 12px 16px; }
  .modal-title { font-size: 17px; }

  /* --- Formularios (F5) ---
     Los grids colapsan a 1 columna. Los inputs de Alto / Ancho / Cantidad /
     Precio necesitan un alto mínimo real para pulsarse sin ambigüedad.
     El `font-size:16px` de iOS (regla global) ya sube el alto; aquí se
     refuerza el padding vertical para que el área de toque sea cómoda. */
  .form-input,
  .form-select,
  textarea.form-input {
    padding-top: 10px;
    padding-bottom: 10px;
  }

  /* Los selects con textos largos ("Impresión de Cartas / Menú") necesitan
     poder recortarse con puntos suspensivos en vez de desbordar. */
  .form-select {
    text-overflow: ellipsis;
  }

  /* Material + Alto + Ancho apilados: son 3 campos relacionados y en 1
     columna consumen mucho alto. Se mantienen legibles pero compactos. */
  .dimensions-grid .form-group label,
  .scrap-group .form-group label {
    font-size: 11.5px;
  }

  /* La fila OT + 🔄: el botón no debe robarle ancho al input. */
  .ot-number-row > .btn-secondary {
    flex: 0 0 auto;
    padding: 8px 12px;
    font-size: 15px;
  }
}

/* ---------- 480px: phones pequeños ----------
   Objetivo: que los botones de acción del modal sean igual de alcanzables
   y cómodo de pulsar que en escritorio, sin importar cuán largo sea el
   formulario. Los botones pasan a ocupar el ancho completo. */
@media (max-width: 480px) {
  /* Overlay casi a pantalla completa, pero NO con padding 0: sin un pequeño
     inset el modal queda pegado a los bordes y la `×` de cerrar queda a
     inches de la pantalla. Con 8px respira sin robar ancho útil. */
  .modal-overlay { padding: 8px; }

  /* `dvh` (altura dinámica del viewport) en lugar de `vh`: en móviles, `vh`
     no descuenta la barra de direcciones ni la barra inferior del navegador,
     así que con `vh` el footer sticky se quedaba debajo de la barra de
     direcciones y parecía inaccesible. `dvh` sí refleja el alto real. */
  .modal-window {
    max-height: calc(100dvh - 16px);
    border-radius: var(--radius-md);
  }

  .modal-header {
    padding: 12px 14px;
    /* El header se mantiene fijo arriba mientras se hace scroll en el
       formulario, así el usuario siempre sabe en qué modal está. */
    position: sticky;
    top: 0;
  }

  .modal-body { padding: 16px 14px; }

  .modal-footer {
    padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
    gap: 8px;
  }

  /* Botones de acción a ancho completo y con altura cómoda para el dedo.
     En columna, cada botón ocupa su propia línea: así da igual si el footer
     tiene 2 botones (Cancelar / Guardar) o 3 (Conservar / Actualizar), todos
     quedan igual de alcanzables. */
  .modal-footer {
    flex-direction: column;
    align-items: stretch;
  }
  .modal-footer > button {
    width: 100%;
    min-height: 44px;
    padding: 10px 14px;
    font-size: 14px;
  }

  /* El título puede partirse, pero la × mantiene su área de toque. */
  .modal-close { width: 40px; height: 40px; }

  /* --- Header y navegación (F8) ---
     A 480px los 3 botones con texto ("Cotización", "Nueva OT / Venta",
     "Agregar Gasto") no caben junto al logo. Se oculta solo el texto y
     quedan como botones de icono. Cada uno conserva su `title`, así que el
     nombre sigue disponible al pasar el cursor o al leerlos en un lector de
     pantalla. La acción NO cambia: es la misma, solo cambia lo que se ve. */
  .app-header {
    padding: 8px 12px;
    gap: 8px;
  }

  .brand-logo { height: 30px; }

  .header-actions { gap: 6px; }
  .header-actions .btn-label { display: none; }

  .header-actions .btn-purple,
  .header-actions .btn-green,
  .header-actions .btn-secondary {
    padding: 0;
    width: 40px;
    height: 40px;
    min-height: 40px;
    justify-content: center;
    font-size: 16px;
    border-radius: var(--radius-md);
  }

  /* Los .btn-icon del header (tema e historial) se alinean con el resto. */
  .header-actions .btn-icon {
    width: 40px;
    height: 40px;
  }

  /* Tabs más compactos: con 8 pestañas el scroll horizontal es inevitable,
     pero al menos caben más por pantalla. */
  .app-nav-bar { padding: 0 8px; }
  .nav-tab { padding: 11px 11px; font-size: 12.5px; gap: 5px; }
  .nav-tab .tab-badge { font-size: 10px; padding: 2px 5px; }
}
