/* Sistema Master GP1 — Estilos */

/* ═══════════════════════════════════════════════════════════════════════
   SISTEMA MASTER GP1 · TOKENS
   ───────────────────────────────────────────────────────────────────────
   Vocabulario del sistema de diseño que entregó Claude Design (ago-2026).
   Todo color, tamaño y espacio de la app sale de aquí: en una vista no va
   nunca un hex suelto — si hace falta un color nuevo, se agrega arriba.

   Los nombres dicen el SIGNIFICADO, no el color: --ok-fg, no --verde. Así
   un cambio de paleta no obliga a releer 700 sitios para saber cuáles
   querían decir "salió bien" y cuáles solo querían verde.

   La guía visual (Administración › Guía visual) muestra todo esto
   renderizado con este mismo archivo, así que no puede quedar desfasada.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* ═══ 1 · RAMPA NEUTRA · cálida, misma familia que el #f5f4f0 de hoy ═══ */
  --n-0:   #ffffff;   --n-25:  #faf9f6;   --n-50:  #f5f4f0;   --n-100: #eceae3;
  --n-200: #e2e0d8;   --n-300: #cecbc0;   --n-400: #a5a299;   --n-500: #767469;
  --n-600: #5f5e58;   --n-700: #454440;   --n-800: #2b2a27;   --n-900: #1a1a18;

  /* ═══ 2 · ROLES ═══ */
  --bg:              var(--n-50);    /* fondo de la app                 */
  --surface:         var(--n-0);     /* tarjeta, tabla, drawer          */
  --surface-alt:     var(--n-25);    /* hover de fila                   */
  --surface-captura: #fbfaf4;        /* columnas nuestras, no del CRM   */
  --border:          var(--n-200);   /* borde por defecto               */
  --border-sutil:    var(--n-100);   /* entre renglones de tabla        */
  --border-fuerte:   var(--n-300);   /* bajo encabezado, entre grupos   */

  --text-1: var(--n-900);   /* 16.4:1 · dato, nombre, título           */
  --text-2: var(--n-600);   /*  6.5:1 · etiqueta, meta, th             */
  --text-3: var(--n-500);   /*  4.7:1 · placeholder, pie — el piso     */
  --text-inv: #ffffff;

  --accion:   #0f6e56;      /* crear algo nuevo. NO es --ok-fg.        */
  --accion-h: #0c5945;
  --foco:     #185fa5;
  --anillo:   0 0 0 3px rgba(24,95,165,.25);

  /* ═══ 3 · SEMÁNTICOS · por significado, no por color ═══
     Contraste fg sobre bg verificado en los seis pares.               */
  --ok-fg:#067a57;   --ok-bg:#e1f5ee;   --ok-bd:#a9dfcd;   /* 4.71 */
  --warn-fg:#8f5700; --warn-bg:#faeeda; --warn-bd:#ecd3a6; /* 5.18 */
  --err-fg:#c62828;  --err-bg:#fcebeb;  --err-bd:#f0b4b4;  /* 4.88 */
  --info-fg:#185fa5; --info-bg:#e6f1fb; --info-bd:#b3d3f0; /* 5.70 */
  --alt-fg:#534ab7;  --alt-bg:#eeedfe;  --alt-bd:#c9c6f3;  /* 6.00 */
  --mut-fg:#5f5e58;  --mut-bg:#eceae3;  --mut-bd:#d8d5cc;  /* 5.40 */

  /* ═══ 3b · PUNTOS DE SEMÁFORO · la marca, no el texto ═══
     Por qué existen aparte (10-ago-2026): el punto heredaba el color del
     texto, y el texto está obligado a contraste AA sobre fondo claro. Eso
     empuja a verdes y rojos oscuros y convierte el amarillo en café: a 9 px
     los tres se veían del mismo tono apagado, y en las pantallas de la
     oficina no se distinguían. Separar la marca del texto deja subir el
     color sin tocar la legibilidad de la palabra que va al lado.

     Son objetos gráficos, así que el listón es 3:1 y no 4.5:1. El ámbar es
     la excepción: ningún amarillo de verdad llega a 3:1 sobre blanco, así
     que se le pone un aro oscuro que le da el borde. Es eso o volver al
     café.                                                              */
  --ok-punto:   #059669;   /* 3.77:1 sobre blanco */
  --warn-punto: #f0a202;   /* 2.13:1 + aro — ver .sem-prog::before */
  --err-punto:  #e02424;   /* 4.72:1 sobre blanco */
  --punto-aro:  inset 0 0 0 1px rgba(0,0,0,.22);

  /* ═══ 4 · TIPOGRAFÍA · pila del sistema, sin cargar fuentes ═══ */
  --fuente: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --fuente-num: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --fs-100: 11px;  /* versalitas, badges, th, contadores — piso duro   */
  --fs-200: 12px;  /* tabla densa, meta, control en celda             */
  --fs-300: 13px;  /* interfaz por defecto                            */
  --fs-400: 14px;  /* base del documento, molde B, prosa              */
  --fs-500: 16px;  /* título de pantalla, cabecera de drawer          */
  --fs-600: 20px;  /* cifra de estadística                            */
  --fs-700: 26px;  /* login, portada de PDF                           */
  --lh-1: 1.25;    /* tabla densa, títulos                            */
  --lh-2: 1.4;     /* interfaz                                        */
  --lh-3: 1.6;     /* prosa                                           */

  /* ═══ 5 · ESPACIO · rejilla de 4 ═══ */
  --sp-05:2px; --sp-1:4px;  --sp-2:8px;  --sp-3:12px;
  --sp-4:16px; --sp-6:24px; --sp-8:32px; --sp-12:48px;

  /* ═══ 6 · FORMA Y ELEVACIÓN ═══ */
  --r-sm:6px; --r:8px; --r-lg:12px; --r-full:999px;
  --sombra-1: 0 1px 2px  rgba(26,26,24,.06);   /* apoya: tarjeta      */
  --sombra-2: 0 4px 14px rgba(26,26,24,.10);   /* flota: tooltip      */
  --sombra-3: 0 12px 32px rgba(26,26,24,.18);  /* tapa:  drawer       */

  /* ═══ 7 · DENSIDAD · la única perilla ═══ */
  --ctl-h:    32px;
  --fila-py:  6px;
  --fila-px:  10px;
  --fs-tabla: 12.5px;
  /* Anclas pegajosas. El handoff traia --h-topbar:49px como estimacion y el
     thead pegado a top:0. Medido en la app: la barra superior mide 63px y el
     thead 45px. Con los valores del handoff pasaban dos cosas: quedaba una
     franja blanca de 5px entre el encabezado y la fila de evento, y al hacer
     scroll el thead se metia DEBAJO de la barra superior (z-index 2 vs 50).
     Los dos altos se fijan aqui y se imponen abajo, para que los calculos
     no dependan de cuanto mida el contenido.                                */
  --h-topbar: 63px;   /* barra superior de la app (sticky, z-index 50) */
  --h-thead:  45px;   /* encabezado de la tabla densa: 2 lineas de 11px */
  --w-nav:    220px;

}

/* Perilla de densidad: una clase en <body>. Guardar la preferencia por
   usuario igual que ya se guarda el estado del menú (localStorage). */
.d-compacta { --ctl-h:26px; --fila-py:3px;  --fila-px:6px;  --fs-tabla:12px; }
.d-comoda   { --ctl-h:36px; --fila-py:10px; --fila-px:12px; --fs-tabla:13px; }



* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: var(--fs-400);
  line-height: var(--lh-3);
  color: var(--text-1);
  background: var(--bg);
}

a { color: var(--n-900); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ── LOGIN ──
   Pantalla partida: a la izquierda qué es esto y si el dato está fresco; a la
   derecha el formulario. La mitad oscura no es adorno — lleva el estado de la
   copia de EasyPlanner, que es el dato del que depende todo lo demás y que
   hasta ahora solo se descubría entrando y capturando sobre datos de antier.

   Debajo de 800 px el panel pasa arriba y se encoge: en un teléfono lo que se
   viene a hacer es entrar, no leer.                                          */
.login-page { min-height: 100vh; }
.lg-marco { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); min-height: 100vh; }
.lg-lado {
  background: var(--n-900); color: #fff;
  padding: var(--sp-8) var(--sp-8);
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-8);
}
.lg-logo { width: 172px; height: 43px; object-fit: contain; object-position: left center; display: block; }
.lg-tit { font-size: var(--fs-600); font-weight: 700; letter-spacing: -.3px; margin-top: 20px; }
.lg-bajada { font-size: var(--fs-300); line-height: var(--lh-3);
             color: rgba(255,255,255,.72); margin: 6px 0 0; max-width: 34ch; }
.lg-estado { border-top: 1px solid rgba(255,255,255,.14); padding-top: var(--sp-4); }
.lg-estado-t { display: block; font-size: var(--fs-100); font-weight: 700;
               text-transform: uppercase; letter-spacing: .8px;
               color: rgba(255,255,255,.45); margin-bottom: 7px; }
/* El semáforo se aclara sobre fondo oscuro: los tonos del sistema están
   calculados contra tarjeta blanca y aquí no contrastan. */
.lg-estado .sem-ok   { color: #6ddcb8; }
.lg-estado .sem-pend { color: #f0a3a3; }
.lg-estado .sem-pend::before { box-shadow: none; }
.lg-estado .sem-nulo { color: rgba(255,255,255,.5); }
.lg-estado-s { font-size: var(--fs-200); line-height: var(--lh-2);
               color: rgba(255,255,255,.62); margin: 5px 0 0; max-width: 40ch; }
/* La ventana del sync es un dato permanente, no el resultado de la corrida de
   anoche: se separa con una linea y se atenua para que no compita con el
   semaforo, pero siga siendo legible. */
.lg-estado-vent { margin-top: 10px; padding-top: 9px;
                  border-top: 1px solid rgba(255,255,255,.12);
                  color: rgba(255,255,255,.5); }
.lg-estado-vent b { color: rgba(255,255,255,.72); font-weight: 600; }

.lg-form { display: flex; align-items: center; justify-content: center;
           padding: var(--sp-8) var(--sp-6); background: var(--bg); }
.lg-h { font-size: var(--fs-600); font-weight: 700; letter-spacing: -.3px; margin: 0 0 var(--sp-6); }
.lg-pie { font-size: var(--fs-200); color: var(--text-3); line-height: var(--lh-2);
          margin: var(--sp-4) 0 0; }

@media (max-width: 800px) {
  .lg-marco { grid-template-columns: minmax(0,1fr); min-height: 0; }
  .lg-lado  { padding: var(--sp-6); gap: var(--sp-4); }
  .lg-bajada { display: none; }
  .lg-form  { min-height: auto; padding: var(--sp-6); }
}

/* ── LAYOUT ── */
.app-shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 220px; flex-shrink: 0;
  background: var(--text-1);
  display: flex; flex-direction: column;
  position: fixed; top: 0; left: 0; bottom: 0;
  z-index: 100;
}
.sidebar-logo {
  padding: 1.25rem var(--sp-4) var(--sp-4);
  color: #fff; font-size: var(--fs-500); font-weight: 700;
  border-bottom: 1px solid rgba(255,255,255,.1);
}
.sidebar-logo span { color: #5DCAA5; }
/* ── Menu de usuario ───────────────────────────────────────────────────
   El bloque de nombre + area es el disparador; abajo cuelga lo que cada
   quien puede administrar de si mismo.                                   */
.sidebar-user { border-bottom: 1px solid rgba(255,255,255,.1); }
.su-btn {
  width: 100%; display: flex; align-items: center; gap: 8px;
  padding: var(--sp-3) var(--sp-4); background: none; border: 0; cursor: pointer;
  font-family: inherit; text-align: left; color: inherit;
}
.su-btn:hover { background: rgba(255,255,255,.06); }
.su-txt { flex: 1; min-width: 0; }
.sidebar-user-name { display: block; color: #fff; font-size: var(--fs-300); font-weight: 500; }
.sidebar-user-area {
  display: block; font-size: var(--fs-100); color: rgba(255,255,255,.5);
  text-transform: uppercase; letter-spacing: .5px;
}
.su-flecha { color: rgba(255,255,255,.45); font-size: var(--fs-100); transition: transform .15s; }
.sidebar-user.abierto .su-flecha { transform: rotate(180deg); }
.su-menu { display: none; padding: 0 0 var(--sp-2); }
.sidebar-user.abierto .su-menu { display: block; }
.su-menu a {
  display: block; padding: .45rem var(--sp-4) .45rem 1.75rem;
  font-size: var(--fs-200); color: rgba(255,255,255,.65);
}
.su-menu a:hover { color: #fff; background: rgba(255,255,255,.06); text-decoration: none; }
nav.sidebar-nav { flex: 1; padding: var(--sp-2) 0; overflow-y: auto; }
.nav-section {
  font-size: var(--fs-100); color: rgba(255,255,255,.35);
  text-transform: uppercase; letter-spacing: .8px;
  padding: var(--sp-3) var(--sp-4) var(--sp-1);
}
.nav-item {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  color: rgba(255,255,255,.7);
  font-size: var(--fs-300);
  cursor: pointer; transition: background .15s;
  border-left: 3px solid transparent;
}
.nav-item:hover { background: rgba(255,255,255,.07); color: #fff; }
.nav-item.active {
  background: rgba(255,255,255,.1); color: #fff;
  border-left-color: #5DCAA5;
}
.nav-dot {
  width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
}

/* ── Módulo plegable de la barra lateral ──
   <details> nativo: pliega sin una línea de JS y sigue funcionando con el
   JS caído. El módulo activo lo abre PHP con el atributo open.
   El triángulo propio del navegador se esconde (list-style + el pseudo de
   WebKit, que no obedece al primero) y se pinta uno propio que gira. */
.sidebar-nav .mod { border-bottom: 1px solid rgba(255,255,255,.08); }
.sidebar-nav .mod > summary {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4); cursor: pointer; list-style: none;
  color: rgba(255,255,255,.6); font-size: var(--fs-100);
  text-transform: uppercase; letter-spacing: .8px;
  transition: background .15s, color .15s;
}
.sidebar-nav .mod > summary::-webkit-details-marker { display: none; }
.sidebar-nav .mod > summary::before {
  content: '›'; font-size: 13px; line-height: 1; width: 6px;
  transition: transform .15s; transform-origin: 45% 50%;
}
.sidebar-nav .mod[open] > summary::before { transform: rotate(90deg); }
.sidebar-nav .mod > summary:hover { background: rgba(255,255,255,.07); color: #fff; }
.sidebar-nav .mod[open] > summary { color: rgba(255,255,255,.85); }
/* Los enlaces se recorren para que se lean como hijos del módulo. */
.sidebar-nav .mod .nav-item { padding-left: var(--sp-6); }

/* ── Espacios (9-oct-2026) ──
   Arriba de las secciones: el regreso a la pantalla de módulos y el nombre del
   espacio en el que se está, para que nadie confunda el menú de Tesorería con
   el de Operación. */
.esp-nav { border-bottom: 1px solid rgba(255,255,255,.1); padding: var(--sp-2) 0; }
.esp-volver {
  display: block; padding: var(--sp-1) var(--sp-4);
  font-size: var(--fs-200); color: rgba(255,255,255,.55);
}
.esp-volver:hover, .esp-volver.active { color: #fff; text-decoration: none; }
.esp-actual {
  padding: var(--sp-1) var(--sp-4) 0;
  color: #fff; font-size: var(--fs-400); font-weight: 700;
}
.sidebar-footer {
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid rgba(255,255,255,.1);
}
.sidebar-footer a {
  color: rgba(255,255,255,.5); font-size: var(--fs-200);
}
.sidebar-footer a:hover { color: #fff; }

.main-content {
  margin-left: 220px; flex: 1;
  display: flex; flex-direction: column; min-height: 100vh;
  /* min-width:0 porque es hijo de un flex, y ahi el valor por omision es `auto`:
     el elemento se niega a encogerse por debajo de su contenido. Con una tabla
     ancha adentro eso empujaba TODA la pagina —barra, menu y encabezado— a
     scroll horizontal, en vez de dejar que la tabla se desplazara sola dentro
     de su tarjeta. Se destapo con la matriz de 13 columnas de Comercial
     (26-ago-2026), pero le pasaba a cualquier contenido ancho.
     Solo PERMITE encoger; a las pantallas que ya cabian no les cambia nada. */
  min-width: 0;
}
.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: .875rem var(--sp-6);
  display: flex; align-items: center; justify-content: space-between;
  position: sticky; top: 0; z-index: 50;
}
.topbar-title { font-size: var(--fs-500); font-weight: 600; }
.topbar-actions { display: flex; gap: var(--sp-2); align-items: center; }
.page-body { padding: var(--sp-6); flex: 1; }

/* ── CARDS ── */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 1.25rem var(--sp-6);
}
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--sp-4); padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.card-title { font-size: var(--fs-400); font-weight: 600; }

/* ── TABLE ── */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: var(--fs-300); }
th {
  text-align: left; padding: .625rem var(--sp-3);
  font-size: var(--fs-100); font-weight: 600;
  color: var(--text-2); text-transform: uppercase; letter-spacing: .5px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
td {
  padding: var(--sp-3) var(--sp-3);
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
tr:last-child td { border-bottom: none; }
tr:hover td { background: #faf9f7; }
.td-code { font-family: monospace; font-size: var(--fs-200); color: var(--text-2); }
.td-name { font-weight: 500; }
.td-date { white-space: nowrap; color: var(--text-2); font-size: var(--fs-200); }

/* ── ETIQUETA DE ESTADO · .et ──
   Design la propuso para sustituir a .badge-verde/-amarillo/-rojo/-azul/
   -morado/-gris: los nombres nuevos dicen el SIGNIFICADO, no el color, y el
   borde es lo que faltaba (sin él la etiqueta flota sobre blanco y se pierde
   sobre el fondo de la página).

   Los nombres viejos se quedan como alias. Son 152 usos repartidos en 30
   vistas y el mapa color→significado no es limpio: .badge-gris hace de
   "apagado" en unas y de "neutro informativo" en otras. Renombrar a ciegas
   cambiaría el significado de algunas. Con el alias, las 152 heredan el look
   nuevo hoy y la migración se hace vista por vista, cuando toque tocarlas.
   Código nuevo: <span class="et et-ok">Concluído</span>. */
.badge, .et {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 9px; border-radius: var(--r-full);
  font-size: var(--fs-100); font-weight: 600; line-height: 18px;
  white-space: nowrap; border: 1px solid transparent;
}
.et-ok,   .badge-verde    { background: var(--ok-bg);   color: var(--ok-fg);   border-color: var(--ok-bd);   }
.et-warn, .badge-amarillo { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-bd); }
.et-err,  .badge-rojo     { background: var(--err-bg);  color: var(--err-fg);  border-color: var(--err-bd);  }
.et-info, .badge-azul     { background: var(--info-bg); color: var(--info-fg); border-color: var(--info-bd); }
.et-alt,  .badge-morado   { background: var(--alt-bg);  color: var(--alt-fg);  border-color: var(--alt-bd);  }
.et-mut,  .badge-gris     { background: var(--mut-bg);  color: var(--mut-fg);  border-color: var(--mut-bd);  }

.dot {
  width: 8px; height: 8px; border-radius: 50%; display: inline-block;
}
.dot-verde    { background: var(--ok-punto); }
.dot-amarillo { background: var(--warn-punto); box-shadow: var(--punto-aro); }
.dot-rojo     { background: var(--err-punto); }
.dot-gris     { background: var(--text-3); }

/* ══ MOLDE E · FORMULARIO DE UNA ENTIDAD ══════════════════════════════
   Crear proveedor, editar receta, alta de usuario, configuración. Una sola
   columna de 640 px: un formulario de alta se lee de arriba abajo y en dos
   columnas se salta renglones sin darse cuenta.

   Lo que trae de nuevo respecto a lo que había: el error va PEGADO a su
   campo (.fg.mal + .err-msg) y no solo en un .alert arriba, donde obliga a
   volver a buscar cuál de los ocho campos era; la ayuda vive bajo el campo
   (.ayuda); y el pie separa las acciones, con lo destructivo lejos.

   .form-group / .form-row / .form-hint se quedan como alias de .fg /
   .fg-dos / .ayuda: son doce vistas y renombrarlas todas de golpe no
   cambiaría nada en pantalla. El código nuevo usa los nombres cortos.   */
.form-mol { max-width: 640px; }

/* Sección con encabezado propio, para partir un formulario largo. */
.fs {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 18px 20px;
  margin-bottom: var(--sp-3); box-shadow: var(--sombra-1);
}
.fs > h4 { font-size: var(--fs-300); font-weight: 700; margin-bottom: 3px; }
.fs > .fs-ay { font-size: var(--fs-200); color: var(--text-2); line-height: 1.5; margin-bottom: 14px; }

.fg, .form-group { margin-bottom: 13px; }
.fg > label, .form-group label {
  display: block; font-size: var(--fs-100); font-weight: 600;
  text-transform: uppercase; letter-spacing: .4px;
  color: var(--text-2); margin-bottom: 5px;
}
.fg .req { color: var(--err-fg); }

input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], select, textarea {
  width: 100%; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r);
  font-size: var(--fs-400); font-family: inherit;
  background: var(--surface); color: var(--text-1);
  transition: border-color .15s, box-shadow .15s;
  appearance: none;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--foco); box-shadow: var(--anillo);
}
textarea { resize: vertical; min-height: 80px; line-height: 1.5; }

/* [hidden] tiene que ganar. El navegador lo aplica con display:none desde su
   hoja de estilo, y CUALQUIER regla de autor la vence: basta un .algo{display:
   flex} para que un elemento marcado hidden siga a la vista. Paso el 14-ago-2026
   en la ficha de proveedor —el "no aplica" y su campo se mostraban a la vez— y
   volveria a pasar en cualquier pantalla que combine hidden con un display de
   clase. Es la unica regla !important del archivo, y se gana el privilegio. */
[hidden] { display: none !important; }

/* Campo en error: el borde y el fondo lo señalan, el mensaje lo explica. */
.fg.mal input, .fg.mal select, .fg.mal textarea {
  border-color: var(--err-fg); background: var(--err-bg);
}
.fg .err-msg { font-size: var(--fs-200); color: var(--err-fg); margin-top: 5px; font-weight: 500; }
.fg .ayuda, .form-hint { font-size: var(--fs-200); color: var(--text-3); margin-top: 5px; line-height: 1.45; }

.fg-dos { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.form-row {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

/* Pie: guardar a la derecha, lo destructivo al otro extremo (.izq), y en
   medio el dato que quita la duda antes de guardar ("se aplica a 12 SETs"). */
.form-pie {
  display: flex; align-items: center; gap: var(--sp-2); justify-content: flex-end;
  padding-top: 14px; border-top: 1px solid var(--border); margin-top: var(--sp-2);
}
.form-pie .izq { margin-right: auto; font-size: var(--fs-200); color: var(--text-3); }

/* ── BUTTONS ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r);
  font-size: var(--fs-300); font-weight: 500; font-family: inherit;
  cursor: pointer; border: 1px solid transparent;
  transition: background .15s, opacity .15s;
  white-space: nowrap;
}
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-primary { background: var(--n-900); color: #fff; border-color: var(--n-900); }
.btn-primary:hover { background: var(--n-700); }
.btn-outline {
  background: transparent; border-color: var(--border); color: var(--text-1);
}
.btn-outline:hover { background: var(--bg); }
.btn-sm { padding: .3rem .7rem; font-size: var(--fs-200); }
.btn-full { width: 100%; }
.btn-green { background: var(--ok-fg); color: #fff; border-color: var(--ok-fg); }
.btn-green:hover { opacity: .9; }

/* Quitar un renglón de una tabla editable: la ✕ al final de la fila. No lleva
   caja porque no compite con la acción principal de la pantalla — se busca
   cuando ya se decidió borrar, no antes.
   Vivía como `.pf-del` en un <style> local de proveedor.php. Se sube al sistema
   el 15-ago-2026 al necesitarla la segunda pantalla: copiarla habría dado dos
   definiciones que se separan con el tiempo, que es justo lo que pasó con
   pl-ok/pl-error. Ver configuracion/guia.php §6. */
.btn-quitar {
  border: none; background: none; color: var(--err-fg);
  cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px;
  border-radius: var(--r);
}
.btn-quitar:hover { background: var(--err-bg, transparent); }

/* ── ALERTS ── */
.alert {
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r);
  font-size: var(--fs-300); margin-bottom: var(--sp-4);
}
.alert-error   { background: var(--err-bg);    color: var(--err-fg);   border: 1px solid #f09595; }
.alert-success { background: var(--ok-bg);  color: var(--ok-fg); border: 1px solid #5DCAA5; }
.alert-info    { background: var(--info-bg);   color: var(--info-fg);  border: 1px solid #85b7eb; }

/* ── IMAGEN SET ── */
.set-img {
  width: 64px; height: 64px; object-fit: cover;
  border-radius: var(--r); border: 1px solid var(--border);
  flex-shrink: 0;
}
.set-img-placeholder {
  width: 64px; height: 64px; border-radius: var(--r);
  background: var(--bg); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3); font-size: var(--fs-100); text-align: center;
  flex-shrink: 0;
}

/* ── PROGRESS BAR ── */
.progress-wrap {
  height: 6px; background: var(--border); border-radius: 3px;
  overflow: hidden; min-width: 80px;
}
.progress-bar {
  height: 100%; border-radius: 3px; transition: width .3s;
}
/* La barra es una marca, no texto: va con los colores de punto, igual que el
   semáforo. El #ba7517 que estaba aquí era el último hex suelto de la paleta. */
.progress-bar.p-low    { background: var(--text-3); }
.progress-bar.p-mid    { background: var(--warn-punto); }
.progress-bar.p-high   { background: var(--ok-punto); }
.progress-bar.p-done   { background: var(--ok-punto); }

/* ── STATS ROW ── */
.stats-row {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  margin-bottom: var(--sp-6);
}
.stat-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--sp-4) 1.25rem;
}
.stat-label { font-size: var(--fs-100); color: var(--text-2); text-transform: uppercase;
              letter-spacing: .5px; margin-bottom: var(--sp-1); }
.stat-value { font-size: var(--fs-700); font-weight: 700; line-height: var(--lh-1); }
.stat-sub   { font-size: var(--fs-100); color: var(--text-3); margin-top: var(--sp-05); }

/* ── MOBILE ── */
@media (max-width: 768px) {
  .sidebar { transform: translateX(-100%); transition: transform .25s; }
  .sidebar.open { transform: translateX(0); }
  .main-content { margin-left: 0; }
  .page-body { padding: var(--sp-4); }
  .stats-row { grid-template-columns: 1fr 1fr; }
}

/* ── Sidebar colapsable ────────────────────────────────────────────────
   Permite recoger el menu hacia la izquierda y ganar ancho para los datos.
   El estado se recuerda en localStorage (ver layout_top.php).            */
.sidebar      { transition: width .18s ease, transform .18s ease; }
.main-content { transition: margin-left .18s ease; }

.app-shell.sidebar-collapsed .sidebar {
  width: 0;
  overflow: hidden;
  border-right: none;
}
.app-shell.sidebar-collapsed .main-content { margin-left: 0; }

/* Boton hamburguesa: visible en escritorio cuando hay sidebar */
#menu-toggle {
  display: inline-flex !important;
  align-items: center; justify-content: center;
  min-width: 38px; min-height: 34px;
  font-size: var(--fs-500); line-height: 1;
}

/* ── ESTANDARES DE TABLA (aplican a toda la app) ──────────────────────
   Convenciones: texto a la izquierda, numeros a la derecha con cifras de
   ancho fijo, fechas y estados centrados. Encabezados siempre en el mismo
   estilo (ya definido en `th`): no anular text-transform en vistas.        */
.col-num  { text-align: right; font-variant-numeric: tabular-nums; }
.col-cen  { text-align: center; }
.col-fecha{ text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Truncado uniforme para textos largos: el valor completo va en title="" */
.col-trunc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ═══════════════════════════════════════════════════════════════════════
   SISTEMA MASTER GP1 · FASE 2 — DENSIDAD DE LA TABLA DE CAPTURA
   ───────────────────────────────────────────────────────────────────────
   Sustituye el bloque `.table-densa` actual de app.css (y las reglas de
   `.table-densa textarea.pl-edit`). NO cambia markup ni PHP: las clases
   .table-densa, .col-num, .col-cen, .col-fecha, .col-trunc y .pl-edit son
   las mismas que ya usa la app.

   Añade dos clases NUEVAS que sí hay que poner en el PHP para aprovechar
   todo — pero la hoja funciona sin ellas:
     .cap      en cada <td>/<th> de columna capturada por nosotros
     .cap-ini  además, en la PRIMERA columna de esa zona

   Los cuatro movimientos:
     1 · controles callados (sin caja hasta que se tocan)
     2 · zona de captura (fondo propio + una línea, en vez de 6 cajas)
     3 · tres pesos de línea (renglón / grupo / encabezado)
     4 · anclas pegajosas (thead y fila de evento)
   ═══════════════════════════════════════════════════════════════════════ */

.table-densa {
  table-layout: fixed;
  width: 100%;
  font-size: var(--fs-tabla);
  border-collapse: collapse;
}

/* ── encabezado ────────────────────────────────────────────────────────
   SIN position:sticky. El handoff lo pedia, pero no sobrevive a este markup:
   Chrome no pega un <th> cuando la tabla usa border-collapse:collapse, y con
   separate tampoco funciono. Ademas la tarjeta contenedora recorta. Se probaron
   las tres combinaciones y ninguna pego el encabezado.
   El sticky de la fila de evento se retira con el: una cabecera de grupo
   flotando sin su encabezado de columnas encima es peor que ninguna.        */
.table-densa th {
  height: var(--h-thead);
  z-index: 2;
  text-align: left;
  /* DESVIACION del handoff, a proposito: el handoff pide padding --fila-px y
     letter-spacing .4px. Con 16 columnas eso hace que los titulos ya no quepan
     y se partan a media palabra ("ESTATU/S", "RECO/L."). El CSS anterior ya
     traia un comentario advirtiendolo. Se conserva el piso de 11px del sistema
     y se recupera el espaciado apretado, que es lo que hace que quepan.        */
  padding: var(--sp-2) var(--sp-1);
  font-size: var(--fs-100);
  font-weight: 600;
  color: var(--text-2);
  text-transform: uppercase;
  letter-spacing: 0;
  line-height: var(--lh-1);
  background: var(--bg);
  border-bottom: 1px solid var(--border-fuerte);
  white-space: normal;
  overflow-wrap: break-word;
  overflow: hidden;
  vertical-align: bottom;
}

/* ── renglones ─────────────────────────────────────────────────────── */
.table-densa td {
  position: relative;
  padding: var(--fila-py) var(--fila-px);
  border-bottom: 1px solid var(--border-sutil);   /* línea 1 · casi invisible */
  vertical-align: middle;
  line-height: var(--lh-2);
}
.table-densa tbody tr:hover td { background: var(--surface-alt); }

/* El renglón enfocado se ilumina ENTERO. Con 16 columnas es lo que evita
   capturar en la fila de al lado. CSS puro, sin JS. */
.table-densa tbody tr:focus-within td { background: #f2f7fd; }

/* ── fila de grupo (evento) · pegajosa bajo el encabezado ──────────── */
.table-densa tr.pl-grupo td,
.table-densa tr.grupo td {
  z-index: 1;
  background: var(--n-100);
  border-top: 2px solid var(--border-fuerte);      /* línea 3 · la fuerte  */
  border-bottom: 1px solid var(--border-fuerte);   /* línea 2 · la media   */
  font-size: var(--fs-200);
  padding: var(--sp-1) var(--fila-px);
}

/* ── zona de captura: lo nuestro, no del CRM ───────────────────────── */
.table-densa th.cap,
.table-densa td.cap { background: var(--surface-captura); }
.table-densa th.cap-ini,
.table-densa td.cap-ini { border-left: 1px solid var(--border-fuerte); }
.table-densa tbody tr:hover td.cap { background: #f7f5ec; }
.table-densa tbody tr:focus-within td.cap { background: #eef4fb; }

/* ── alineaciones (sin cambio respecto a hoy) ──────────────────────── */
.col-num   { text-align: right;  font-variant-numeric: tabular-nums; }
.col-cen   { text-align: center; }
.col-fecha { text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }
.col-trunc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── CONTROLES CALLADOS ────────────────────────────────────────────────
   El cambio que más se nota. Sin caja hasta que el cursor pasa por encima;
   con caja y anillo al enfocar. Quita ~600 rectángulos de la pantalla sin
   quitar un solo dato. El subrayado conserva la pista de "aquí se escribe".
   ─────────────────────────────────────────────────────────────────────── */
.table-densa select,
.table-densa input[type=text],
.table-densa input[type=date],
.table-densa textarea.pl-edit {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  height: calc(var(--ctl-h) - 6px);
  min-height: calc(var(--ctl-h) - 6px);
  margin: 0;
  padding: 0 4px;
  font-family: inherit;
  font-size: var(--fs-200);
  color: var(--text-1);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  box-shadow: inset 0 -1px 0 var(--border);
  appearance: none;
}
.table-densa select:hover,
.table-densa input[type=text]:hover,
.table-densa input[type=date]:hover,
.table-densa textarea.pl-edit:hover {
  background: var(--surface);
  border-color: var(--border);
}
.table-densa select:focus,
.table-densa input[type=text]:focus,
.table-densa input[type=date]:focus,
.table-densa textarea.pl-edit:focus {
  outline: none;
  background: var(--surface);
  border-color: var(--foco);
  box-shadow: var(--anillo);
  position: relative;
  z-index: 3;
}
/* El widget nativo de fecha no se puede estilizar del todo: solo cabe
   apretarle el padding. Ver README, sección "Límites". */
.table-densa input[type=date] { padding: 0 2px; }

/* Texto largo: una línea, y al enfocar se expande sobre la fila. */
.table-densa textarea.pl-edit {
  resize: none;
  overflow: hidden;
  line-height: var(--lh-2);
  padding: 3px 4px;
}
.table-densa textarea.pl-edit:focus,
.table-densa textarea.pl-edit.pl-expandido {
  position: absolute;
  left: 2px;
  top: 1px;
  width: 340px;
  height: 110px;
  z-index: 30;
  overflow: auto;
  resize: vertical;
  box-shadow: var(--sombra-2);
  background: var(--surface);
}

/* ── ESTADO DE GUARDADO EN LA CELDA ────────────────────────────────────
   Lo que hoy falta: la confirmación vive en la línea de resumen, a 2.000 px
   de scroll de donde están los ojos. El JS pone y quita estas clases.
   ─────────────────────────────────────────────────────────────────────── */
.pl-edit.guardando { box-shadow: inset 0 -2px 0 var(--warn-fg); }
.pl-edit.guardado  { box-shadow: inset 0 -2px 0 var(--ok-fg); }
.pl-edit.sin-guardar {
  border-color: var(--err-fg);
  background: var(--err-bg);
  box-shadow: inset 0 -2px 0 var(--err-fg);
}

/* ── MEJORA OPCIONAL, MEDIR ANTES ──────────────────────────────────────
   Acelera el pintado en tablas de 200+ renglones. Una línea, sin JS, y no
   rompe Ctrl+F. Probar en la máquina de Isabel antes de dejarla puesta.
   .table-densa tbody tr { content-visibility: auto; contain-intrinsic-size: auto 32px; }
   ─────────────────────────────────────────────────────────────────────── */

/* ── Tooltip propio ────────────────────────────────────────────────────
   El title nativo tarda ~1s y no se puede dar formato. Este aparece al
   instante y respeta saltos de linea. Se activa con data-tip="...".      */
.tip-box {
  position: fixed; z-index: 9999; max-width: 420px;
  background: #1f1e1c; color: #fff;
  padding: 7px 10px; border-radius: 6px;
  font-size: var(--fs-200); line-height: var(--lh-2);
  box-shadow: 0 6px 20px rgba(0,0,0,.28);
  pointer-events: none; white-space: pre-wrap; overflow-wrap: break-word;
}
[data-tip] { cursor: help; }
.table-densa [data-tip] input,
.table-densa [data-tip] select { cursor: auto; }

/* El textarea expandible ahora vive en el bloque de la tabla densa (fase 2). */

/* ══ BARRA DE HERRAMIENTAS ════════════════════════════════════════════
   Estandar unico de toda la plataforma. Una barra por vista, con dos zonas
   de significado que nunca se cruzan:
     izquierda (.barra-filtros)  = acotar lo que YA existe
     derecha   (.barra-acciones) = crear algo NUEVO
   No lleva boton "Filtrar": los filtros se aplican solos (ver app.js).

   La altura sale toda de --ctl-h. NUNCA escribir height en el HTML: antes
   habia hasta 4 alturas distintas en un mismo renglon porque cada vista la
   resolvia a mano (y input[type=date] no estaba en el selector global de
   abajo, asi que se quedaba con el control nativo del navegador).          */
:root { --ctl-h: 32px; }

.barra {
  display: flex; align-items: flex-end; flex-wrap: wrap;
  gap: 8px 10px; padding: 10px 12px; margin-bottom: var(--sp-4);
}
/* flex-basis 0 + min-width 0: el bloque de filtros CEDE espacio al de acciones
   en vez de reclamar su ancho natural. Sin esto, una barra con muchos campos
   (Cambios tiene 8) empujaba las acciones a un renglon propio: los campos ya
   ocupaban dos filas y "Limpiar" caia solo en una tercera.                  */
.barra-filtros {
  display: flex; align-items: flex-end; flex-wrap: wrap;
  gap: 8px 10px; flex: 1 1 0; min-width: 0; margin: 0;
}
.barra-acciones { display: flex; align-items: flex-end; gap: 8px; margin-left: auto; flex: 0 0 auto; }

/* Campo = etiqueta + control apilados. */
.barra .campo { display: flex; flex-direction: column; margin: 0; }
.barra .campo > span {
  font-size: var(--fs-100); font-weight: 600; text-transform: uppercase;
  letter-spacing: .4px; color: var(--text-2);
  margin: 0 0 3px 2px; line-height: 1;
}
.barra .campo-flex { flex: 1 1 200px; min-width: 180px; }

/* UNA sola regla de altura para input, select, date y boton por igual. */
.barra input, .barra select, .barra .btn {
  height: var(--ctl-h); min-height: var(--ctl-h);
  box-sizing: border-box; font-size: var(--fs-300); font-family: inherit; margin: 0;
}
.barra input, .barra select {
  width: 100%; padding: 2px 8px;
  border: 1px solid var(--border); border-radius: var(--r);
  background: var(--surface); color: var(--text-1); appearance: none;
}
.barra input[type=date] { width: 132px; flex: none; }
.barra select { max-width: 200px; padding-right: 22px; }
.barra .btn { padding: 0 14px; font-weight: 500; }

/* Submit accesible pero invisible: sin boton "Filtrar", es lo que hace que
   Enter siga funcionando y que la barra sirva aunque el JS no cargue.      */
.barra-submit { position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

/* Jerarquia: crear = color, secundaria = contorno, limpiar = texto. */
.btn-accion { background: var(--ok-fg); color: #fff; border-color: var(--ok-fg); }
.btn-accion:hover { background: #0c5945; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn-ghost:hover { background: var(--bg); color: var(--text-1); }

/* ══ SEMÁFORO · .sem ════════════════════════════════════════════════════
   Sustituye a los emoji 🔴🟡🟢⚫. Requiere migrar el valor guardado y el
   parámetro de URL de glifo a palabra (?sem=pendiente). Ver README.
   <span class="sem sem-pend">Pendiente</span>
   En tabla densa, solo el punto:  <span class="sem sem-pend solo" data-tip="Pendiente"></span>
   ══════════════════════════════════════════════════════════════════════ */
.sem {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--fs-100); font-weight: 600; letter-spacing: .2px; white-space: nowrap;
}
.sem::before {
  content: ''; width: 9px; height: 9px; border-radius: 50%;
  background: currentColor; flex: none;
}
.sem.solo { font-size: 0; gap: 0; }
.sem-ok   { color: var(--ok-fg); }
.sem-prog { color: var(--warn-fg); }
.sem-pend { color: var(--err-fg); }
.sem-nulo { color: var(--text-3); }
/* El punto NO hereda el color de la palabra: la palabra debe ser legible y el
   punto debe verse de lejos, y eso pide dos colores distintos. Ver los tokens. */
.sem-ok::before   { background: var(--ok-punto); }
.sem-prog::before { background: var(--warn-punto); box-shadow: var(--punto-aro); }
.sem-pend::before { background: var(--err-punto); }
/* halo: hace saltar el pendiente sin depender del color (daltonismo, B/N) */
.sem-pend::before { box-shadow: 0 0 0 3px var(--err-bg); }

/* ══ CHIPS DE FILTRO ══════════════════════════════════════════════════
   Sustituye a .fl-chips / .rq-chip / .rt-chip / .emp-chips, que eran cuatro
   copias casi iguales con tres paddings y dos tamanos de letra distintos.  */
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: var(--sp-4); }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 26px; padding: 0 12px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface);
  font-size: var(--fs-200); line-height: 1; color: var(--text-2);
  /* font-family heredada: sin esto un .chip escrito como <button> sale con la
     tipografia del navegador y no con la del sistema. Los chips que filtran
     en el cliente (Proveedores) no pueden ser <a>: no navegan a ningun lado. */
  font-family: inherit;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: border-color .12s, color .12s, background .12s;
}
.chip:hover { border-color: var(--info-fg); color: var(--info-fg); text-decoration: none; }
.chip.on { background: var(--info-fg); border-color: var(--info-fg); color: #fff; }
.chip b { font-weight: 700; font-variant-numeric: tabular-nums; }
.chip.on b { opacity: .85; }
.chip.vacio { opacity: .45; }
.chip .dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
/* Para un chip de otro eje (no del mismo grupo de estatus): lo manda a la derecha. */
/* PESTAÑAS · elegir QUÉ lista se ve. No son chips, aunque se parezcan.
   El chip filtra lo que ya está en pantalla; la pestaña cambia la pantalla.
   Mezclarlos en un solo renglón fue lo que reventó Cobranza: cuatro listas más
   siete filtros no caben en 1,172 px y se iban a tres renglones. Separarlos no
   es cosmético — son dos preguntas distintas, y ahora cada una cabe en su
   renglón. Rafael, 27-ago-2026. */
.tabs {
  display: flex; flex-wrap: wrap; gap: 2px; align-items: flex-end;
  border-bottom: 1px solid var(--border); margin-bottom: var(--sp-4);
}
.tab {
  padding: 7px 14px; border-radius: var(--radio) var(--radio) 0 0;
  border: 1px solid transparent; border-bottom: 0; margin-bottom: -1px;
  font-size: var(--fs-200); line-height: 1; color: var(--text-2);
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: color .12s, background .12s;
}
.tab:hover { color: var(--info-fg); background: var(--n-25); text-decoration: none; }
.tab.on {
  background: var(--surface); border-color: var(--border);
  color: var(--info-fg); font-weight: 600;
}
.tab b { font-weight: 700; font-variant-numeric: tabular-nums; opacity: .7; margin-left: 5px; }

.chip-aparte { margin-left: auto; }
/* Chip que señala un problema (cambios por revisar, faltantes): rojo en vez de azul. */
.chip-alerta { border-color: #fca5a5; color: var(--err-fg); }
.chip-alerta:hover { border-color: var(--err-fg); color: var(--err-fg); }
.chip-alerta.on { background: var(--err-fg); border-color: var(--err-fg); color: #fff; }

/* ══ LINEA DE RESUMEN ═════════════════════════════════════════════════
   "71 SETS florales en 29 eventos · 08/08 → 24/08". Va SIEMPRE aqui: entre
   los chips y el cuerpo, fuera de la tarjeta. Antes seis vistas la metian
   dentro del .card-header de la tabla y cuatro la dejaban fuera.
   .resumen-extra manda a la derecha lo accesorio (banner de frescura).   */
.resumen {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  font-size: var(--fs-200); color: var(--text-2); margin: -4px 0 12px 2px;
}
.resumen-extra { margin-left: auto; }

/* ══ ESTADO DE PANTALLA · .estado ═════════════════════════════════════
   Vacío, error, sin permiso, primera vez. Anatomía fija de Design:
   marca → qué pasó → por qué → qué hacer. Lo último es obligatorio: un
   "No hay resultados" a secas deja al usuario sin siguiente movimiento.

   Antes cada vista lo resolvía por su cuenta —seis vistas, seis estilos
   inline distintos, una con emoji y Órdenes con la tabla vacía y ningún
   texto—. Se emite con estado_vacio() (config/app.php).             */
.estado {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--sp-2); padding: var(--sp-12) var(--sp-6);
  color: var(--text-2); font-size: var(--fs-300);
}
.estado-marca {
  width: 40px; height: 40px; border-radius: var(--r); flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--mut-bg); color: var(--text-3);
  font-size: 18px; margin-bottom: var(--sp-1);
}
.estado-titulo { font-size: var(--fs-400); font-weight: 600; color: var(--text-1); }
.estado-texto  { max-width: 46ch; line-height: var(--lh-2); }
.estado-acciones { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); flex-wrap: wrap; justify-content: center; }
.estado-err     .estado-marca { background: var(--err-bg);  color: var(--err-fg);  }
.estado-permiso .estado-marca { background: var(--warn-bg); color: var(--warn-fg); }
.estado-primera .estado-marca { background: var(--info-bg); color: var(--info-fg); }

/* ══ MOLDE B · TABLA DE REGISTROS ═════════════════════════════════════
   Una fila = un documento (folio, estatus, acciones). El ANCHO de columna
   se sigue poniendo inline porque es propio de cada vista; padding,
   tipografia y color salen de aqui. Antes habia 38 <th style> y 44
   <td style> que ademas del ancho cambiaban densidad y tamano de letra,
   y por eso ninguna tabla se parecia a otra.                             */
.tabla th { padding: var(--sp-2) .625rem; font-size: var(--fs-100); }
.tabla td { padding: .55rem .625rem; font-size: var(--fs-200); vertical-align: middle; }
.tabla .col-num { text-align: right; font-variant-numeric: tabular-nums; }
.tabla .col-mid { text-align: center; }
.tabla .folio   { font-family: monospace; font-weight: 700; color: var(--info-fg); font-size: var(--fs-200); }
.tabla .sub     { font-size: var(--fs-100); color: var(--text-2); }
/* La tarjeta que envuelve una tabla no lleva padding: si no, el encabezado
   gris queda flotando en medio del blanco (se veia en Ordenes de Renta).  */
/* overflow:clip, no hidden. Los dos recortan igual (la tabla respeta la esquina
   redondeada), pero hidden convierte la tarjeta en contenedor de scroll y eso
   ancla ahi el position:sticky del encabezado, que entonces deja de pegarse a
   la ventana. clip no crea contenedor. */
.card-tabla { padding: 0; overflow: clip; }

/* Un encabezado DENTRO de una tarjeta-tabla tiene que reponer el padding que
   .card-tabla quita. Sin esto el título queda pegado al filo de la tarjeta por
   arriba y a la primera fila de la tabla por abajo, y se lee como si fuera parte
   del encabezado gris en vez de un título. El padding-bottom es menor que el de
   arriba a propósito: la línea divisoria ya separa, y repetir el mismo valor
   arriba y abajo hace ver el bloque desbalanceado. */
.card-tabla > .card-header {
  padding: var(--sp-4) var(--sp-6) var(--sp-3);
  margin-bottom: 0;
}

/* ══ MOLDE A · TARJETA DE EVENTO ══════════════════════════════════════
   Lista agrupada por evento con sub-filas desplegables. Estas clases
   sustituyen a los ~10 estilos inline que estaban duplicados literalmente
   entre Solicitudes Florales y Solicitudes de Rentas.                    */
.ev { margin-bottom: var(--sp-2); }
.ev-cab { display: flex; gap: var(--sp-4); align-items: center; cursor: pointer; user-select: none; }
/* El color va en el contenedor y lo heredan punto y etiqueta. Antes la
   etiqueta lo pedia inline con var(--c-rojo/-amarillo/-verde/-gris), tokens
   que nunca se definieron: los dias a la entrega salian del color heredado y
   el semaforo lo daba solo el punto. */
.ev-sem { width: 28px; text-align: center; flex-shrink: 0; }
.ev-sem small { display: block; font-size: var(--fs-100); margin-top: 1px; }
.ev-sem .dot { background: currentColor; }
.ev-txt { flex: 1; min-width: 0; }
.ev-l1 { display: flex; gap: var(--sp-2); align-items: baseline; flex-wrap: wrap; }
.ev-cod { font-weight: 700; font-size: var(--fs-400); }
.ev-folio { font-size: var(--fs-100); color: var(--text-3); }
.ev-nom { font-size: var(--fs-300); font-weight: 500; }
.ev-meta { font-size: var(--fs-100); color: var(--text-2); }
.ev-tags { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }
.ev-flecha { width: 16px; text-align: center; color: var(--text-3); font-size: var(--fs-100);
             flex-shrink: 0; transition: transform .15s; }
/* Desplegado por CLASE en la tarjeta, no por style inline: una sola linea de JS
   (classList.toggle) en vez de manipular display y transform a mano.          */
.ev-cuerpo { display: none; margin-top: var(--sp-3); border-top: 1px solid var(--border); padding-top: .625rem; }
.ev.abierto .ev-cuerpo { display: block; }
.ev.abierto .ev-flecha { transform: rotate(90deg); }

/* El bloque .filtros legado se retiro en la fase 3: sus !important de
   altura y tamano de letra hacian inmunes a los tokens de densidad a
   cualquier vista que lo usara. Ninguna lo usa desde el 08-ago-2026. */

/* ── Contador de semaforo ──────────────────────────────────────────────
   Resume, sobre lo filtrado, cuantos registros hay en cada color.        */
/* Los chips de semaforo y de revision de Planeacion pasaron al componente
   estandar .chip. Aqui solo queda lo suyo: el contador del boton .dw-abrir,
   que NO es un chip de filtro (abre el drawer de cambios).                  */

/* ── Drawer lateral ────────────────────────────────────────────────────
   Panel que entra desde la derecha. Componente global: se abre con
   cualquier elemento que lleve data-drawer-url (y opcionalmente
   data-drawer-titulo). El contenido se pide por AJAX al abrirlo.        */
.dw-fondo {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(26,26,24,.35);
  /* pointer-events es OBLIGATORIO, no adorno: con solo opacity:0 el fondo
     sigue existiendo a pantalla completa en z-index 1000 y se traga TODOS
     los clics de la pagina despues de cerrar el drawer. */
  opacity: 0; pointer-events: none;
  transition: opacity .18s ease;
}
.dw-fondo.abierto { opacity: 1; pointer-events: auto; }

.dw-panel {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 1001;
  width: min(560px, 100vw);
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -8px 0 28px rgba(0,0,0,.18);
  display: flex; flex-direction: column;
  transform: translateX(100%);
  transition: transform .22s ease;
}
.dw-panel.abierto { transform: translateX(0); }
.dw-panel.dw-ancho { width: min(1120px, 100vw); }

/* visibility se controla desde JS con un temporizador, NO con la transicion:
   si la pestana esta en segundo plano el navegador congela las transiciones y
   el panel se quedaria encima del contenido. Un setTimeout siempre corre. */
.dw-fondo.dw-oculto,
.dw-panel.dw-oculto { visibility: hidden; }

.dw-panel > header {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
  background: var(--bg);
}
.dw-panel > header h3 { font-size: var(--fs-400); font-weight: 700; flex: 1; }
.dw-cerrar {
  border: 1px solid var(--border); background: var(--surface);
  border-radius: var(--r); width: 28px; height: 28px;
  font-size: var(--fs-500); line-height: 1; cursor: pointer; color: var(--text-2);
}
.dw-cerrar:hover { color: var(--text-1); }
.dw-ep {
  border: 1px solid var(--border); background: var(--surface);
  border-radius: var(--r); height: 28px; padding: 0 10px;
  display: inline-flex; align-items: center; gap: 4px;
  font-size: var(--fs-200); font-weight: 600; color: var(--info-fg);
  text-decoration: none; white-space: nowrap; cursor: pointer;
}
.dw-ep:hover { background: var(--bg); }
.dw-ep[hidden] { display: none; }

.dw-cuerpo { flex: 1; overflow-y: auto; padding: 10px 14px 20px; }
.dw-vacio  { padding: 20px 2px; color: var(--text-2); font-size: var(--fs-300); }

/* Cada cambio es un bloque, no un renglon de tabla: en 560px de ancho una
   tabla de 8 columnas se vuelve ilegible. */
.dw-cambio {
  border: 1px solid var(--border); border-radius: var(--r);
  padding: 9px 11px; margin-top: 9px; background: var(--surface);
}
.dw-cambio.dw-ok { opacity: .5; }
.dw-cambio.dw-ok:hover { opacity: 1; }

.dw-cab { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.dw-check { display: flex; align-items: center; cursor: pointer; }
.dw-op    { font-weight: 700; font-size: var(--fs-300); }
.dw-meta  { margin-left: auto; font-size: var(--fs-100); color: var(--text-2); font-variant-numeric: tabular-nums; }

.dw-valores { margin-top: 7px; font-size: var(--fs-200); line-height: var(--lh-2); }
.dw-antes, .dw-despues {
  white-space: pre-wrap; overflow-wrap: break-word;
  padding: 5px 8px; border-radius: 6px; margin-top: 4px;
}
.dw-antes   { background: var(--err-bg);   color: var(--text-2); }
.dw-despues { background: var(--ok-bg); font-weight: 600; }
.dw-et {
  display: block; font-size: var(--fs-100); letter-spacing: .5px;
  text-transform: uppercase; opacity: .65; font-weight: 700;
}

.dw-nota {
  width: 100%; margin-top: 7px; padding: 5px 7px;
  font-family: inherit; font-size: var(--fs-200); line-height: var(--lh-2);
  border: 1px solid var(--border); border-radius: 6px;
  resize: vertical; min-height: 30px;
}

/* Chip que abre el drawer desde el encabezado de un evento. */
.dw-abrir {
  display: inline-flex; align-items: center; gap: 5px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--text-1);
  padding: 1px 9px; font-size: var(--fs-100); line-height: var(--lh-3);
  cursor: pointer; font-family: inherit;
}
.dw-abrir:hover { background: var(--info-bg); border-color: var(--info-fg); text-decoration: none; }
.dw-abrir .n { font-weight: 700; font-variant-numeric: tabular-nums; }
/* Con pendientes resalta; sin pendientes queda discreto pero accesible. */
.dw-abrir.hay { border-color: var(--warn-fg); background: var(--warn-bg); color: var(--warn-fg); }
.dw-abrir.sin { opacity: .5; }

/* ── Banner de frescura de datos ───────────────────────────────────────
   Master lee una COPIA diaria de EasyPlanner, no EP en vivo. El banner
   dice la antiguedad del DATO, no la de nuestro sync. En alerta cuando la
   copia diaria parece haber fallado: quedarse con datos viejos en silencio
   es el peor modo de falla de esta herramienta.                          */
.pl-frescura { white-space: nowrap; }
.pl-frescura strong { font-weight: 700; }
.pl-frescura.alerta {
  color: var(--warn-fg); background: var(--warn-bg);
  padding: 1px 7px; border-radius: 999px; font-weight: 600;
}

/* ── Tarjeta de detalle dentro del drawer ──────────────────────────────
   Replica el Detalle de SET de Solicitudes Florales. Bloques y no tabla:
   en 560px de ancho una tabla no se lee.                                */
.dt-cab { display:flex; gap:12px; align-items:flex-start; }
.dt-foto {
  width:82px; height:82px; flex:none; border-radius:var(--r);
  object-fit:cover; border:1px dashed var(--border); background:var(--bg);
}
.dt-sinfoto {
  display:flex; align-items:center; justify-content:center;
  font-size: var(--fs-100); color:var(--text-3); text-align:center; line-height: var(--lh-1);
}
.dt-cab-txt { min-width:0; }
.dt-linea1  { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.dt-id      { font-size: var(--fs-200); color:var(--text-3); font-variant-numeric:tabular-nums; }
.dt-sem     { font-size: var(--fs-400); }
.dt-titulo  { font-size: var(--fs-500); font-weight:700; line-height: var(--lh-1); margin:5px 0 4px; }
.dt-sub     { font-size: var(--fs-200); color:var(--text-2); line-height: var(--lh-2); }

.dt-caja {
  margin-top:10px; padding:9px 11px; border-radius:var(--r);
  background:var(--bg); border:1px solid var(--border);
  font-size: var(--fs-200); line-height:1.55; overflow-wrap:break-word;
}
.dt-aviso { background:var(--warn-bg); border-color:transparent; color:var(--warn-fg); }

/* Los datos duros en dos columnas: se leen de un golpe sin ocupar alto. */
.dt-datos {
  display:grid; grid-template-columns:1fr 1fr; gap:7px 14px; margin-top:12px;
  font-size: var(--fs-200);
}
.dt-datos div    { display:flex; justify-content:space-between; gap:8px;
                   border-bottom:1px solid var(--border); padding-bottom:4px; }
.dt-datos span   { color:var(--text-2); }
.dt-datos strong { text-align:right; }

.dt-cambios {
  display:block; margin-top:12px; padding:8px 11px; border-radius:var(--r);
  background:var(--info-bg); color:var(--info-fg); font-size: var(--fs-200); font-weight:600;
}
.dt-cambios:hover { text-decoration:none; filter:brightness(.97); }

.dt-captura { margin-top:16px; border-top:1px solid var(--border); padding-top:12px; }
.dt-captura h5 {
  font-size: var(--fs-100); text-transform:uppercase; letter-spacing:.5px;
  color:var(--text-2); margin-bottom:9px;
}
.dt-captura label {
  display:block; margin-bottom:9px; font-size: var(--fs-100); color:var(--text-2);
}
.dt-captura select,
.dt-captura input,
.dt-captura textarea {
  display:block; width:100%; margin-top:3px; padding:6px 8px;
  font-family:inherit; font-size: var(--fs-300); color:var(--text-1);
  border:1px solid var(--border); border-radius:6px; background:var(--surface);
}
.dt-captura textarea { resize:vertical; line-height: var(--lh-2); }
.dt-dos { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.dt-pie { font-size: var(--fs-100); color:var(--text-3); margin-top:2px; }

/* Etiqueta de cada bloque de texto del detalle: sin ella, descripcion y
   comentarios internos se veian como dos parrafos sueltos sin saber cual era
   cual. */
.dt-et {
  display:block; font-size: var(--fs-100); letter-spacing:.5px; text-transform:uppercase;
  font-weight:700; opacity:.6; margin-bottom:3px;
}
.dt-foto { display:block; }
a:has(> .dt-foto):hover .dt-foto { filter:brightness(.92); }

/* ── Stepper de fases de Flores ────────────────────────────────────────
   Tira compacta de N fases por evento. Verde = completa, azul = fase
   actual (la primera sin terminar), gris = pendiente.                    */
.fl-stepper { display:flex; align-items:flex-start; gap:0; margin-top: var(--sp-2); }
.fl-paso { flex:1; display:flex; flex-direction:column; align-items:center; position:relative; min-width:0; }
.fl-paso .bola {
  width:22px; height:22px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; font-size: var(--fs-100); font-weight:700; z-index:1;
  background:var(--border); color:var(--text-2); border:2px solid var(--border);
}
.fl-paso .txt { font-size: var(--fs-100); color:var(--text-2); margin-top:3px; text-align:center; line-height: var(--lh-1); max-width:90px; }
/* La linea que une una bola con la siguiente. */
.fl-paso:not(:last-child)::after {
  content:''; position:absolute; top:11px; left:50%; width:100%; height:2px;
  background:var(--border); z-index:0;
}
.fl-paso.ok    .bola { background:var(--ok-fg); border-color:var(--ok-fg); color:#fff; }
.fl-paso.ok::after   { background:var(--ok-fg); }
.fl-paso.ok    .txt  { color:var(--ok-fg); }
.fl-paso.actual .bola{ background:var(--info-fg); border-color:var(--info-fg); color:#fff; }
.fl-paso.actual .txt { color:var(--info-fg); font-weight:700; }

/* Detalle de la Fase 1 (checklist derivado) en el evento expandido. */
.fl-f1 { display:flex; flex-wrap:wrap; gap: var(--sp-2) 1.25rem; font-size: var(--fs-200); margin-bottom: var(--sp-3); }
.fl-f1 span { display:inline-flex; align-items:center; gap:.35rem; }
.fl-f1 .si { color:var(--ok-fg); }
.fl-f1 .no { color:var(--err-fg); }

/* ── Drawer de fases de evento (Flores) ────────────────────────────────*/
.fe-fase { margin-top: var(--sp-4); border-top:1px solid var(--border); padding-top: var(--sp-3); }
.fe-fase h5 {
  font-size: var(--fs-200); font-weight:700; margin-bottom:.6rem;
  display:flex; align-items:center; gap: var(--sp-2);
}
.fe-auto { font-size: var(--fs-100); font-weight:500; text-transform:uppercase; letter-spacing:.4px;
           color:var(--text-2); background:var(--bg); padding:1px 6px; border-radius:999px; }
.fe-check { display:flex; align-items:center; gap:.4rem; font-size: var(--fs-300); margin-bottom:.35rem; cursor:pointer; }
.fe-comp {
  margin-top: var(--sp-2); padding:6px 9px; border-radius:6px; font-size: var(--fs-200);
  background:var(--bg); color:var(--text-2);
}
.fe-comp.bien { background:var(--ok-bg); color:var(--ok-fg); font-weight:600; }
.fe-comp.mal  { background:var(--err-bg);   color:var(--err-fg);   font-weight:600; }
.fe-sets { width:100%; font-size: var(--fs-200); border-collapse:collapse; }
.fe-sets td { padding:5px 4px; border-bottom:1px solid var(--border); vertical-align:middle; }
.fe-sets tr:hover td { background:var(--bg); }

/* ── Drawer abierto como PÁGINA ────────────────────────────────────────
   El mismo fragmento sirve de panel y de página (ver views/_drawer.php).
   Cuando se abre por URL directa —sin JS, o porque alguien compartió el
   enlace— se envuelve aquí para que no quede pegado al borde. */
.dw-pagina { max-width: 720px; }
.dw-volver { display: inline-block; font-size: var(--fs-200); color: var(--text-2);
             margin-bottom: var(--sp-3); }
.dw-volver:hover { color: var(--text-1); }

/* Stepper compacto: el que vive en la cabecera del evento.
   Dos cosas que costaron un intento: las etiquetas SI van —sin ellas no se
   sabe que es cada paso— pero en UNA linea, porque "Recepcion de flor" en dos
   renglones se encimaba con "Produccion"; y el ancho es FIJO, igual que el de
   los badges de al lado, porque si no cada tarjeta ponia sus circulos en una x
   distinta segun lo largo que fuera su badge ("2 cambios" vs "20 cambios"). */
.fl-stepper.compacto { flex: none; width: 240px; margin: 0; align-items: flex-start; }
.fl-stepper.compacto .fl-paso .bola { width: 18px; height: 18px; font-size: 10px; }
.fl-stepper.compacto .fl-paso .txt {
  font-size: 9.5px; margin-top: 2px; max-width: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 100%;
}
.fl-stepper.compacto .fl-paso:not(:last-child)::after { top: 9px; }
/* Columnas de ancho fijo a la derecha: lo unico que hace que los circulos de
   todas las tarjetas caigan en la misma vertical. */
.ev-tags { min-width: 250px; justify-content: flex-end; }


/* ══ MOLDE D2 · ARMAZÓN DE DRAWER (Design, ago-2026) ═══════════════════
   Sustituye a .dt-* de a poco: un drawer por vez, empezando por Empalmes.
   Mientras dure la migración conviven; cuando los cuatro estén, .dt-* se va.

   Las cuatro reglas que trae, y que son la razón de existir del armazón:
     1. Una franja arriba dice QUÉ SIGUE. El drawer se abre para hacer algo,
        no para leer.
     2. Lo editable va sobre --surface-captura. De un vistazo se sabe qué se
        puede escribir y qué llega del CRM.
     3. Lo excepcional va plegado. Daños, incidencias, cancelar: existen,
        pero no ocupan pantalla mientras no pasen.
     4. Un aviso permanente no es un aviso. Tres banners en cada apertura
        enseñan a saltárselos todos, incluido el que importaba.

   --dr-lado es el margen lateral del contenedor. Se declara en los dos
   contextos donde vive un fragmento —dentro del panel y como página
   suelta— para que lo que sangra a los bordes calcule igual en ambos.  */
.dw-cuerpo  { --dr-lado: 14px; }
.dw-pagina  { --dr-lado: 0px; }

.dr-sig {
  display: flex; align-items: flex-start; gap: 11px;
  margin: -10px calc(-1 * var(--dr-lado)) 0;
  padding: 13px 16px;
  background: var(--info-bg); border-bottom: 1px solid var(--info-bd);
}
.dr-sig.alerta { background: var(--err-bg);  border-bottom-color: var(--err-bd); }
.dr-sig.aviso  { background: var(--warn-bg); border-bottom-color: var(--warn-bd); }
/* Design trajo tres tonos —azul informa, ámbar avisa, rojo bloquea—. Falta
   uno: el de "ya no hay nada que hacer aquí". Sin él, un empalme resuelto
   seguiría abriendo en rojo, que es justo la Regla 4 al revés. */
.dr-sig.ok     { background: var(--ok-bg);   border-bottom-color: var(--ok-bd); }
.dr-sig .t { display: block; font-size: var(--fs-300); font-weight: 700; color: var(--info-fg); line-height: 1.35; }
.dr-sig.alerta .t { color: var(--err-fg); }
.dr-sig.aviso  .t { color: var(--warn-fg); }
.dr-sig.ok     .t { color: var(--ok-fg); }
.dr-sig .s { display: block; font-size: var(--fs-200); color: var(--text-2); line-height: 1.45; margin-top: 2px; }
.dr-sig .ic { font-size: 14px; margin-top: 1px; flex: none; }

.dr-bloque { padding: 16px 0; border-bottom: 1px solid var(--border); }
.dr-bloque:last-child { border-bottom: none; padding-bottom: 0; }
.dr-tit {
  display: flex; align-items: baseline; gap: 8px;
  font-size: var(--fs-100); font-weight: 700; text-transform: uppercase;
  letter-spacing: .7px; color: var(--text-2); margin-bottom: 10px;
}
.dr-tit .ay { font-weight: 400; letter-spacing: 0; text-transform: none;
              font-size: var(--fs-200); color: var(--text-3); }

/* Regla 2: el bloque de captura sangra a los bordes y va en crema. */
.dr-cap {
  background: var(--surface-captura);
  margin: 0 calc(-1 * var(--dr-lado)); padding: 16px;
}
.dr-datos { display: grid; grid-template-columns: 1fr 1fr; gap: 7px 18px; font-size: var(--fs-200); }
.dr-datos > div { display: flex; justify-content: space-between; gap: 8px;
                  border-bottom: 1px solid var(--border-sutil); padding-bottom: 5px; }
.dr-datos span   { color: var(--text-2); }
.dr-datos strong { text-align: right; }

/* Renglón de totales: concepto a la izquierda, importe a la derecha. */
.dr-tot { display: flex; justify-content: space-between; gap: 12px;
          font-size: var(--fs-200); color: var(--text-2); padding: 4px 0;
          font-variant-numeric: tabular-nums; }
.dr-tot.fin { border-top: 1.5px solid var(--text-1); margin-top: 4px; padding-top: 7px;
              font-size: var(--fs-400); font-weight: 700; color: var(--text-1); }

/* Regla 3: <details> nativo otra vez — pliega sin JS. */
.dr-plegado { border: 1px dashed var(--border-fuerte); border-radius: var(--r); background: var(--surface); }
.dr-plegado > summary {
  display: flex; align-items: center; gap: 9px; padding: 11px 13px;
  font-size: var(--fs-300); color: var(--text-2); cursor: pointer; list-style: none;
}
.dr-plegado > summary::-webkit-details-marker { display: none; }
.dr-plegado > summary::before { content: '＋'; font-size: 13px; color: var(--text-3); flex: none; }
.dr-plegado[open] > summary::before { content: '−'; }
.dr-plegado > summary:hover { color: var(--text-1); }
.dr-plegado > summary .col { margin-left: auto; font-size: var(--fs-200); color: var(--text-3); }
.dr-plegado .dr-cuerpo { padding: 0 13px 13px; font-size: var(--fs-200); color: var(--text-2); line-height: 1.5; }
.dr-plegado.riesgo > summary { color: var(--err-fg); }
.dr-plegado.riesgo { border-color: var(--err-bd); }

/* Cita atribuida: para lo que dice EasyPlanner. Antes era una caja de alarma
   ámbar, y como sale en TODOS los registros, alarmar dejaba de informar. */
.dr-cita { border-left: 3px solid var(--border-fuerte); padding: 2px 0 2px 12px;
           font-size: var(--fs-300); line-height: 1.55; color: var(--text-1); }
.dr-cita.info { border-left-color: var(--info-bd); color: var(--text-2); font-size: var(--fs-200); }
.dr-cita .f { display: block; font-size: var(--fs-100); text-transform: uppercase;
              letter-spacing: .5px; color: var(--text-3); font-weight: 700; margin-bottom: 3px; }

.dr-pie {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 16px calc(-1 * var(--dr-lado)) calc(-1 * var(--dr-lado));
  padding: 12px 16px; border-top: 1px solid var(--border); background: var(--bg);
}
.dr-pie .meta { font-size: var(--fs-200); color: var(--text-3); line-height: 1.4; }


/* ══ EMPALMES · BARRA DE CAPACIDAD ════════════════════════════════════
   Enseña la aritmética. Los eventos se acumulan contra la línea de lo
   disponible, así que dónde se rompe y quién queda fuera se ven de un
   golpe. Antes el veredicto era una etiqueta chiquita en la esquina
   derecha de cada renglón, cuando es la respuesta entera — y lo que
   Isabel tiene que defender frente a la vendedora que se queda sin
   producto.                                                            */
.cap-marco { position: relative; padding-top: 18px; }
.cap-barra { display: flex; height: 38px; border-radius: var(--r-sm);
             border: 1px solid var(--border); background: var(--bg); }
.cap-seg {
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-200); font-weight: 700; color: #fff; min-width: 0;
  border-right: 1px solid rgba(255,255,255,.35); overflow: hidden;
}
.cap-seg:first-child { border-radius: 5px 0 0 5px; }
.cap-seg:last-child  { border-radius: 0 5px 5px 0; border-right: none; }
/* El showroom cuenta contra la capacidad igual que un evento, pero no es un
   evento: es exhibición. Rayarlo lo distingue sin sacarlo de la cuenta. */
.cap-seg.show {
  background-image: repeating-linear-gradient(135deg,
    rgba(255,255,255,.28) 0 5px, transparent 5px 10px);
}
/* La línea del corte puede caer DENTRO de un segmento: un evento se cubre a
   medias. Design lo dibujó con el corte justo entre dos, que es el caso
   limpio; en los datos reales casi nunca lo es, y partir el segmento por la
   mitad es justamente lo que hay que ver. */
.cap-corte { position: absolute; top: 13px; height: 50px; width: 2px;
             background: var(--err-fg); pointer-events: none; }
.cap-corte::after {
  content: attr(data-limite); position: absolute; top: -14px; left: 50%;
  transform: translateX(-50%); font-size: 9.5px; font-weight: 700;
  color: var(--err-fg); white-space: nowrap; letter-spacing: .3px;
}
/* En los extremos la etiqueta centrada se sale del marco: con disponible 0 el
   corte cae en 0% y "límite 0" quedaba cortado. Ahí se ancla al lado. */
.cap-corte.izq::after { left: 0;    transform: none; }
.cap-corte.der::after { left: auto; right: 0; transform: none; }
.cap-pie { display: flex; justify-content: space-between; gap: 10px;
           font-size: var(--fs-100); color: var(--text-3); margin-top: 6px; }
/* En el panel de 560 px los nombres largos parten en dos renglones y los dos
   lados se encabalgan. Se corta el de la izquierda, que es el accesorio;
   quién queda fuera se lee entero siempre. */
.cap-pie > :first-child { min-width: 0; overflow: hidden;
                          text-overflow: ellipsis; white-space: nowrap; }
.cap-pie .fuera { color: var(--err-fg); font-weight: 600; flex: none; }

/* Renglón de prioridad. El acumulado bajo la cantidad es lo que convierte el
   corte en una cuenta que se sigue con el dedo. */
.ev-ap { display: flex; gap: 11px; align-items: flex-start; padding: 11px 12px;
         border: 1px solid var(--border); border-radius: var(--r);
         background: var(--surface); margin-bottom: 7px; }
.ev-ap.manda { border-color: var(--ok-bd);  background: #fbfefd; }
.ev-ap.sobra { border-color: var(--err-bd); background: var(--err-bg); }
.ev-ord { width: 22px; height: 22px; border-radius: 50%; flex: none;
          display: flex; align-items: center; justify-content: center;
          font-size: var(--fs-100); font-weight: 700;
          background: var(--n-100); color: var(--text-2); }
.ev-ap.manda .ev-ord { background: var(--ok-fg);  color: #fff; }
.ev-ap.sobra .ev-ord { background: var(--err-fg); color: #fff; }
.ev-in { flex: 1; min-width: 0; }
.ev-nm { display: block; font-size: var(--fs-300); font-weight: 700; line-height: 1.25; }
.ev-mt { display: block; font-size: var(--fs-200); color: var(--text-2); margin-top: 2px; line-height: 1.45; }
.ev-mono { font-family: var(--fuente-num); }
.ev-u  { flex: none; text-align: right; }
.ev-u .u  { display: block; font-size: var(--fs-500); font-weight: 700;
            font-variant-numeric: tabular-nums; line-height: 1.1; }
.ev-u .ac { display: block; font-size: 10px; color: var(--text-3);
            font-variant-numeric: tabular-nums; margin-top: 1px; }


/* ══ HITOS · línea de tiempo de una orden ═════════════════════════════
   Design los propuso para la Orden de Renta y sirven igual para las
   fases de Flores, así que van al sistema y no a la vista.

   La idea que los hace valer: la fecha PROGRAMADA va a la izquierda y no
   cambia; la REAL va a la derecha y se escribe al marcar. Antes el campo
   venía precargado con la programada, así que viendo "31/07" no había
   forma de saber si eso ya pasó o si nadie lo ha tocado — y el retraso,
   que es lo único que importa mirar, no se veía por ningún lado.       */
.hito { display: flex; gap: 11px; align-items: flex-start; padding: 9px 0; }
.hito + .hito { border-top: 1px solid var(--border-sutil); }
.hito-b {
  width: 20px; height: 20px; border-radius: 50%; flex: none; margin-top: 2px;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700;
  background: var(--surface); border: 2px solid var(--n-300); color: var(--text-3);
}
.hito.ok  .hito-b { background: var(--ok-fg); border-color: var(--ok-fg); color: #fff; }
.hito.hoy .hito-b { border-color: var(--info-fg); color: var(--info-fg);
                    box-shadow: 0 0 0 3px var(--info-bg); }
.hito-t { flex: 1; min-width: 0; }
.hito-n { display: block; font-size: var(--fs-300); font-weight: 600; line-height: 1.3; }
.hito-p { display: block; font-size: var(--fs-200); color: var(--text-2); margin-top: 1px; }
.hito-p .tarde { color: var(--err-fg); font-weight: 600; }
.hito-a { display: flex; align-items: center; gap: 8px; flex: none; }
.hito-a input[type="date"] {
  height: 30px; width: 122px; padding: 0 8px; font-size: var(--fs-200);
  font-variant-numeric: tabular-nums;
}
/* Sin marcar, la fecha real se ve como hueco por llenar, no como dato. */
.hito:not(.ok) .hito-a input[type="date"] { border-style: dashed; color: var(--text-3); }

/* Casilla del hito: dice "ya ocurrió", no "yo lo autorizo". */
.chk { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-200);
       color: var(--text-2); white-space: nowrap; cursor: pointer; margin: 0; }
.chk input { width: auto; margin: 0; }
.hito.ok .chk { color: var(--ok-fg); font-weight: 600; }


/* ══ TIRA DE HERMANOS · los otros SETs del mismo evento ═══════════════
   El problema que resuelve no es de estilo sino de navegación: un evento
   trae SET FLORAL, SET FLORAL, SET FLORAL… (483 eventos tienen el mismo
   producto repetido) y quien abre uno no tiene forma de saber cuál es ni
   en qué se diferencia del de al lado. Con la tira se salta de uno a
   otro sin cerrar el panel, y de un vistazo se ve cuál falta.          */
.hermanos { display: flex; gap: 7px; overflow-x: auto; padding-bottom: 4px; }
.herm {
  width: 92px; flex: none; border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 6px; background: var(--surface); color: inherit; text-decoration: none;
}
.herm:hover { border-color: var(--border-fuerte); text-decoration: none; }
.herm.act { border-color: var(--n-900); border-width: 2px; padding: 5px; }
.herm .mi {
  height: 52px; border-radius: 4px; border: 1px dashed var(--border-fuerte);
  background: var(--bg); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  font-size: 8.5px; color: var(--text-3); text-align: center;
}
.herm .mi img { width: 100%; height: 100%; object-fit: cover; display: block; }
.herm .nm { display: block; font-size: 10px; font-weight: 600; line-height: 1.25;
            margin-top: 5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Sin receta el SET no tiene nombre propio: se muestra lo que hay (la
   descripción de EP recortada) en cursiva, para que se lea como "provisional"
   y no como un nombre que alguien eligió. */
.herm .nm.provisional { font-weight: 400; font-style: italic; color: var(--text-2); }
.herm .st { display: block; font-size: 9.5px; margin-top: 2px; }

/* Foto grande: es lo único que de verdad distingue un SET FLORAL de otro. */
.dt-foto-xl {
  width: 150px; height: 150px; flex: none; border-radius: var(--r);
  border: 1px solid var(--border); object-fit: cover; display: block; background: var(--bg);
}
.dt-foto-xl.sin { display: flex; align-items: center; justify-content: center;
                  border-style: dashed; color: var(--text-3); font-size: var(--fs-100); text-align: center; }


/* ══ PRODUCCIÓN FLORAL · pieza y fichas de flor ═══════════════════════
   La pantalla se ordena como el trabajo real: primero se retira de cámara
   fría UNA vez (es el primer movimiento físico del día) y después se arma
   pieza por pieza. Antes la lista de cámara fría iba al final y las flores
   de cada SET en un acordeón, así que el florista veía las mismas flores
   dos veces y ninguna al abrir.                                        */
.pieza { border: 1px solid var(--border); border-radius: var(--r-lg);
         background: var(--surface); margin-bottom: var(--sp-2); overflow: hidden; }
.pieza.lista { border-color: var(--ok-bd); background: #fbfefd; }
.pieza.nula  { opacity: .55; }
.pieza-cab { display: flex; gap: 12px; padding: 12px 13px; align-items: flex-start; }
.pieza-fo { width: 66px; height: 66px; flex: none; border-radius: var(--r);
            border: 1px solid var(--border); object-fit: cover; background: var(--bg); cursor: zoom-in; }
.pieza-fo.sin { border-style: dashed; cursor: default;
                display: flex; align-items: center; justify-content: center;
                font-size: 8.5px; color: var(--text-3); text-align: center; }
.pieza-t { flex: 1; min-width: 0; }
.pieza-n { display: block; font-size: var(--fs-300); font-weight: 700; line-height: 1.3; }
.pieza-d { display: block; font-size: var(--fs-200); color: var(--text-1); line-height: 1.45; margin-top: 3px; }
.pieza-c { display: block; font-size: var(--fs-200); color: var(--text-2); line-height: 1.45; margin-top: 3px; }
.pieza-pie { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
             padding: 9px 13px; border-top: 1px solid var(--border-sutil); background: var(--bg); }

/* Las flores de la pieza, en línea. En acordeón había que abrir cada SET
   para saber qué lleva, que es justo lo que el florista viene a ver. */
.fichas { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.ficha { display: inline-flex; align-items: baseline; gap: 5px;
         padding: 2px 8px; border-radius: var(--r-full);
         background: var(--n-100); font-size: var(--fs-100); white-space: nowrap; }
.ficha b { font-variant-numeric: tabular-nums; }
.ficha .cod { color: var(--text-3); font-family: var(--fuente-num); font-size: 9px; }

/* Barra de avance de la producción del evento. */
.avance { display: flex; align-items: center; gap: 12px; }
.avance .barra { flex: 1; height: 8px; border-radius: var(--r-full);
                 background: var(--n-200); overflow: hidden; }
.avance .barra > i { display: block; height: 100%; background: var(--ok-fg); }
.avance .n { font-size: var(--fs-300); font-weight: 700;
             font-variant-numeric: tabular-nums; white-space: nowrap; }


/* ══ MOLDE E-GRANDE · formulario de pantalla completa ═════════════════
   Para un DOCUMENTO con renglones anidados y un total: editar receta hoy,
   y mañana crear orden de renta con partidas, requisición manual y lo que
   traiga Compras. La regla para elegir molde no es el largo del formulario
   sino el anidamiento: si no hay renglones dentro de renglones, va el
   molde E de una columna.

   Contenido + panel fijo de 330 px. El panel sustituye al "carrito": no
   era un carrito, era el resumen de la receta y el botón de cerrarla, y la
   metáfora de tienda hacía que un botón flotante compitiera con todo,
   tapara contenido y que nadie entendiera que ahí se finaliza el trabajo.

   Todo es CSS plano —sticky y <details>—, así que funciona sin JS.      */

/* Cabecera fija: en qué etapa va y si se guardó. Nunca al pie, que es
   justo donde nadie mira mientras captura. */
.fbar {
  position: sticky; top: var(--h-topbar); z-index: 30;
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  margin: calc(-1 * var(--sp-4)) calc(-1 * var(--sp-4)) var(--sp-4);
  padding: 10px var(--sp-4);
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.fbar .folio { font-family: var(--fuente-num); font-weight: 700; font-size: var(--fs-400); }
.fbar .guardado { font-size: var(--fs-200); color: var(--text-2); }
.fbar .der { margin-left: auto; display: flex; gap: var(--sp-2); align-items: center; }

/* El ciclo completo, no solo la etapa actual. */
.ciclo { display: flex; align-items: center; gap: 5px; font-size: var(--fs-100); }
.ciclo .p {
  padding: 2px 9px; border-radius: var(--r-full); white-space: nowrap;
  background: var(--n-100); color: var(--text-3); border: 1px solid transparent;
}
.ciclo .p.hecha { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-bd); }
.ciclo .p.aqui  { background: var(--n-900); color: #fff; font-weight: 700; }
.ciclo .sep { color: var(--n-300); }

/* Lienzo: contenido + panel. En pantalla angosta el panel baja y deja de
   ser fijo, porque a 900 px no caben 330 px de panel y una tabla. */
.lienzo { display: grid; grid-template-columns: minmax(0,1fr) 330px; gap: var(--sp-4); align-items: start; }
.panel {
  position: sticky; top: calc(var(--h-topbar) + 58px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sombra-1);
  max-height: calc(100vh - var(--h-topbar) - 78px); display: flex; flex-direction: column;
}
.panel-cuerpo { flex: 1; overflow-y: auto; padding: 14px 16px; }
.panel-pie { border-top: 1px solid var(--border); padding: 14px 16px; background: var(--bg);
             border-radius: 0 0 var(--r-lg) var(--r-lg); }
.panel h5 { font-size: var(--fs-100); font-weight: 700; text-transform: uppercase;
            letter-spacing: .7px; color: var(--text-2); margin: 12px 0 6px; }
.panel h5:first-child { margin-top: 0; }
/* 1280 y no 1100: con el menú lateral de 220 px, a 1200 el contenido queda
   en 557 px y la tabla de flores (710 px) obliga a scroll horizontal justo
   sobre la columna de Subtotal. Debajo de ese ancho el panel baja y la tabla
   recupera el ancho completo. */
@media (max-width: 1280px) {
  .lienzo { grid-template-columns: minmax(0,1fr); }
  .panel { position: static; max-height: none; }
}

/* Repetidor colapsable: cerrado enseña foto, título, cantidad y subtotal;
   se abre el que se trabaja. Con 8 arreglos abiertos el scroll no acaba y
   no hay forma de saber dónde estás. */
.rep > summary {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  cursor: pointer; list-style: none; border-radius: var(--r-lg);
}
.rep > summary::-webkit-details-marker { display: none; }
.rep > summary::before { content: '›'; font-size: 14px; color: var(--text-3);
                         transition: transform .15s; width: 8px; flex: none; }
.rep[open] > summary::before { transform: rotate(90deg); }
.rep > summary:hover { background: var(--surface-alt); }
.rep-mini { width: 34px; height: 34px; border-radius: var(--r-sm); flex: none;
            border: 1px solid var(--border); background: var(--bg) center/cover no-repeat; }
.rep-t { flex: 1; min-width: 0; font-size: var(--fs-300); font-weight: 600;
         overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rep-m { font-size: var(--fs-100); color: var(--text-2); white-space: nowrap; }
.rep-s { font-size: var(--fs-300); font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Lo calculado no parece campo. Si se ve como input, alguien va a intentar
   escribirlo — y Paquetes, P.Paquete y Subtotal son fórmulas, no capturas. */
.calc { display: block; background: var(--n-25); border-radius: var(--r-sm);
        padding: 4px 7px; text-align: right; font-variant-numeric: tabular-nums;
        color: var(--text-2); font-size: var(--fs-200); }
.calc.fuerte { color: var(--text-1); font-weight: 600; }

/* Índice del panel: clic en un arreglo y salta. */
.idx { display: flex; flex-direction: column; gap: 1px; }
.idx a { display: flex; gap: 8px; align-items: baseline; padding: 5px 7px;
         border-radius: var(--r-sm); font-size: var(--fs-200); color: var(--text-1); }
.idx a:hover { background: var(--surface-alt); text-decoration: none; }
.idx a .n { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.idx a .v { color: var(--text-2); font-variant-numeric: tabular-nums; }

/* Cabecera de sección con acción a la derecha. Es .fs partido en dos: el
   título a la izquierda, el botón o el dato accesorio a la derecha. */
.fs-cab { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.fs-cab h4 { flex: 1; font-size: var(--fs-300); font-weight: 700; margin: 0; }

/* ── Hub de catálogos de un área (lib/ui.php · hub_catalogos) ──────────────
   Rejilla de tarjetas que agrupa lo que cada área mantiene por su cuenta.
   El hover va en CSS y no en onmouseover inline como en la pantalla vieja de
   Configuración: así respeta el tema y no depende de JS. */
.hub-cat { display: grid; gap: var(--sp-3);
           grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
.hub-cat-t { display: block; padding: var(--sp-6); text-decoration: none;
             background: var(--surface); border: 1px solid var(--border);
             border-radius: var(--r-lg); color: inherit;
             transition: border-color .15s, box-shadow .15s, transform .15s; }
.hub-cat-t:hover { text-decoration: none; border-color: var(--text-3);
                   box-shadow: 0 4px 16px rgba(0,0,0,.08); transform: translateY(-1px); }
.hub-cat-ic { font-size: 26px; line-height: 1; margin-bottom: var(--sp-3); }
.hub-cat-h  { font-weight: 700; font-size: var(--fs-400); margin-bottom: 2px; }
.hub-cat-s  { font-size: var(--fs-200); color: var(--text-2); line-height: var(--lh-2); }
.hub-cat-g { font-size: var(--fs-200); font-weight: 700; text-transform: uppercase;
             letter-spacing: .6px; color: var(--text-3);
             margin: var(--sp-6) 0 var(--sp-2); }
.hub-cat-g:first-child { margin-top: 0; }

/* ── Interruptor de activo / inactivo ──────────────────────────────────────
   Sustituye al <select> Activo|Inactivo. Un estado de dos valores que se
   cambia a diario no merece un desplegable: son dos clics y una lectura para
   algo que debería ser uno y un vistazo.

   Se lee ENCENDIDO o APAGADO sin leer el texto, que es el punto. El texto va al
   lado igualmente: el color solo no basta para quien no lo distingue.

   Es un <input type=checkbox> de verdad, no un div con JS: llega el foco por
   teclado, la barra espaciadora lo cambia y los lectores de pantalla lo anuncian
   como lo que es. */
.itr { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
.itr input { position: absolute; opacity: 0; width: 0; height: 0; }
.itr .pista {
  position: relative; flex: none; width: 38px; height: 22px; border-radius: 999px;
  background: var(--n-300, #cfccc4); transition: background .16s;
}
.itr .pista::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25);
  transition: transform .16s;
}
.itr input:checked + .pista { background: var(--ok-fg, #2e7d32); }
.itr input:checked + .pista::after { transform: translateX(16px); }
.itr input:focus-visible + .pista { outline: 2px solid var(--info-fg); outline-offset: 2px; }
.itr .txt { font-size: var(--fs-200); color: var(--text-2); }
.itr input:checked ~ .txt { color: var(--text-1); font-weight: 600; }

/* ═══ MÓDULO COMERCIAL · la matriz de 13 columnas ═══
   Es un reporte, no una lista: 12 meses más el total no caben con el ancho de
   una tabla normal. Por eso baja a --fs-200, usa cifras tabulares (para que las
   columnas alineen sin importar el dígito) y scroll horizontal PROPIO, dentro
   de su tarjeta — nunca del body, que es la regla de la guía.

   Sin colores nuevos: todo sale de los tokens de arriba. */
/* Comercial apila varias tarjetas (el reporte, el desglose por vendedora), y en
   el resto de la app cada vista trae UNA sola: por eso no había separación entre
   tarjetas consecutivas y quedaban pegadas. Se resuelve con una clase propia en
   vez de un `.card + .card` global, que le sumaría margen a las pantallas que ya
   traen el suyo en un style inline (Sincronización, Recursos, Checklists). */
.cm-bloque { margin-bottom: var(--sp-6); }

.cm-scroll { overflow-x: auto; }

/* table-layout:fixed y anchos explícitos porque en esta pantalla hay DOS
   matrices apiladas —el seguimiento y el desglose por vendedora— y con anchos
   automáticos cada una se acomodaba a su propio contenido: "CONCEPTO" quedaba
   angosto y "VENDEDORA" ancho, así que los doce meses no coincidían entre una
   tabla y otra. Con esto las columnas caen en el mismo lugar siempre. */
.cm-matriz {
  table-layout: fixed;
  min-width: 1530px;   /* 230 de etiqueta + 12 x 100 de mes + 100 del total */
  font-variant-numeric: tabular-nums;
}
.cm-matriz .cm-etq   { width: 230px; }
.cm-matriz .num      { width: 100px; }
.cm-matriz .cm-total { width: 100px; }
.cm-matriz th, .cm-matriz td { white-space: nowrap; }
.cm-matriz .num { text-align: right; font-family: var(--fuente-num); font-size: var(--fs-200); }
.cm-matriz thead th { text-align: right; color: var(--text-2); }
.cm-matriz thead th.cm-etq { text-align: left; }

/* La etiqueta del renglón se queda pegada al desplazarse: sin esto, al llegar a
   diciembre ya no se sabe qué renglón se está leyendo. */
.cm-etq {
  position: sticky; left: 0; z-index: 1;
  background: var(--surface);
  text-align: left; font-weight: 600; color: var(--text-1);
  font-size: var(--fs-200); min-width: 190px;
}

.cm-total { font-weight: 700; border-left: 1px solid var(--border-fuerte); }

/* ── SEPARACIÓN EN BLOQUES ──
   La tabla son cinco preguntas distintas —cuánto llevamos, cómo vamos contra la
   meta, qué se movió esta semana, qué se perdió, y cómo fue en años pasados— y
   leídas de corrido se mezclan. Se separan con línea y aire arriba, NO con
   renglones vacíos: un renglón en blanco cortaría la raya azul del mes en curso
   y dejaría un hueco en la columna pegajosa de la izquierda. */
.cm-sep > * {
  border-top: 1px solid var(--border-fuerte) !important;
  padding-top: 22px !important;
}
/* El bloque histórico se separa doble: no es otra medida del año en curso, es
   la referencia contra la que se juzga todo lo de arriba. */
.cm-sep-doble > * {
  border-top: 3px double var(--border-fuerte) !important;
  padding-top: 26px !important;
}
.cm-sub    { background: var(--n-25); font-weight: 600; }

/* ── LA CLAVE DE COLOR DE LOS RENGLONES ──
   Verde = venta cerrada del año en curso · ámbar = todavía en cotización ·
   gris = suma de las dos · azul = venta real de años anteriores.
   Con doce columnas de números iguales, el color de la etiqueta es lo que deja
   encontrar el renglón sin leerlo.

   El azul es LA VARA CON LA QUE SE MIDE: la meta vigente y la venta real de los
   años anteriores. Ninguna de las dos es venta de este año; las dos son el
   punto de comparación. Mismo tono que la raya del mes en curso.

   El rojo es lo que se perdió. Como con el ámbar, la barra sube de tono
   (--err-punto) y la palabra se queda en el rojo que cumple AA (--err-fg).

   La barra y la palabra NO llevan el mismo tono, por la misma razón que los
   semáforos (ver .sem): el texto está obligado a contraste AA sobre fondo claro,
   y eso convierte cualquier amarillo de verdad en café. La barra es objeto
   gráfico, solo debe 3:1, y sí puede ir en ámbar real. */
/* Las tres reglas de color llevan `tbody tr` de más para igualar la
   especificidad de la regla base de aquí abajo. Sin eso la base —que es más
   específica por el elemento `tbody`— gana y la barra se queda transparente,
   aunque el color del texto sí entre: pasó al construirlo. */
.cm-matriz tbody .cm-etq { border-left: 3px solid transparent; }
.cm-matriz tbody tr.cm-r-vendido .cm-etq { border-left-color: var(--ok-punto);   color: var(--ok-fg); }
.cm-matriz tbody tr.cm-r-cotiza  .cm-etq { border-left-color: var(--warn-punto); color: var(--warn-fg); }
.cm-matriz tbody tr.cm-r-total   .cm-etq { border-left-color: var(--n-300);      color: var(--text-2); }
/* Aquí barra y texto SÍ comparten tono: --info-fg ya cumple AA como texto
   (5.70:1), así que no hace falta un token de punto aparte como con el ámbar. */
.cm-matriz tbody tr.cm-r-referencia .cm-etq { border-left-color: var(--info-fg); color: var(--info-fg); }
.cm-matriz tbody tr.cm-r-rechazo    .cm-etq { border-left-color: var(--err-punto); color: var(--err-fg); }

.cm-neg { color: var(--err-fg); }
.cm-pos { color: var(--ok-fg); }
.cm-cero { color: var(--text-3); }
.cm-vacio { text-align: center; color: var(--text-3); padding: var(--sp-4); }
.cm-pie {
  margin: 0; padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-200); color: var(--text-2);
  border-top: 1px solid var(--border-sutil);
}

/* Celdas de captura del presupuesto: el input ocupa la celda entera para que la
   cuadrícula se lea como una hoja de cálculo, que es de donde viene la cifra. */
.cm-captura input {
  width: 100%; text-align: right;
  font-family: var(--fuente-num); font-size: var(--fs-200);
  height: var(--ctl-h); padding: 0 6px;
}

/* Tarjeta plegable (<details>) para acciones que se usan poco pero tienen que
   estar a la mano: la creación de una versión de presupuesto se hace tres veces
   al año, y desplegada empujaba hacia abajo la cuadrícula que sí se captura
   todos los días. Cerrada ocupa un renglón. */
.cm-plegable { padding: 0; margin-bottom: var(--sp-4); }
.cm-plegable > summary {
  list-style: none; cursor: pointer; user-select: none;
  padding: var(--sp-3) var(--sp-6);
  font-size: var(--fs-300); font-weight: 600; color: var(--accion);
}
.cm-plegable > summary::-webkit-details-marker { display: none; }
.cm-plegable > summary:hover { background: var(--n-25); }
.cm-plegable > summary:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }
.cm-plegable[open] > summary { border-bottom: 1px solid var(--border); }
.cm-plegable-cuerpo { padding: var(--sp-4) var(--sp-6); }
.cm-plegable-cuerpo p {
  margin: 0 0 var(--sp-4); font-size: var(--fs-200); color: var(--text-2);
}
.cm-acciones { display: inline-flex; gap: var(--sp-2); }

/* La suma del reparto: se lee como encabezado del bloque de vendedoras, no como
   una vendedora más. */
.cm-suma > * { background: var(--n-25); font-weight: 600; }
/* El código de dos letras junto al nombre: es la llave de atribución, y verla
   ayuda a cuadrar contra el folio del evento. */
.cm-cod { font-family: var(--fuente-num); font-size: var(--fs-100); color: var(--text-3); }

/* ── CATÁLOGO DE CÓDIGOS ──
   Tabla de captura ancha: campos de texto que llenan su celda, y los renglones
   de quien ya salió atenuados para que se lean como historia y no como equipo. */
.cm-cat { min-width: 1180px; font-size: var(--fs-200); }
.cm-cat th, .cm-cat td { padding: var(--sp-2) .5rem; vertical-align: middle; }
.cm-cat input[type=text], .cm-cat input[type=date], .cm-cat select {
  width: 100%; height: var(--ctl-h); font-size: var(--fs-200); padding: 0 6px;
}
.cm-cat .num { text-align: right; font-family: var(--fuente-num); white-space: nowrap; }
.cm-cat .cm-fecha { font-family: var(--fuente-num); color: var(--text-2); white-space: nowrap; }
.cm-cod-celda {
  font-family: var(--fuente-num); font-weight: 700; color: var(--info-fg);
  text-align: center; width: 46px;
}
/* Quien ya salió sigue a la vista —su venta cuenta— pero apagado. */
.cm-baja > td, .cm-baja > th { opacity: .55; }
.cm-baja .cm-cod-celda { color: var(--text-3); }

/* El aviso de códigos sin clasificar. */
.cm-aviso { border-color: var(--warn-bd); background: var(--warn-bg); font-size: var(--fs-200); }
.cm-aviso ul { margin: var(--sp-2) 0 0; padding-left: 1.2rem; }
.cm-aviso li { margin-bottom: 2px; }
/* Meses en que la persona ya no estaba: ni se capturan ni se leen como cero. */
.cm-fuera { background: repeating-linear-gradient(45deg, transparent, transparent 5px,
            var(--n-50) 5px, var(--n-50) 10px); }

/* ── DESGLOSE PLEGABLE POR VENDEDORA ──
   Cada vendedora es un <tbody> propio. Cerrado deja a la vista el renglón de
   cumplimiento; abierto muestra vendido, meta y diferencia. */
.cm-grupo .cm-detalle { display: none; }
.cm-grupo.abierto .cm-detalle { display: table-row; }
.cm-grupo .cm-cab[onclick] { cursor: pointer; user-select: none; }
.cm-grupo .cm-cab[onclick]:hover .cm-etq { color: var(--info-fg); }
.cm-grupo + .cm-grupo .cm-cab > * { border-top: 1px solid var(--border-sutil); }
.cm-flecha {
  display: inline-block; width: 12px; color: var(--text-3);
  transition: transform .15s;
}
.cm-grupo.abierto .cm-flecha { transform: rotate(90deg); }
/* El detalle se hunde un poco para leerse como hijo de su vendedora. */
.cm-grupo.abierto .cm-detalle .cm-etq { padding-left: 26px; font-weight: 400; }
/* Rótulo que separa los grupos del desglose por vendedora. */
.cm-rotulo {
  text-align: left !important; font-weight: 600; font-size: var(--fs-100);
  text-transform: uppercase; letter-spacing: .04em; color: var(--text-3);
  background: var(--n-25); position: static !important;
}

/* ── COBRANZA: la mesa de trabajo semanal ── */
.cm-cob { min-width: 1400px; font-size: var(--fs-200); }
/* Cartera lleva dos columnas menos —los días bajan bajo la fecha y la condición
   bajo el nombre del evento— para que Estado y Seguimiento quepan sin scroll
   horizontal: son justamente las dos que hay que mirar en esta lista. */
.cm-cob-cartera { min-width: 1120px; }
.cm-cob th, .cm-cob td { padding: var(--sp-2) .5rem; vertical-align: top; }
.cm-cob .num { text-align: right; font-family: var(--fuente-num); white-space: nowrap; }
.cm-cob .cm-fecha { font-family: var(--fuente-num); white-space: nowrap; color: var(--text-2); }
.cm-cob .cm-folio { font-family: var(--fuente-num); font-weight: 700; color: var(--info-fg); white-space: nowrap; }
.cm-cob .sub { font-size: var(--fs-100); color: var(--text-2); }
.cm-firma { font-size: var(--fs-100); color: var(--text-3); margin-top: 2px; }

/* Cuántas actualizaciones lleva el evento y de cuándo es la última. El hilo
   completo vive en el drawer: metido en la celda apretaba los datos del
   renglón, que es justo lo que hay que leer para decidir. El "+" de los vacíos
   invita a escribir en lugar de dejar el hueco callado. */
.cob-marcas a { display: inline-flex; align-items: center; gap: 5px; text-decoration: none; }
.cob-hilo {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: 10px; font-size: var(--fs-100); font-weight: 700;
  background: var(--n-100); color: var(--text-3);
}
.cob-hilo.llena { background: var(--info-bg); color: var(--info-fg); }
.cob-cuando { font-family: var(--fuente-num); font-size: var(--fs-100); color: var(--text-3); }
.cm-cob .cm-folio a { color: var(--info-fg); text-decoration: none; }
.cm-cob .cm-folio a:hover { text-decoration: underline; }

/* Renglones marcados en Pago anticipado. El color va en el fondo del renglón
   entero y con una franja al inicio, no solo en una celda: la pregunta que se
   contesta al abrir la lista es "¿a quién le hablo hoy?", y eso se ve barriendo
   la hoja, no leyendo columna por columna.

   El tinte es el de los tokens semánticos, que ya están medidos para que el
   texto encima siga siendo legible; no se pinta el texto de rojo, porque
   entonces pelearía con los chips de estado que ya viven en el renglón. */
.cm-cob tbody tr.cob-rojo    { background: var(--err-bg); }
.cm-cob tbody tr.cob-amarillo{ background: var(--warn-bg); }
.cm-cob tbody tr.cob-rojo     > td:first-child { box-shadow: inset 3px 0 0 var(--err-punto); }
.cm-cob tbody tr.cob-amarillo > td:first-child { box-shadow: inset 3px 0 0 var(--warn-punto); }
/* La muestra de color en la leyenda del pie. */
.cob-clave { padding: 1px 6px; border-radius: 4px; font-weight: 600; }
.cob-clave.cob-rojo     { background: var(--err-bg);  color: var(--err-fg);  }
.cob-clave.cob-amarillo { background: var(--warn-bg); color: var(--warn-fg); }

/* El índice mes a mes. Un mes sin cortar se ve distinto a propósito: su número
   todavía se mueve y no sirve para pagar un bono. */
.cm-pol { width: 100%; font-size: var(--fs-200); }
.cm-pol th, .cm-pol td { padding: var(--sp-2) .5rem; }
.cm-pol .num { text-align: right; font-family: var(--fuente-num); white-space: nowrap; }
.cm-pol .col-cen { text-align: center; font-family: var(--fuente-num); }
.cm-pol tbody tr.pol-provisional { color: var(--text-3); background: var(--n-25); }
.cm-pol tbody tr.pol-provisional .num { opacity: .75; }

/* ── El muro de actualizaciones ──
   No es un campo de texto por área: es la historia de lo que se intentó y
   cuándo. Se lee de arriba abajo como una conversación, lo último queda pegado
   a la caja de escribir, y nada se edita ni se borra. */
.cob-muro {
  max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px;
  padding: 10px; border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--n-25);
}
.cob-msg { background: var(--surface); border: 1px solid var(--borde); border-radius: var(--radio); padding: 7px 9px; }
.cob-msg-cab { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; margin-bottom: 3px; }
.cob-msg-cab b { font-size: var(--fs-200); }
.cob-msg-cab span { font-size: var(--fs-100); color: var(--text-3); font-family: var(--fuente-num); }
.cob-msg-txt { font-size: var(--fs-200); color: var(--text-1); line-height: 1.45; white-space: pre-wrap; }
.cob-escribir { display: flex; gap: 8px; align-items: flex-end; margin-top: 8px; }
.cob-escribir textarea {
  flex: 1; min-width: 0; resize: vertical; font: inherit; font-size: var(--fs-200);
  padding: 7px 9px; border: 1px solid var(--borde); border-radius: var(--radio);
  background: var(--surface); color: var(--text-1);
}
.cob-escribir .btn { white-space: nowrap; }

/* ── Drawer de cobranza ── */
.cob-datos {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--sp-3) var(--sp-4); margin: var(--sp-3) 0;
}
.cob-datos > div { display: flex; flex-direction: column; gap: 2px; }
.cob-datos span { font-size: var(--fs-100); color: var(--text-2); text-transform: uppercase; letter-spacing: .03em; }
.cob-datos b { font-size: var(--fs-300); font-weight: 600; }
.cob-datos i { font-style: normal; font-size: var(--fs-100); color: var(--text-3); }
.cob-dinero { background: var(--n-25); border-radius: var(--r-md, 6px); padding: var(--sp-3); }
.cob-dinero b { font-family: var(--fuente-num); }
.cob-pagos { font-size: var(--fs-200); }
.cob-pagos .num { text-align: right; font-family: var(--fuente-num); }
.cob-nota { width: 100%; resize: vertical; font-size: var(--fs-300); padding: 6px 8px; line-height: 1.4; }

/* ═══ FICHA (.pv-* / .pf-*) ═══════════════════════════════════════════════
   Vocabulario de las pantallas de FICHA: renglon rayado con etiqueta a la
   izquierda, seccion con contador, control segmentado, pareja de tarjetas de
   altura pareja, y tabla con campos que solo se dibujan al pasar encima.

   Nacio dentro de views/rentas/proveedor.php (propuesta de Claude Design,
   14-ago-2026) y vivio ahi hasta el 8-sep-2026, cuando Cotizaciones necesito
   lo mismo. Copiarlo habria creado dos hojas que se desvian —el error que
   este codigo ya cometio con las listas de areas—, asi que se subio aqui tal
   cual, SIN cambiar una sola regla, y proveedor.php dejo de traerlo.
   El razonamiento de cada decision se conservo en los comentarios.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Ficha de proveedor · propuesta de Claude Design, 14-ago-2026 ──────────
   Sustituye tres intentos mios que Rafael fue rechazando con razon. Lo que yo
   no estaba viendo:

   1. CONTROLES SEGMENTADOS, no chips sueltos. Un grupo unido dice "elige uno de
      estos"; pastillas separadas parecen etiquetas y no se sabe si son opcion o
      dato. Es lo que mas cambia la sensacion de la pantalla.
   2. Un AVISO ARRIBA cuando falta algo que rompe la operacion. Un proveedor sin
      ubicacion y con un viaje programado es un chofer que sale sin direccion:
      eso no es un campo vacio, es un problema con fecha.
   3. RENGLONES ALTERNADOS. Con seis filas de etiqueta-y-campo el ojo se pierde;
      el rayado cuesta nada y ancla la lectura.
   4. SECCIONES CON CONTADOR. "Contactos 1" contra "Contactos" a secas: el
      numero dice si hay que entrar antes de entrar.

   Los dos bloques de arriba llevan CINCO renglones cada uno a proposito, para
   que queden de la misma altura. Notas internas es el quinto de su columna y por
   eso va acotada: si crece, descuadra la pareja. */

/* A LO ANCHO DE LA PAGINA, sin tope (Rafael, 14-ago-2026).
   Hubo un tope de 1,180 px, y existia por un problema que este diseno ya no
   tiene: antes el valor se estiraba hasta el borde de la tarjeta y quedaba a
   400 px de su etiqueta. Aqui cada campo lleva su propio tope (.pv-f .val,
   360 px) y los segmentados miden lo que miden, asi que ensanchar la pagina
   solo ensancha las dos columnas — la linea de lectura no crece.
   Si algun dia se quita ese tope de .val, hay que volver a acotar la hoja. */

/* Barra de pagina: identidad y las acciones que aplican a TODA la ficha. */
.pv-barra{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
          padding-bottom:10px;border-bottom:1px solid var(--border);margin-bottom:14px}
.pv-barra .volver{color:var(--text-2);text-decoration:none;font-size:16px}
.pv-barra h1{margin:0;font-size:19px;font-weight:700}
.pv-barra .ruta{font-size:var(--fs-200);color:var(--text-3)}
.pv-guardado{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-200);color:var(--text-2)}
.pv-guardado::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--ok-fg)}

/* Tarjeta de identidad. */
.pv-id{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}
.pv-id .nom{font-size:22px;font-weight:700;margin:0;letter-spacing:-.2px}
.pv-id .sub{font-size:var(--fs-300);color:var(--text-2);margin:4px 0 0}
.pv-cifra{text-align:right;min-width:96px}
.pv-cifra dt{font-size:10.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--text-3);margin:0}
.pv-cifra dd{font-size:19px;font-weight:700;margin:2px 0 0;font-variant-numeric:tabular-nums}

/* Etiqueta de estado y de categoria. */
.pv-tag{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:999px;
        font-size:12px;background:var(--n-100,#f2f0ec);color:var(--text-2);border:1px solid var(--border)}
.pv-tag.on{background:var(--ok-bg);color:var(--ok-fg);border-color:transparent;font-weight:600}
.pv-tag .x{cursor:pointer;color:var(--text-3);font-size:13px;line-height:1}
.pv-tag .x:hover{color:var(--err-fg)}

/* Aviso de lo que rompe la operacion. */
.pv-alerta{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
           background:var(--warn-bg);border:1px solid var(--warn-bd);
           border-radius:var(--r-lg);padding:12px 14px;margin:12px 0}
.pv-alerta b{color:var(--warn-fg)}
.pv-alerta .txt{flex:1;min-width:240px;font-size:var(--fs-300);color:var(--warn-fg)}

/* Seccion con encabezado, contador y accion. */
.pv-sec h4{margin:0;font-size:11px;text-transform:uppercase;letter-spacing:.7px;color:var(--text-2)}
.pv-sech{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.pv-num{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;
        padding:0 6px;border-radius:999px;background:var(--n-100,#f2f0ec);
        font-size:11px;font-weight:700;color:var(--text-2)}
.pv-num.cero{background:var(--warn-bg);color:var(--warn-fg)}

/* Renglon de campo, con rayado. */
/* flex-wrap: si el renglon no cabe, la ayuda BAJA en vez de estrujar el campo
   —dos inputs de fecha se salian de la tarjeta—. Cuando cabe, no cambia nada. */
.pv-f{display:flex;align-items:center;gap:12px;padding:7px 10px;border-radius:6px;min-height:36px;flex-wrap:wrap}
.pv-f .val > input, .pv-f .val > select, .pv-f .val > textarea{min-width:0}
.pv-f:nth-child(odd){background:var(--n-050,#faf9f7)}
.pv-f > .et{flex:0 0 150px;font-size:var(--fs-300);color:var(--text-2)}
.pv-f .val{flex:1 1 auto;max-width:360px}
.pv-f .ay{font-size:var(--fs-200);color:var(--text-3)}
.pv-inp{border:1px solid var(--border);background:var(--surface);border-radius:var(--r-sm);
        padding:5px 8px;font-size:var(--fs-300);width:100%;text-overflow:ellipsis}
.pv-inp:focus{border-color:var(--foco);box-shadow:var(--anillo);outline:none}
.pv-inp::placeholder{color:var(--text-3);opacity:1}
textarea.pv-inp{min-height:38px;resize:vertical}

/* Control segmentado: un grupo unido dice "elige uno de estos". */
.pv-seg{display:inline-flex;border:1px solid var(--border);border-radius:var(--r-sm);overflow:hidden}
.pv-seg button{border:0;background:var(--surface);color:var(--text-2);cursor:pointer;
               font-family:inherit;font-size:12.5px;padding:5px 12px;white-space:nowrap}
.pv-seg button + button{border-left:1px solid var(--border)}
.pv-seg button:hover{background:var(--n-050,#faf9f7)}
.pv-seg button.on{background:var(--n-900);color:#fff;font-weight:600}

/* SIN align-items:start, y es deliberado. Esa linea era la que dejaba las dos
   tarjetas desparejas: cada una tomaba su propia altura. Por omision la rejilla
   ESTIRA los dos hijos a la altura del mas alto, asi que crezca lo que crezca
   cualquiera de los dos, quedan siempre parejos. El hueco sobrante queda abajo
   del corto, que se lee como espacio y no como error. */
.pv-par{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.pv-par > .fs{display:flex;flex-direction:column}
@media (max-width:1000px){ .pv-par{grid-template-columns:minmax(0,1fr)} }

/* Listas: contacto y ubicacion se LEEN; se editan al entrar en el campo. */
.pv-lista{margin:0;padding:0;list-style:none}
.pv-lista > li{padding:9px 0;border-bottom:1px solid var(--border-sutil)}
.pv-lista > li:last-child{border-bottom:0}
.pv-ini{width:30px;height:30px;border-radius:50%;background:var(--n-100,#f2f0ec);
        display:flex;align-items:center;justify-content:center;flex:none;
        font-size:11px;font-weight:700;color:var(--text-2)}
.pv-vacio{font-size:var(--fs-300);color:var(--text-2);line-height:var(--lh-2);margin:0}
.pf-tabla{width:100%;border-collapse:collapse;font-size:12.5px}
.pf-tabla th{text-align:left;color:var(--text-2);font-weight:500;padding:4px 6px;font-size:10.5px;text-transform:uppercase;border-bottom:1px solid var(--border)}
.pf-tabla td{padding:3px 6px;border-bottom:1px solid var(--border-sutil)}
.pf-inp{border:1px solid transparent;background:transparent;border-radius:6px;padding:4px 6px;font-size:13px;width:100%}
.pf-inp:hover{border-color:var(--border)}
.pf-inp:focus{border-color:var(--foco);background:var(--surface);box-shadow:var(--anillo);outline:none}
.pf-inp::placeholder{color:var(--text-3);opacity:1}
.pf-sel{border:1px solid var(--border);border-radius:var(--r-sm);height:var(--ctl-h);font-size:var(--fs-200);padding:0 6px;background:var(--surface)}
.pf-nuevo{border-top:2px solid var(--border);background:var(--n-100,#f7f6f3)}
.pf-nuevo td{padding:6px}
.pf-ok{outline:2px solid var(--ok-fg)} .pf-err{outline:2px solid var(--err-fg)}

/* ══ COSTEO ═══════════════════════════════════════════════════════════
   Las siete pantallas del costeo, en un solo lugar.

   Nació el 18-sep-2026, cuando Rafael señaló que cada pantalla del módulo se
   veía distinta. Lo era: cada vista traía su propio <style> y definía .co-num,
   .ch-num y .cu-num para la MISMA columna de cifras, con valores que se habían
   ido separando. Aquí está una sola vez.

   Lo que NO vive aquí, porque ya lo resuelve el sistema: tarjetas de cifra
   (.stat-card), barras de avance (.progress-bar), etiquetas de estado (.et),
   columnas numéricas (.col-num), dato secundario (.sub), línea de resumen
   (.resumen) y pantalla sin datos (estado_vacio). */

/* ── Dinero y claves ───────────────────────────────────────────────── */
/* El negativo en rojo: la utilidad bruta puede salir negativa y en una columna
   de cifras alineadas el signo solo se pierde. */
.co-neg { color: var(--err-fg); }
/* El hueco: un dato que no aplica, distinto de un cero. */
.co-sin { color: var(--text-3); }
/* Celda de clave: cuenta contable, código de evento, folio de documento. */
.co-cod { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* El folio es un enlace, pero discreto: subrayado sólo al pasar encima, para
   que 400 renglones no se vean como una lista de links. */
.co-ep { color: var(--text-2); text-decoration: none; border-bottom: 1px dotted var(--border); }
.co-ep:hover { color: var(--foco); border-bottom-style: solid; }
/* El concepto abre el pago en el panel lateral. Mismo trato discreto. */
.co-pago { color: var(--text-1); text-decoration: none; border-bottom: 1px dotted var(--border); }
.co-pago:hover { color: var(--foco); border-bottom-style: solid; }

/* ── Columnas de las tablas del costeo ─────────────────────────────── */
/* UNA SOLA COLUMNA ELÁSTICA POR TABLA. Con `width:100%` en dos columnas, el
   navegador reparte el sobrante entre las dos y deja un hueco en medio mientras
   las cortas —silo, departamento, fecha— se parten en dos renglones. La larga
   se marca con .co-flex y las cortas se blindan con .co-seco.
   EL AIRE SOBRANTE SE LO LLEVA EL NOMBRE DEL EVENTO: con ancho automático el
   folio se veía flotando en medio de la nada aunque su min-width fuera chico. */
.co-ev   { min-width: 14rem; }
.co-flex { width: 100%; }
.co-seco { white-space: nowrap; }
.co-sel  { width: 2rem; text-align: center; }
/* Encabezado de una columna de cifras: centrado, que es donde se lee mejor un
   rótulo corto sobre números alineados a la derecha. */
thead .col-num { text-align: center; }
/* La fila de totales va ARRIBA: con 400 eventos, ponerla al final obliga a
   bajar hasta el fondo para saber cómo cerró el mes. */
.co-tot th { border-bottom: 2px solid var(--border); background: var(--surface-alt); }
.co-com  { background: var(--surface-alt); }
.co-ub   { border-left: 2px solid var(--border); }
/* Factura y Saldo son el estado del dinero YA VENDIDO, no parte del costo: van
   pegadas a la venta y separadas de las comisiones por su propio fondo. */
.co-est { background: var(--surface); text-align: center; white-space: nowrap; }
.col-num.co-est { text-align: right; }

/* ── Filas que se despliegan y grupos ──────────────────────────────── */
.co-abre { cursor: pointer; }
.co-abre:hover td { background: var(--surface-captura); }
.co-abre:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }
.co-flecha { display: inline-block; width: .7em; color: var(--text-3);
             transition: transform .12s ease; }
.co-abre[aria-expanded="true"] .co-flecha { transform: rotate(90deg); }
.co-hijo td:first-child { border-left: 3px solid var(--border); }
/* EL GRUPO SE VE COMO GRUPO. El encabezado lleva el nombre y los totales del
   lead; sus eventos van debajo, marcados con una línea al costado. */
.co-grupo th { background: var(--surface-alt); border-top: 2px solid var(--border); }
/* Los dos bloques de estatus mandan sobre los grupos: son la división gruesa de
   la tabla y por eso pesan más que un encabezado de grupo. */
.co-estatus th { border-top: 3px solid var(--text-3); letter-spacing: .03em; }
/* El código del lead lo pone la app y no se edita: es una llave, no un nombre.
   NO HAY COLUMNA DE LEAD: una columna propia obligaría a dejarla vacía en los
   400 renglones de evento, y una columna vacía es ruido. */
.co-ref { padding-right: .3rem; white-space: nowrap; }
.co-cod-neg { font-variant-numeric: tabular-nums; letter-spacing: .02em; }
/* LO QUE NO SE VENDIÓ VA EN ROJO CLARO Y SEPARADO. Son dos tablas pegadas: una
   es el mes y la otra la lista de reclamos. El hueco y el color evitan que
   alguien siga leyendo hacia abajo creyendo que sigue sumando. El rojo sale de
   --err-bg, que ya está resuelto para el modo oscuro. */
.co-hueco td { height: 2.2rem; border: 0; background: var(--surface); }
.co-fuera th { background: var(--err-bg); color: var(--err-fg);
               border-top: 3px solid var(--err-bd); }
.co-fuera-fila td { background: var(--err-bg); color: var(--text-2); }
/* Renglón ya resuelto: sigue ahí, pero se apaga. Se queda en su lugar a
   propósito — reordenar al hacer clic hace perder el sitio en una tabla larga. */
.co-hecho > td { opacity: .55; }

/* ── El campo de categoría del paso 2 ──────────────────────────────── */
/* LA CATEGORÍA ES EL CAMPO CON EL QUE SE TRABAJA, así que se ve como campo y no
   como nota al pie. Antes iba en gris chico debajo del proveedor y no se veía;
   es justo lo que el operador tiene que usar para avanzar la etapa 2-C.
     azul  = la puso la app deduciendo
     verde = la confirmó una persona
     rojo  = falta, y un pago sin categoría es un pago fuera del costeo */
/* Es un <button> de verdad, no un <span role="button">: con la fila entera
   abriendo el drawer, sólo los controles reales quedan excluidos del
   disparador — si no, tocar la categoría abría el panel y tapaba justo lo que
   se iba a editar. `font: inherit` porque el navegador le pone la suya. */
.co-cat { display: inline-block; font: inherit; font-size: var(--fs-200); cursor: pointer;
          white-space: nowrap; text-align: left;
          padding: .15rem .5rem; border-radius: 999px; border: 1px solid transparent; }
.co-cat-ded   { background: var(--info-bg); color: var(--info-fg); border-color: var(--info-bd); }
.co-cat-ok    { background: var(--ok-bg);   color: var(--ok-fg);   border-color: var(--ok-bd);
                font-weight: 600; }
.co-cat-falta { background: var(--err-bg);  color: var(--err-fg);  border-color: var(--err-bd);
                font-weight: 600; }
/* Categoría que existe pero NO suma al costeo (comisiones, bono de ventas): hay
   que clasificarla igual, pero no es costo. */
.co-cat-nosuma { background: var(--surface-alt); color: var(--text-3);
                 border-color: var(--border); font-weight: 400;
                 text-decoration: line-through dotted; }
.co-cat:hover { border-color: var(--foco); }
.co-cat-sel { font: inherit; font-size: var(--fs-200); max-width: 16rem; }
/* El renglón del pago se reparte: el texto a la izquierda, el campo a la
   derecha, que es donde estaba el espacio en blanco. */
.co-linea { display: flex; gap: 1rem; align-items: center; justify-content: space-between; }
/* La caja de ancho fijo es lo que alinea los chips en columna. Sin ella cada uno
   arranca donde termina su texto y la lista se ve como un serrucho. */
.co-cat-caja { flex: 0 0 13.5rem; display: flex; gap: .4rem; align-items: center; }
/* El OK se va a apretar cientos de veces: no puede gritar, pero tiene que verse
   que está ahí y que falta. */
.co-ok { font: inherit; font-size: var(--fs-100); font-weight: 600; cursor: pointer;
         padding: .1rem .45rem; border-radius: 999px; border: 1px solid var(--border);
         background: var(--surface); color: var(--text-2); }
.co-ok:hover { border-color: var(--ok-fg); color: var(--ok-fg); }
.co-ok-hecho { border-color: var(--ok-bd); background: var(--ok-bg); color: var(--ok-fg); }
.co-ok[disabled] { opacity: .5; cursor: default; }
/* El 3/13 del evento con su barrita: cuánto falta por revisar, de un vistazo. */
.co-cuenta { font-variant-numeric: tabular-nums; font-size: var(--fs-200); }
.co-cuenta-ok { color: var(--ok-fg); font-weight: 600; }
.co-mini { display: block; height: 4px; margin-top: .2rem; border-radius: 2px;
           background: var(--surface-alt); border: 1px solid var(--border); overflow: hidden; }
.co-mini > span { display: block; height: 100%; background: var(--ok-fg); }

/* ── Tablero de etapas y colas de revisión ─────────────────────────── */
/* EN TRES COLUMNAS. Una debajo de otra ocupaba media pantalla antes de llegar
   al primer dato, y este tablero es para mirarse de reojo, no para leerse. En
   pantalla angosta vuelven a apilarse solas. */
.co-etapas { display: grid; gap: var(--sp-3);
             grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
/* CADA ETAPA ES UNA TARJETA, con su aire. Antes no tenía caja propia y el único
   recuadro que se veía venía de un CHOQUE DE NOMBRES: el modificador de «etapa
   terminada» se llamaba .co-ok, que es también el botón OK de categorías, así
   que la etapa heredaba una píldora con borde redondo y sin márgenes. Se
   renombró a .co-etapa-lista. Ojo con los nombres cortos y genéricos: dos cosas
   distintas llamadas igual se pisan sin avisar. */
.co-etapa { border: 1px solid var(--border); border-radius: var(--r);
            padding: var(--sp-3) var(--sp-4); background: var(--surface); }
.co-etapa-lista { border-color: var(--ok-bd); background: var(--ok-bg); }
.co-etapa-t { font-size: var(--fs-200); margin-bottom: var(--sp-2);
              display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.co-etapa-p { font-size: var(--fs-100); color: var(--text-3); margin-top: var(--sp-2); }
.co-barra-fondo { height: 8px; border-radius: 4px; background: var(--surface-alt);
                  border: 1px solid var(--border); overflow: hidden; }
.co-barra-llena { height: 100%; background: var(--warn-fg); }
.co-etapa-lista .co-barra-llena { background: var(--ok-fg); }
/* Sobre el fondo verde de la etapa terminada, el canal de la barra en blanco
   para que el 100% se lea como lleno y no como un bloque de color. */
.co-etapa-lista .co-barra-fondo { background: var(--surface); border-color: var(--ok-bd); }
/* LAS COLAS DE REVISIÓN MANDAN: mientras tengan renglones, el mes no cierra. */
/* El sobre: el correo se ve dentro de un iframe para que sus estilos en línea
   no se mezclen con los de la app —ni al revés—, que es la única forma de que
   el borrador sea de verdad lo que va a llegar. */
.co-sobre { width: 100%; height: 780px; border: 1px solid var(--border);
            border-radius: var(--r-sm); background: #fff; display: block; }
.co-texto { white-space: pre-wrap; font-size: var(--fs-200); color: var(--text-2);
            margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* DIRECTORIO DE PERSONAS.
   Una lista de doscientos renglones que se capturan del tirón, así que manda
   la densidad: campos que no parezcan cajas hasta que se tocan, y el estado
   del guardado como una línea de color bajo el campo, sin ocupar columna. */
.pe-ayuda { display: grid; grid-template-columns: 130px 1fr; gap: var(--sp-2) var(--sp-4);
            margin: 0; align-items: baseline; }
.pe-ayuda dt { font-weight: 600; font-size: var(--fs-200); text-transform: uppercase;
               letter-spacing: .04em; color: var(--text-3); }
.pe-ayuda dd { margin: 0; font-size: var(--fs-300); color: var(--text-2); max-width: 82ch; }
.pe-ayuda dd + dt { border-top: 1px solid var(--border); padding-top: var(--sp-2); }
.pe-ayuda dd:not(:last-child) { border-bottom: 1px solid transparent; padding-bottom: var(--sp-1); }
@media (max-width: 720px) { .pe-ayuda { grid-template-columns: 1fr; gap: var(--sp-1); } }

/* El campo se ve como texto hasta que se enfoca: con doscientos renglones,
   cuatrocientas cajas con borde son una reja. */
/* ⚠️ Va con `.pe-fila` delante a propósito. El selector global de campos es
   input[type="text"], input[type="email"]… y pesa más que una sola clase: sin
   esto las reglas de abajo no pintan nada y la tabla sigue siendo una reja. */
.pe-fila .pe-edit { width: 100%; height: auto; min-height: 0;
                    border: 1px solid transparent; background: transparent;
                    border-radius: var(--r-sm); padding: 3px 6px;
                    font: inherit; color: inherit; }
.pe-fila .pe-edit:hover  { border-color: var(--border); background: var(--surface); }
.pe-fila .pe-edit:focus  { border-color: var(--info-fg); background: var(--surface); outline: none; }
.pe-fila .pe-edit::placeholder { color: var(--text-3); font-style: italic; }

/* El estado del guardado, en la línea de abajo del campo. Mismos nombres que
   usa Planeación para lo mismo (.guardando/.guardado/.sin-guardar). */
.pe-fila .pe-edit.guardando   { box-shadow: inset 0 -2px 0 var(--warn-fg); }
.pe-fila .pe-edit.guardado    { box-shadow: inset 0 -2px 0 var(--ok-fg); }
.pe-fila .pe-edit.sin-guardar { box-shadow: inset 0 -2px 0 var(--err-fg);
                                background: var(--err-bg); border-color: var(--err-bd); }

.pe-fila > td { padding-top: 4px; padding-bottom: 4px; vertical-align: middle; }
.pe-llaves { line-height: 1.9; }
.pe-baja > td { opacity: .5; }
.pe-sw { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.pe-sw span { font-size: var(--fs-200); color: var(--text-3); }

/* P0 · Pendientes: una tarjeta por TIPO, con sus personas dentro.
   El color lo pone la clase semántica del tipo (co-tono-err, -warn, -info) y
   no un hex: lo que decide el tono es cuánto bloquea el cierre. */
.co-tipo { border-left: 4px solid var(--border); padding-left: var(--sp-4); }
.co-tono-err  { border-left-color: var(--err-fg);  }
.co-tono-warn { border-left-color: var(--warn-fg); }
.co-tono-info { border-left-color: var(--info-fg); }
.co-tono-mut  { border-left-color: var(--mut-fg);  }

.co-tipo-cab { display: flex; align-items: flex-start; justify-content: space-between;
               gap: var(--sp-4); }
.co-tipo-cab h3 { margin: 0; }
.co-tipo-pide { margin: 2px 0 0; font-size: var(--fs-300); color: var(--text-2); }
.co-tipo-nota { margin: var(--sp-2) 0 var(--sp-3); font-size: var(--fs-300);
                color: var(--text-3); max-width: 78ch; }

/* Las dos cifras del encabezado: el conteo y el dinero, alineados a la derecha
   y del mismo tamaño para que se lean de un vistazo sin competir con el
   título. */
.co-tipo-cifras { display: flex; gap: var(--sp-6); text-align: right; flex: none; }
.co-tipo-cifras strong { display: block; font-size: var(--fs-600); line-height: 1.1; }
.co-tipo-cifras span { font-size: var(--fs-100); color: var(--text-3);
                       text-transform: uppercase; letter-spacing: .04em; }

/* La persona dentro del tipo: es una tarjeta más chica y sin sombra, para que
   se lea como parte del bloque y no como otra tarjeta suelta. */
.co-persona { background: var(--surface-alt); border: 1px solid var(--border);
              border-radius: var(--r-sm); padding: var(--sp-3); box-shadow: none; }
.co-persona + .co-persona { margin-top: var(--sp-2); }
.co-persona .ev-nom { font-weight: 600; }
.co-persona .ev-folio { color: var(--text-3); font-weight: 400; }
.co-persona .ev-cuerpo { border-top-color: var(--border); }

.co-cola { border-left: 4px solid var(--err-fg); }
.co-cola h3 { margin-top: 0; }
.co-dos { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }
.co-vs  { color: var(--text-3); font-size: var(--fs-100); }
/* Las dos decisiones de un renglón, lado a lado y pegadas a la derecha. Sin
   esto se apilan y la fila crece al doble. */
.co-acc { display: flex; gap: var(--sp-1); justify-content: flex-end; flex-wrap: nowrap; }
.co-acc .btn { white-space: nowrap; }

/* ── Notas de regla y varios ───────────────────────────────────────── */
/* La explicación de qué entra y qué no va plegada: es larga a propósito —cada
   renglón costó una verificación contra los datos— y quien ya la leyó una vez
   no necesita volver a verla cada que abre la pantalla. */
.co-regla { font-size: var(--fs-200); color: var(--text-2); }
.co-regla > summary { cursor: pointer; font-weight: 600; color: var(--text-1); }
.co-regla[open] > summary { margin-bottom: var(--sp-2); }
.co-regla table { margin-top: var(--sp-3); }
.co-lista, .co-regla ul { margin: var(--sp-2) 0 0; padding-left: 1.1rem; }
.co-lista li, .co-regla li { font-size: var(--fs-200); color: var(--text-2); margin: var(--sp-1) 0; }
/* La barra de acciones vive pegada abajo y sólo aparece con algo seleccionado:
   una barra siempre visible roba alto de pantalla en una tabla de 400 filas. */
.co-barra { position: sticky; bottom: 0; z-index: 5; display: flex; gap: .5rem;
            align-items: center; padding: .6rem var(--sp-4); background: var(--surface);
            border-top: 2px solid var(--border); box-shadow: var(--sombra-2); }
.co-oculto { display: none; }
/* EL AIRE ENTRE BLOQUES, DE UNA VEZ Y PARA TODOS.
   Esto empezó como una lista de pares —card+card, card+resumen…— y esa forma
   falla por omisión: el día que aparece un vecino nuevo que no está en la lista,
   el hueco se va a cero sin que nada truene. Pasó dos veces el 19-sep-2026, la
   segunda entre el bloque de etapas y las tarjetas de cifra. Un hermano tras
   otro lleva aire, y punto; quien necesite otra cosa lo dice después.
   Va acotado al módulo: como regla global le cambiaría el espaciado a las otras
   treinta pantallas de la app, que hoy lo resuelven cada una. */
.mod-costeo > * + * { margin-top: var(--sp-4); }
/* .resumen trae margin-top negativo porque en el molde va pegada a los chips,
   que ya dejan su aire debajo. Aquí no hay chips, así que se le quita. */
.mod-costeo > .resumen { margin-top: var(--sp-4); margin-bottom: var(--sp-3); }

/* .sub es «dato secundario» y app.css lo define dentro de .tabla, que es donde
   lo usa el molde B. En prosa —una nota bajo un título de tarjeta— hace falta
   el mismo trato, o el pie se lee igual de fuerte que el dato principal. Va en
   fs-200 y no fs-100: un párrafo al tamaño de una celda no se lee. */
.mod-costeo p.sub, .mod-costeo .card > .sub,
.co-regla .sub, .alert .sub { font-size: var(--fs-200); color: var(--text-2); }

/* El detalle de un pago usa el molde D del drawer, pero sus datos vienen en
   <dl>/<dt>/<dd> y no en <div><span><strong>. Misma rejilla, otro elemento. */
.co-datos { display: grid; grid-template-columns: max-content 1fr; gap: .25rem 1rem; }
.co-datos dt { color: var(--text-2); }
.co-datos dd { margin: 0; text-align: left; }
/* El renglón que nadie ha firmado se ve: normalmente es la razón de que el pago
   completo siga en SOLICITADO, y el dueño de esa cuenta es a quién ir a buscar. */
.co-falta td { background: var(--err-bg); }

/* .co-chk y .co-chk-grupo no llevan estilo a propósito: son ganchos de JS para
   la selección múltiple del paso 1. Se documentan aquí para que nadie los
   borre creyendo que son clases muertas. */

/* Teñir una FILA es distinto de ponerle una etiqueta. `.et` es inline-block con
   borde y padding: aplicada a un <tr> le rompe la caja a la fila entera, y así
   quedó la tabla de categorías el 18-sep-2026. Para la fila, esto. */
.co-fila-falta > td { background: var(--warn-bg); }

/* Fila que abre un panel al hacer clic en CUALQUIER parte de ella. Distinta de
   .co-abre, que despliega sus hijos ahí mismo. Rafael la pidió así el
   19-sep-2026: apuntarle a una palabra en una tabla de cientos de renglones
   cansa, y la fila entera es un blanco que no se falla. El enlace del folio
   sigue funcionando: el manejador del drawer descarta los controles que viven
   dentro del disparador. */
.co-abre-fila { cursor: pointer; }
.co-abre-fila:hover > td { background: var(--surface-captura); }
.co-abre-fila:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }

/* El renglón de una CATEGORÍA DEL COSTEO, con su explicación al lado.
   La explicación va EN LA MISMA LÍNEA y en minúsculas: dentro de un <th> hereda
   `text-transform: uppercase` del sistema, y una frase larga en mayúsculas
   partida en dos renglones ocupa el doble y se lee la mitad de bien. */
.co-rubro > th { background: var(--surface-alt); border-top: 2px solid var(--border); }
.co-rubro .co-rubro-t { font-size: var(--fs-200); }
/* El flex va en un DIV dentro de la celda, nunca en el <th>: un th convertido
   en contenedor flex sale del algoritmo de columnas de la tabla y le rompe el
   ancho a todas. Pasó el 19-sep-2026 — la fila creció a 185px de alto. */
.co-rubro-cab { display: flex; align-items: baseline; gap: var(--sp-2); }
.co-rubro .co-rubro-t { flex: 0 0 auto; }
/* La nota cede el espacio: se recorta antes que empujar la tabla fuera de la
   pantalla, y el texto completo vive en el title. */
.co-rubro .co-rubro-n {
  text-transform: none; letter-spacing: 0; font-weight: 400;
  font-size: var(--fs-100); color: var(--text-3);
  flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  /* El tope va en ch y no en píxeles: la tabla usa ancho automático, así que sin
     un límite duro la columna crece con el texto y `text-overflow` nunca llega a
     aplicarse — la nota no se recorta, ensancha la tabla. */
  max-width: 52ch;
}

/* La categoría del costeo va en MAYÚSCULAS también en el detalle, para que la
   columna se lea como una sola cosa. Se hace con CSS y no tocando el texto: el
   nombre guardado es el que después se compara contra el archivo de Ángel. */
.co-rubro-d { text-transform: uppercase; letter-spacing: .3px; }
/* El IVA, debajo de su monto. Tenue y alineado a la derecha como la cifra a la
   que pertenece: es un dato de apoyo, no compite con el total. */
.co-iva { font-size: var(--fs-100); color: var(--text-3); font-weight: 400;
          text-transform: none; letter-spacing: 0; margin-top: 1px; }

/* La fila que se va porque ya se decidió. Se desvanece en vez de desaparecer de
   golpe: con cien renglones, algo que se esfuma sin aviso se siente como un
   error, y esto deja ver CUÁL se fue. */
.co-sale { transition: opacity .35s, transform .35s; opacity: 0; transform: translateX(1.5rem); }

/* EL PANEL PARA ELEGIR ENTRE DOS EVENTOS. Pequeño a propósito: es una pregunta
   de una línea con dos respuestas, no una pantalla. */
/* El centrado se escribe: en cuanto un <dialog> modal lleva max-width propio,
   deja de heredar el `margin:auto` del navegador y se va a la esquina. */
.co-elegir { border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--sp-6);
             width: min(34rem, calc(100vw - 2rem)); margin: auto;
             background: var(--surface); color: var(--text-1); box-shadow: var(--sombra-3); }
.co-elegir::backdrop { background: rgba(0,0,0,.35); }
.co-elegir h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-400); }
.co-elegir > .sub { display: block; margin-bottom: var(--sp-4); }
/* LAS DOS OPCIONES, LADO A LADO. Se está comparando una contra otra —«¿este o
   este?»— y en vertical eso se lee como una lista, no como una disyuntiva. En
   pantalla angosta vuelven a apilarse solas. */
.co-elegir-ops { display: grid; gap: var(--sp-3);
                 grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
.co-elegir-op { border: 1px solid var(--border); border-radius: var(--r);
                display: flex; flex-direction: column; align-items: stretch;
                padding-bottom: var(--sp-2); }
.co-elegir-op.on { border-color: var(--ok-bd); background: var(--ok-bg); }
.co-elegir-op:hover { border-color: var(--foco); }
/* La opción completa es el blanco del clic, no una palabra dentro de ella. */
.co-elegir-pick { flex: 1; text-align: left; font: inherit; cursor: pointer;
                  background: none; border: 0; padding: var(--sp-3) var(--sp-4);
                  display: grid; gap: 2px; }
/* El folio y el código son los dos datos que se comparan: los dos grandes y
   juntos, no uno de título y otro en la letra chica. */
.co-elegir-llave { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.co-elegir-folio { font-size: var(--fs-500); font-weight: 700;
                   font-variant-numeric: tabular-nums; line-height: 1; }
.co-elegir-cod { font-size: var(--fs-300); font-weight: 600; color: var(--text-2);
                 font-variant-numeric: tabular-nums; }
.co-elegir-ev  { font-size: var(--fs-200); }
.co-elegir-ver { font-size: var(--fs-100); white-space: nowrap;
                 padding: 0 var(--sp-4) var(--sp-1); }
.co-elegir-pie { display: flex; justify-content: flex-end; margin-top: var(--sp-4); }

/* ═══════════════════════════════════════════════════════════════════════════
   STOCK MÍNIMO
   ═══════════════════════════════════════════════════════════════════════════ */

/* El drawer de un producto en DOS COLUMNAS: a la izquierda lo que se lee (foto,
   existencias, comportamiento), a la derecha lo que se escribe. Nace porque la
   captura quedaba debajo del pliegue y había que hacer scroll para llegar a
   ella cada vez — con 1,433 productos que revisar, ese scroll se paga 1,433
   veces. Pide el panel ancho (data-drawer-ancho="grande", 1120 px).

   Por debajo de 900 px vuelve a una sola columna: en el panel angosto y en el
   teléfono, dos columnas dejarían los campos a 180 px. */
.sm-dos { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--sp-8); align-items: start; }
.sm-dos > * { min-width: 0; }
@media (max-width: 900px) { .sm-dos { grid-template-columns: 1fr; } }

/* La columna de captura se queda a la vista aunque la izquierda sea más larga:
   lo que se escribe no debería depender de qué tanto hay que leer. */
.sm-cap-col { position: sticky; top: 0; }

/* Avance de revisión. Va en el renglón de cada familia y en la línea de
   resumen. Es barra Y número a propósito: la barra se lee de reojo al bajar,
   el número es el que se reporta. */
.sm-prog { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-100); color: var(--text-2); font-weight: 400; }
.sm-prog-b { width: 64px; height: 5px; border-radius: var(--r-full); background: var(--n-200); overflow: hidden; flex-shrink: 0; }
.sm-prog-b > i { display: block; height: 100%; background: var(--ok-punto); border-radius: var(--r-full); }
.sm-prog.lleno .sm-prog-b > i { background: var(--ok-punto); }
.sm-prog.cero  { color: var(--text-3); }

/* La letra de prioridad. Cuadrada y del mismo ancho las tres, para que la
   columna se lea como una columna y no como texto suelto. */
.sm-pri { display: inline-block; min-width: 18px; text-align: center; font-weight: 700;
          font-size: var(--fs-100); line-height: 16px; border-radius: var(--r-sm); border: 1px solid; }
.sm-pri-A { background: var(--err-bg);  color: var(--err-fg);  border-color: var(--err-fg); }
.sm-pri-B { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-fg); }
.sm-pri-C { background: var(--mut-bg);  color: var(--text-2);  border-color: var(--border); }

/* Tira de clasificación del producto, bajo la franja del drawer. La prioridad
   NO cabe dentro de .dr-datos: esa rejilla alinea el valor a la derecha contra
   el borde —la insignia se cortaba— y su regla `.dr-datos span` le pisa el
   color. Además es una clasificación de todo el producto, no un dato más entre
   ocho, así que cruzar las dos columnas es lo que le corresponde. */
.sm-tira { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
           font-size: var(--fs-200); color: var(--text-2);
           padding: var(--sp-2) 0 var(--sp-3); border-bottom: 1px solid var(--border-sutil);
           margin-bottom: var(--sp-3); }
.sm-tira b { color: var(--text-1); }

/* La foto del producto: reconocer cuál es, no admirarla. A 240 px de alto se
   comía un cuarto de la columna izquierda y empujaba la captura fuera de
   pantalla — que es justo lo que el drawer ancho venía a resolver. */
.sm-foto { text-align: center; margin-bottom: var(--sp-3); }
.sm-foto img { max-width: 100%; max-height: 120px; border-radius: var(--r);
               border: 1px solid var(--border); }

/* Dentro de las dos columnas los bloques van más apretados: son la mitad de
   ancho que un drawer normal, y el aire que ahí se agradece aquí cuesta
   scroll. */
.sm-dos .dr-bloque { padding-bottom: var(--sp-3); margin-bottom: var(--sp-3); }
.sm-dos .dr-datos  { gap: 5px 14px; }
.sm-dos .dr-datos > div { min-width: 0; }
.sm-dos .dr-datos strong { min-width: 0; overflow-wrap: anywhere; }
.sm-cap-col .fg { margin-bottom: var(--sp-3); }

/* .dr-cap sangra a los bordes del drawer con un margen negativo de --dr-lado.
   En una sola columna eso es justo lo que se quiere; en dos, ese margen mete el
   bloque crema 14 px DENTRO de la columna izquierda y pinta encima del valor de
   los pares etiqueta/valor —«Sugerido (p90) 206» se veía cortado a media cifra
   (medido el 19-sep-2026: la columna termina en 775 px y el crema empezaba en
   761). A la derecha sí conserva la sangría, que es el borde del panel. */
.sm-cap-col .dr-cap { margin-left: 0; }

/* El canal entre las dos mitades, con una línea que las separa de verdad.
   Antes iba `gap: 0 var(--sp-5)` y --sp-5 NO EXISTE en la rampa de Master
   (05·1·2·3·4·6·8·12): la declaración era inválida, el hueco colapsaba a cero y
   los valores de la izquierda quedaban pegados al bloque crema. El borde no es
   decoración — marca dónde termina lo que se lee y empieza lo que se escribe. */
.sm-dos > .sm-cap-col { border-left: 1px solid var(--border); padding-left: var(--sp-6); }
@media (max-width: 900px) {
  .sm-dos > .sm-cap-col { border-left: 0; padding-left: 0; padding-top: var(--sp-4);
                          border-top: 1px solid var(--border); }
}

/* La cabecera del drawer de un producto: las tres cifras que se aprueban.
   Van grandes y juntas porque es lo único que esta persona tiene que decidir;
   todo lo demás de la pantalla existe para sostener estos tres números. */
.sm-cabeza { display: flex; align-items: flex-start; gap: var(--sp-6); flex-wrap: wrap;
             padding: var(--sp-3) 0 var(--sp-4); }
.sm-num { text-align: center; min-width: 62px; }
.sm-num-v { display: block; font-size: var(--fs-700); font-weight: 700; line-height: 1.1;
            color: var(--text-1); font-variant-numeric: tabular-nums; }
.sm-num-l { display: block; font-size: var(--fs-100); color: var(--text-2);
            text-transform: uppercase; letter-spacing: .04em; margin-top: 2px; }
.sm-num.mal .sm-num-v { color: var(--err-fg); }
.sm-cab-txt { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.sm-cab-txt > .sub { flex-basis: 100%; }

/* Los renglones de explicación: frase a la izquierda, cifra a la derecha.
   No es .dr-datos —esa rejilla es de pares etiqueta/valor cortos— porque aquí
   la izquierda es una ORACIÓN («un día normal te piden»), y eso es lo que hace
   que alguien de Comercial entienda el número sin que nadie se lo explique. */
.sm-expl { width: 100%; border-collapse: collapse; font-size: var(--fs-200); }
.sm-expl td { padding: 6px 0; border-bottom: 1px solid var(--border-sutil); vertical-align: baseline; }
.sm-expl td:first-child { color: var(--text-2); padding-right: var(--sp-4); }
.sm-expl td:last-child  { text-align: right; font-weight: 700; color: var(--text-1);
                          white-space: nowrap; font-variant-numeric: tabular-nums; }
.sm-expl td .sub { display: block; font-weight: 400; }
.sm-expl tr:last-child td { border-bottom: 0; }
.sm-expl .sm-clave td { background: var(--n-100); font-size: var(--fs-300); }
.sm-expl .sm-mal td:last-child { color: var(--err-fg); }

/* La matriz ABC-XYZ: el mapa del ejercicio de stock mínimo. Plegable porque se
   consulta al empezar y estorba después. Cada celda es un enlace-filtro. */
.sm-matriz { padding: 0; margin-bottom: var(--sp-3); }
.sm-matriz > summary { padding: var(--sp-3) var(--sp-4); cursor: pointer; font-size: var(--fs-300); font-weight: 700; }
.sm-matriz > summary .sub { font-weight: 400; }
.sm-mx-cuerpo { padding: 0 var(--sp-4) var(--sp-4); }
.sm-mx { width: 100%; border-collapse: separate; border-spacing: 4px; table-layout: fixed; }
.sm-mx thead th { font-size: var(--fs-100); color: var(--text-2); font-weight: 600;
                  text-transform: uppercase; letter-spacing: .04em; padding-bottom: 2px; }
.sm-mx thead th span { font-weight: 400; text-transform: none; letter-spacing: 0; }
.sm-mx tbody th { width: 96px; text-align: left; font-size: var(--fs-100); color: var(--text-2);
                  font-weight: 400; vertical-align: middle; }
.sm-mx tbody th span:last-child { display: block; margin-top: 2px; }
.sm-mx td { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); }
.sm-mx td a { display: block; padding: var(--sp-2) var(--sp-3); color: inherit; }
.sm-mx td a:hover { text-decoration: none; }
.sm-mx td:hover { border-color: var(--info-fg); }
.sm-mx td.on { border-color: var(--n-900); box-shadow: inset 0 0 0 1px var(--n-900); }
.sm-mx td.vacio { opacity: .5; }
.sm-mx .n { font-size: var(--fs-500); font-weight: 700; color: var(--text-1);
            font-variant-numeric: tabular-nums; margin-right: 6px; }
.sm-mx .p { font-size: var(--fs-100); color: var(--text-2); }
.sm-mx .d { display: block; font-size: var(--fs-100); color: var(--text-3); margin-top: 3px; line-height: 1.35; }
@media (max-width: 760px) { .sm-mx .d { display: none; } }

/* La letra XYZ al lado de la ABC. Más discreta que la de prioridad a
   propósito: la primera ordena la lista, ésta matiza cómo leerla. */
.sm-xyz { display: inline-block; min-width: 15px; margin-left: 3px; text-align: center;
          font-size: var(--fs-100); font-weight: 700; line-height: 16px; color: var(--text-2);
          border: 1px dashed var(--border-fuerte); border-radius: var(--r-sm); }

/* La foto, en la cabecera. Reconocer el producto es lo primero que uno hace al
   abrir el panel, no algo que se busca a media lectura — y ahí aprovecha el
   ancho que las tres cifras dejaban en blanco. En la columna izquierda ocupaba
   un bloque entero y la desbalanceaba contra la de captura. */
.sm-foto-cab { margin-left: auto; flex-shrink: 0; }
.sm-foto-cab img { max-height: 104px; max-width: 160px; border-radius: var(--r);
                   border: 1px solid var(--border); display: block; }
@media (max-width: 760px) { .sm-foto-cab { display: none; } }

/* Marca de producto reciente. Dos clases porque NO se deciden igual: una
   colección nueva entra fuerte a la lista de compra; una compra hecha para un
   cliente puntual casi nunca debe repetirse. */
.sm-nuevo { display: inline-block; font-size: var(--fs-100); font-weight: 700;
            padding: 1px 7px; border-radius: var(--r-full); border: 1px solid; }
.sm-nuevo-coleccion { background: var(--info-bg); color: var(--info-fg); border-color: var(--info-fg); }
.sm-nuevo-puntual   { background: var(--mut-bg);  color: var(--text-2);  border-color: var(--border-fuerte); }

/* Pantalla de ambientes (inicio.php): las fichas centradas y más grandes que
   las de un hub de catálogos — es la puerta de entrada, no un submenú. */
.amb-portal { max-width: 960px; margin: var(--sp-6) auto 0; }
.amb-portal .hub-cat { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.amb-portal .hub-cat-t { padding: var(--sp-6) var(--sp-6) calc(var(--sp-6) * 1.5); }
.amb-portal .hub-cat-ic { font-size: 40px; }
.amb-portal .hub-cat-h  { font-size: var(--fs-500, 1.25rem); }
.app-shell.sin-menu .main-content { margin-left: 0; }

/* ── Botón de ícono (9-oct-2026) ──
   Para las acciones de un renglón de tabla: cuadrado, con su nombre en el
   title (al pasar el cursor) y en aria-label (lectores de pantalla). Tres
   botones con texto partían el renglón en dos filas. El ícono es SVG en línea
   con currentColor, así hereda el color del botón. */
.btn-ico { display: inline-flex; align-items: center; justify-content: center;
           width: 30px; height: 30px; padding: 0; border-radius: var(--r-sm, 6px);
           border: 1px solid var(--border); background: var(--surface); color: var(--text-2);
           cursor: pointer; transition: background .15s, color .15s, border-color .15s; }
.btn-ico:hover { background: var(--n-100); color: var(--text-1); border-color: var(--text-3); text-decoration: none; }
.btn-ico svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2;
               stroke-linecap: round; stroke-linejoin: round; }
.btn-ico.primario { background: var(--n-900); border-color: var(--n-900); color: #fff; }
.btn-ico.primario:hover { background: var(--n-700, #333); color: #fff; }
.btn-ico.peligro:hover { color: var(--alerta-fg, #b42318); border-color: var(--alerta-fg, #b42318); background: var(--surface); }
.acciones-ico { display: flex; gap: 6px; flex-wrap: nowrap; align-items: center; }

/* Rótulo de grupo en el menú lateral (REPORTES, CONFIGURACIÓN): separa los
   submenús en bloques. Más chico y más tenue que un submenú, con aire arriba
   y una raya, para que se lea como encabezado y no como algo que se abre. */
.sidebar-nav .nav-grupo {
  margin-top: var(--sp-5, 20px);
  padding: 6px var(--sp-4, 16px) 4px;
  border-top: 1px solid rgba(255,255,255,.14);
  font-size: 10px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255,255,255,.38);
}

/* ═══ FINANCIERO · Solicitud de pago (drawer ancho o página) ═══════════════
   Rafael, 9-oct-2026: «más bonita, compacta, con colores para los estatus».
   Cabecera con quién/cuánto/etapa, pasos del ciclo en color, campos en
   rejilla de 4 y, en consulta, los campos se leen como ficha (sin cajas).   */
.sol-cab { display: flex; justify-content: space-between; gap: 16px; align-items: flex-start;
  padding: 14px 16px; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface);
  box-shadow: var(--sombra-1); margin-bottom: 10px; }
.sol-cab-linea { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-bottom: 6px; }
.sol-folio { font-family: var(--fuente-num); font-weight: 700; font-size: var(--fs-400); margin-right: 4px; }
.sol-chip { font-size: 10.5px; padding: 2px 8px; border-radius: var(--r-full); background: var(--n-100); color: var(--text-2); }
.sol-estatus { font-size: 11px !important; font-weight: 700; padding: 2px 10px; }
.sol-prov-nombre { font-size: 16px; font-weight: 700; line-height: 1.25; }
.sol-cab-der { text-align: right; white-space: nowrap; }
.sol-monto { font-family: var(--fuente-num); font-size: 24px; font-weight: 700; line-height: 1.1; }
.sol-monto small { font-size: 12px; color: var(--text-2); margin-left: 3px; }

.sol-pasos { display: flex; list-style: none; margin: 0 0 12px; padding: 0; gap: 0; }
.sol-pasos li { flex: 1; display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--text-3);
  padding: 6px 8px; border-bottom: 3px solid var(--n-100); white-space: nowrap; }
.sol-pasos .pt { width: 18px; height: 18px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; background: var(--n-100); color: var(--text-3); flex: none; }
.sol-pasos li.hecho { color: var(--ok-fg); border-bottom-color: var(--ok-bd); }
.sol-pasos li.hecho .pt { background: var(--ok-fg); color: #fff; }
.sol-pasos li.aqui { font-weight: 700; background: none; }
.sol-pasos li.aqui.et-mut  { color: var(--mut-fg);  border-bottom-color: var(--mut-fg); }
.sol-pasos li.aqui.et-warn { color: var(--warn-fg); border-bottom-color: var(--warn-fg); }
.sol-pasos li.aqui.et-info { color: var(--info-fg); border-bottom-color: var(--info-fg); }
.sol-pasos li.aqui.et-alt  { color: var(--alt-fg);  border-bottom-color: var(--alt-fg); }
.sol-pasos li.aqui.et-ok   { color: var(--ok-fg);   border-bottom-color: var(--ok-fg); }
.sol-pasos li.aqui .pt { background: currentColor; }
.sol-pasos li.aqui .pt { color: #fff; }
.sol-pasos li.aqui.et-mut .pt  { background: var(--mut-fg); }
.sol-pasos li.aqui.et-warn .pt { background: var(--warn-fg); }
.sol-pasos li.aqui.et-info .pt { background: var(--info-fg); }
.sol-pasos li.aqui.et-alt .pt  { background: var(--alt-fg); }
.sol-pasos li.aqui.et-ok .pt   { background: var(--ok-fg); }

.sol-aviso { border: 1px solid var(--border); border-left: 4px solid var(--info-fg); background: var(--info-bg);
  border-radius: 8px; padding: 8px 12px; margin-bottom: 10px; font-size: 12.5px; color: var(--text-2); }
.sol-aviso b:first-child { display: block; color: var(--text-1); margin-bottom: 2px; }
.sol-aviso.alerta { border-left-color: var(--err-fg); background: var(--err-bg); }
.sol-aviso.aviso  { border-left-color: var(--warn-fg); background: var(--warn-bg); }

.sol-campos { border: 0; padding: 0; margin: 0; min-width: 0; }
.sol-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: 14px 16px 6px; margin-bottom: 10px; box-shadow: var(--sombra-1); }
.sol-card > h4 { display: flex; align-items: center; gap: 8px; font-size: var(--fs-300); font-weight: 700; margin: 0 0 12px; }
.sol-card > h4 .n { width: 20px; height: 20px; border-radius: 6px; background: var(--n-900); color: #fff;
  font-size: 11px; display: inline-flex; align-items: center; justify-content: center; }
.sol-card .fs-ay { font-size: var(--fs-200); color: var(--text-2); margin: -6px 0 10px; }
.sol-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0 12px; }
.sol-grid .c2 { grid-column: span 2; } .sol-grid .c4 { grid-column: 1 / -1; }
.sol-grid .fg { margin-bottom: 10px; }
.sol-grid textarea { min-height: 54px; }
#sol-form input.num { text-align: right; font-variant-numeric: tabular-nums; }
.sol-total input { font-weight: 700; }
.sol-uuid { margin: -4px 0 10px; } .sol-uuid span { font-family: var(--mono, monospace); }

.sol-archivos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-bottom: 12px; }
.sol-arch { border: 1px dashed var(--n-300, #ccc); border-radius: 8px; padding: 8px 10px; background: var(--n-25, #fafaf8); min-width: 0; }
.sol-arch.mal { border-color: var(--err-fg); background: var(--err-bg); }
.sol-arch .t { font-size: 11px; font-weight: 700; color: var(--text-2); margin-bottom: 4px; }
.sol-arch .f { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 3px; }
.sol-arch input[type=file] { font-size: 11px; width: 100%; }

.sol-bitacora { padding-bottom: 12px; } .sol-bitacora summary { cursor: pointer; font-weight: 700; font-size: var(--fs-300); }

.sol-res-total { display: flex; justify-content: space-between; align-items: baseline; padding-bottom: 8px; margin-bottom: 6px; border-bottom: 1px solid var(--border); }
.sol-res-total span { font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--text-2); font-weight: 700; }
.sol-res-total strong { font-family: var(--fuente-num); font-size: 20px; }
.sol-res-total strong.mal { color: var(--err-fg); }
.sol-firma { display: flex; align-items: center; gap: 8px; font-size: 12px; margin: 5px 0; }
.sol-firma > span:nth-child(2) { flex: 1; min-width: 0; }
.sol-firma .et { font-size: 9.5px; }
.sol-firma .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.sol-firma .dot.ok { background: var(--ok-fg); } .sol-firma .dot.pend { background: var(--warn-fg); }
.sol-faltan { margin: 0; padding-left: 16px; font-size: 12px; color: var(--err-fg); }
.sol-faltan li { margin: 2px 0; }
.sol-faltan li.listo { color: var(--ok-fg); list-style: none; margin-left: -16px; font-weight: 700; }

/* Consulta (ya no se edita): los campos se leen como ficha, sin cajas. */
#sol-form.solo-lectura fieldset[disabled] :is(input, select, textarea) {
  border-color: transparent; background: transparent; color: var(--text-1); padding-left: 0; padding-right: 0;
  box-shadow: none; resize: none; opacity: 1; -webkit-text-fill-color: var(--text-1); }
#sol-form.solo-lectura fieldset[disabled] select { background-image: none; }
#sol-form.solo-lectura fieldset[disabled] textarea { min-height: 0; }
#sol-form.solo-lectura .sol-grid .fg > label { margin-bottom: 0; }
#sol-form.solo-lectura .r-costeo .costeo-caja { background: transparent; }

/* Dentro del drawer, el panel de resumen se pega al borde de arriba del drawer. */
.dw-cuerpo .sol-lienzo { grid-template-columns: minmax(0, 1fr) 290px; }
.dw-cuerpo .sol-panel { top: 0; max-height: calc(100vh - 90px); }
@media (max-width: 900px) {
  .sol-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sol-archivos { grid-template-columns: 1fr; }
  .dw-cuerpo .sol-lienzo { grid-template-columns: minmax(0, 1fr); }
}
/* (Lo que vivía en el <style> de la página vieja: dentro del drawer tiene que
   estar en la hoja global.) */
.sol-tabla td { vertical-align: top; }
.sol-tabla select, .sol-tabla input { width: 100%; }
.sol-res { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: 12px; color: var(--text-2); margin: 4px 0; }
.sol-res > span:first-child { min-width: 0; }
.sol-res .calc { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--text-1); }
.sol-res .calc.mal { color: var(--err-fg); }
.sol-sug { position: absolute; z-index: 20; left: 0; right: 0; background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; box-shadow: 0 8px 20px rgba(0,0,0,.12); max-height: 260px; overflow-y: auto; }
.sol-sug button { display: block; width: 100%; text-align: left; padding: 6px 10px; border: 0; background: none; font: inherit; font-size: 12px; cursor: pointer; }
.sol-sug button:hover, .sol-sug button:focus { background: var(--n-100); }
.sol-sug .sub { display: block; }
#sol-form .de-xml[readonly] { background: var(--n-25); color: var(--text-2); }
.r-grupo + .r-grupo .r-fila td { border-top: 2px solid var(--border); }
.r-costeo > td { padding-top: 0 !important; }
.costeo-caja { margin: 0 0 6px 18px; padding: 8px 10px; border-left: 3px solid var(--alt-bd, #c9c6f3); background: var(--alt-bg, #eeedfe); border-radius: 0 6px 6px 0; }
.costeo-tit { font-size: 11px; font-weight: 700; color: var(--alt-fg, #534ab7); margin-bottom: 4px; }
.costeo-suma { font-weight: 400; }
.costeo-suma.mal { color: var(--err-fg); font-weight: 700; }
.costeo-tabla { width: 100%; border-collapse: collapse; }
.costeo-tabla td { padding: 2px 4px 2px 0; }
.costeo-tabla input { width: 100%; }

/* ═══ FINANCIERO · Drawer de Autorización (armazón D2) ════════════════════
   Rafael, 9-oct-2026: «tan bonito como los de Operaciones». Franja de qué
   sigue, la cabecera de la solicitud, la firma en crema y arriba, datos en
   dos columnas, archivos como tarjetas y las firmas como línea de tiempo.  */
.sol-cab-dw { border: 0; box-shadow: none; padding: 0; margin: 0 0 10px; background: none; }
.sol-cab-dw .sol-prov-nombre { font-size: 15px; }
.sol-cab-dw .sol-monto { font-size: 21px; }
.sol-pasos-dw { margin: 0; }
.sol-pasos-dw li { font-size: 10.5px; padding: 5px 4px; gap: 4px; }
.sol-pasos-dw .pt { width: 16px; height: 16px; font-size: 9px; }

.aut-firma { border-bottom: 1px solid var(--border); }
.aut-firma + .aut-firma { border-top: 0; }
.aut-firma-tit { font-size: var(--fs-100); font-weight: 700; text-transform: uppercase; letter-spacing: .7px; color: var(--text-2); margin-bottom: 6px; }
.aut-firma-linea { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; font-size: var(--fs-300); margin-bottom: 10px; }
.aut-firma-linea strong { font-family: var(--fuente-num); font-size: 18px; white-space: nowrap; }
.aut-form { display: flex; flex-direction: column; gap: 8px; }
.aut-form input[type=text] { width: 100%; background: var(--surface); }
.aut-botones { display: flex; gap: 8px; justify-content: flex-end; }
.aut-botones .btn { min-width: 130px; justify-content: center; }
.aut-rechazar { color: var(--err-fg); border-color: var(--err-bd); }
.aut-rechazar:hover { background: var(--err-bg); }
.aut-falta { color: var(--warn-fg); }

.aut-archivos { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.aut-arch { display: flex; gap: 8px; align-items: center; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); color: var(--text-1); min-width: 0; }
.aut-arch:hover { border-color: var(--info-bd); background: var(--info-bg); text-decoration: none; }
.aut-arch .ic { font-size: 18px; flex: none; }
.aut-arch .tx { min-width: 0; display: flex; flex-direction: column; font-size: 11px; }
.aut-arch .tx b { font-size: 12px; }
.aut-arch .tx span { color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.aut-linea-tiempo { position: relative; }
.aut-paso { position: relative; display: flex; gap: 12px; padding: 0 0 12px; }
.aut-paso:not(:last-child)::before { content: ''; position: absolute; left: 5px; top: 14px; bottom: 0; width: 2px; background: var(--border); }
.aut-paso .dot { width: 12px; height: 12px; border-radius: 50%; margin-top: 3px; flex: none; border: 2px solid var(--warn-fg); background: var(--surface); position: relative; z-index: 1; }
.aut-paso.ok .dot { background: var(--ok-fg); border-color: var(--ok-fg); }
.aut-paso.espera .dot { border-color: var(--n-300, #ccc); }
.aut-paso .cuerpo { flex: 1; min-width: 0; }
.aut-paso .et { font-size: 9.5px; }
.aut-linea { display: flex; gap: 8px; align-items: baseline; font-size: var(--fs-200); }
.aut-linea .nom { flex: 1; min-width: 0; }
.aut-linea strong { white-space: nowrap; font-variant-numeric: tabular-nums; }
.aut-evento { display: flex; gap: 6px; align-items: baseline; font-size: 11.5px; margin: 4px 0 0; padding: 3px 8px;
  border-left: 3px solid var(--alt-bd, #c9c6f3); background: var(--alt-bg, #eeedfe); border-radius: 0 6px 6px 0; }

/* ═══ FINANCIERO · Drawer de Pago (armazón D2) ═════════════════════════════
   La cuenta del proveedor grande y con copiar (es lo que se teclea en el
   banco), una barra de cuánto va pagado, los pagos como tarjetas con su
   comprobante, y el registro del pago en crema.                            */
.pg-clabe2 { margin: 0 0 4px; padding: 12px 14px; border: 1px solid var(--info-bd); background: var(--info-bg); border-radius: var(--r-lg); }
.pg-clabe2.sin { border-color: var(--err-bd); background: var(--err-bg); }
.pg-clabe2-tit { font-size: var(--fs-100); font-weight: 700; text-transform: uppercase; letter-spacing: .7px; color: var(--text-2); margin-bottom: 6px; }
.pg-clabe2-fila { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.pg-clabe2 .banco { font-weight: 700; font-size: var(--fs-300); }
.pg-clabe2 code { font-family: var(--fuente-num); font-size: 19px; font-weight: 700; letter-spacing: .8px; color: var(--text-1); background: none; padding: 0; }

.pg-barra { height: 10px; border-radius: 999px; background: var(--n-100); overflow: hidden; margin-bottom: 8px; }
.pg-barra span { display: block; height: 100%; background: var(--ok-fg); border-radius: 999px; transition: width .3s; }
.pg-cifras { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 8px; margin-bottom: 12px; }
.pg-cifras > div { display: flex; flex-direction: column; padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px; }
.pg-cifras span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .5px; color: var(--text-3); font-weight: 700; }
.pg-cifras strong { font-family: var(--fuente-num); font-size: var(--fs-400); }
.pg-cifras strong.ok { color: var(--ok-fg); } .pg-cifras strong.falta { color: var(--warn-fg); }

.pg-pago2 { border: 1px solid var(--border); border-left: 4px solid var(--ok-fg); border-radius: 8px; padding: 9px 12px; margin-bottom: 8px; background: var(--surface); }
.pg-pago2.anulado { border-left-color: var(--err-fg); opacity: .6; }
.pg-pago2.anulado .pg-pago2-cab strong { text-decoration: line-through; }
.pg-pago2-cab { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; font-size: var(--fs-200); }
.pg-pago2-cab strong { font-family: var(--fuente-num); font-size: var(--fs-400); }
.pg-pago2-cab .et { font-size: 9.5px; margin-left: auto; }
.pg-pago2-arch { display: flex; gap: 8px; flex-wrap: wrap; margin: 8px 0 6px; align-items: center; }
.pg-pago2-arch .aut-arch { padding: 5px 9px; }
.pg-falta-comp { font-size: 11px; color: var(--warn-fg); background: var(--warn-bg); border-radius: 999px; padding: 2px 9px; }
.pg-anular { margin-top: 8px; } .pg-anular > summary { padding: 6px 10px; font-size: 12px; }

.pg-registrar2, .pg-programar { border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.pg-grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; }
.pg-grid2 .c2 { grid-column: 1 / -1; }
.pg-grid2 input, .pg-grid2 select { width: 100%; background: var(--surface); }
.pg-grid2 input[type=file] { font-size: 11px; background: none; }
.pg-grid2 input.num { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
.pg-pie { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: 12px; }
.pg-fila { display: flex; gap: 8px; align-items: flex-end; margin-top: 6px; flex-wrap: wrap; }
.dw-cuerpo .mal, .dw-pagina .mal { border-color: var(--err-fg) !important; background: var(--err-bg); }
.dw-cuerpo .err-msg, .dw-pagina .err-msg { color: var(--err-fg); font-size: 11px; margin-top: 3px; }

/* ═══ FINANCIERO · Drawer de Anticipo por Comprobar (armazón D2) ══════════ */
.ant-barra span { background: var(--alt-fg); }
.pg-cifras em { font-style: normal; font-size: 10.5px; color: var(--text-3); }
.pg-cifras .vencido { color: var(--err-fg); }
.ant-factura { border-left-color: var(--alt-fg); }
.ant-reglas { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px; }
.ant-reglas > div { font-size: 11.5px; color: var(--text-2); padding: 6px 9px; border-radius: 6px; background: var(--surface); border: 1px solid var(--border); }
.ant-plazo { margin: 14px 0 0; }

/* ═══ FINANCIERO · Ficha de Proveedor (armazón D2) ═════════════════════════ */
.prv-clabe-cab { font-family: var(--fuente-num); font-size: 16px; font-weight: 700; }
.prv-clabe { font-family: var(--fuente-num) !important; font-size: 16px !important; letter-spacing: .6px; }
.prv-check { display: flex; gap: 6px; align-items: center; font-size: var(--fs-300); font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--text-1); min-height: 36px; }
.prv-check input { width: auto; margin: 0; }
.prv-docs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-bottom: 12px; }
.prv-docs .sol-arch { display: flex; flex-direction: column; gap: 6px; }
.prv-docs .sol-arch.falta { border-color: var(--warn-bd); background: var(--warn-bg); }
.prv-docs .aut-arch { padding: 5px 8px; }
.prv-pie { position: sticky; bottom: 0; display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 12px 16px; margin: 0 calc(-1 * var(--dr-lado, 0px)); background: var(--bg); border-top: 1px solid var(--border); z-index: 5; }
@media (max-width: 900px) { .prv-docs { grid-template-columns: 1fr; } }

/* Ficha en consulta (sin permiso de editar): se lee como ficha, sin cajas. */
.ficha-lectura fieldset[disabled] :is(input, select, textarea) {
  border-color: transparent; background: transparent; color: var(--text-1); padding-left: 0; padding-right: 0;
  box-shadow: none; resize: none; opacity: 1; -webkit-text-fill-color: var(--text-1); }
.ficha-lectura fieldset[disabled] select { background-image: none; }
.ficha-lectura fieldset[disabled] textarea { min-height: 0; }
/* Pegada al borde de abajo del drawer, no 20 px arriba: .dw-cuerpo lleva
   20 px de relleno inferior y el contenido se asomaba por debajo (Rafael,
   9-oct-2026). */
.dw-cuerpo .prv-pie { bottom: -20px; margin-bottom: -20px; padding-bottom: 14px; box-shadow: 0 -4px 12px rgba(0,0,0,.05); }
.prv-lista tbody tr[data-drawer-url]:hover td { background: var(--n-50, #f7f7f5); }

/* ═══ FINANCIERO · Ficha de Cuenta Contable (armazón D2) ═══════════════════ */
.sol-grid .c3 { grid-column: span 3; }
.cta-tipos { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.cta-tipo { display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px;
  cursor: pointer; text-transform: none; letter-spacing: 0; font-weight: 400; color: var(--text-1); background: var(--surface); }
.cta-tipo input { position: absolute; opacity: 0; pointer-events: none; }
.cta-tipo b { font-size: var(--fs-300); }
.cta-tipo span { font-size: 11px; color: var(--text-3); line-height: 1.35; }
.cta-tipo:has(input:checked) { border-color: var(--n-900); box-shadow: 0 0 0 1px var(--n-900) inset; background: var(--n-25); }
.ficha-lectura .cta-tipo:not(:has(input:checked)) { display: none; }
.cta-lista tbody tr[data-drawer-url]:hover td { background: var(--n-50, #f7f7f5); }
/* Ficha corta (Cuenta): el pie también va pegado al fondo del drawer, no a
   media pantalla. El formulario ocupa todo el alto y el pie se va abajo. */
.dw-cuerpo:has(.prv-pie) { display: flex; flex-direction: column; }
.dw-cuerpo:has(.prv-pie) > form { flex: 1 0 auto; display: flex; flex-direction: column; }
.dw-cuerpo .prv-pie { margin-top: auto; }
.prv-pie-revisa input[type=text] { flex: 1; min-width: 0; background: var(--surface); }
/* Aire entre la franja de «qué sigue» y lo que viene debajo cuando no hay
   cabecera en medio (p. ej. una solicitud de alta nueva). */
.dr-sig + form, .dr-sig + .alert { margin-top: 16px; }
/* Folio PP-AAAA-NNNNN (9-oct-2026): nunca partido en dos renglones. */
.tabla .folio, .sol-folio { white-space: nowrap; }
/* Configuración, aparte y más abajo en la pantalla de ambientes (9-oct-2026). */
.amb-portal.amb-aparte { margin-top: 36px; padding-top: 28px; border-top: 1px solid var(--border); }
.amb-portal.amb-aparte .hub-cat { grid-template-columns: repeat(auto-fill, minmax(240px, 300px)); }
.amb-portal.amb-aparte .hub-cat-t { padding: 18px 22px 20px; background: var(--n-50, #f5f4f0); }
.amb-portal.amb-aparte .hub-cat-ic { font-size: 26px; }
.amb-portal.amb-aparte .hub-cat-h { font-size: var(--fs-400); }
/* Pedir excepción del candado de cierre (9-oct-2026). */
.cierre-pedir { display: flex; gap: 8px; margin-top: 8px; }
.cierre-pedir input { flex: 1; min-width: 0; background: var(--surface); }

/* ── Tesorería · Cajas (10-oct-2026) ─────────────────────────── */
/* Casilla con explicación a su lado, dentro de un formulario de drawer. */
.tz-check { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--surface, #fff); cursor: pointer; grid-column: 1 / -1; }
.tz-check input[type=checkbox] { width: auto; flex: none; margin: 3px 0 0; }
.tz-check > span { flex: 1; }

/* Botón del documento imprimible (VDC, Arqueo) en los drawers de Cajas. */
.tz-doc { display: flex; justify-content: flex-end; margin: 10px 0 0; }

/* Autocosteo - Rentas (10-oct-2026): rango de fechas y reparto calculado. */
.auto-rango { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 10px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--n-50, #faf9f6); }
.auto-rango.mal { border-color: var(--err-bd); }
.auto-rango .fg { margin: 0; } .auto-rango input[type=date] { width: 160px; }
.auto-tabla { max-height: 260px; overflow: auto; }
.auto-tabla thead th { position: sticky; top: 0; background: var(--surface, #fff); font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-2); text-align: left; }

/* Ambientes en prueba (10-oct-2026): Financiero y Tesorería. Ver AUTH_ROL_PRUEBA en config/auth.php. */
.et-prueba { display:inline-block; vertical-align:middle; margin-left:6px; padding:1px 7px; border-radius:999px;
  font-size:10px; font-weight:800; letter-spacing:.6px; text-transform:uppercase; line-height:1.6;
  background: var(--warn-bg); color: var(--warn-fg); border:1px solid var(--warn-bd); }
.topbar .et-prueba { margin-left:10px; }

/* SISTEMA DE PRUEBAS (12-oct-2026): franja fija arriba de todo, sólo donde APP_PRUEBAS. */
.franja-pruebas { position: sticky; top: 0; z-index: 9999; background: repeating-linear-gradient(45deg, #f5b800 0 14px, #1d1d1b 14px 28px);
  color: #fff; text-align: center; font-size: 12px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; padding: 5px 10px;
  text-shadow: 0 1px 2px #000, 0 0 6px #000; }

/* «Ver como» del Master de Pruebas (lib/pruebas.php). */
.ver-como { margin: .9rem .75rem .75rem; padding: .5rem .6rem; border: 1px dashed #f5b800; border-radius: 8px; background: rgba(245,184,0,.08); }
.ver-como label { display: block; }
.ver-como span { display: block; font-size: 10px; font-weight: 800; letter-spacing: .6px; text-transform: uppercase; color: #f5b800; margin-bottom: 3px; }
.ver-como select { width: 100%; font-size: 12.5px; }
.topbar-actions .ver-como { margin: 0 .75rem 0 0; padding: .25rem .5rem; display: inline-block; vertical-align: middle; }
.topbar-actions .ver-como select { width: auto; min-width: 220px; }
