/* ⚠️ Acá vivían las reglas de `facturas/list.html` (`.facturas-panel`,
   `.facturas-head`, `.facturas-search*`, `.dots-btn`, la leyenda de colores y
   las franjas `.fila-nacional` / `.fila-exportacion`). Se borraron el
   2026-08-21 con esa plantilla: eran su único usuario, comprobado con grep
   sobre plantillas, JSX y JS antes de tocar nada.
   Las franjas eran la última excepción viva de `FRANJAS_PERMITIDAS` en el
   guardián de estilo; el tinte de fila que las reemplaza está en el bloque de
   `.tema-bento`. `.dots-panel` sí sigue vivo: lo usa `ui/Menu.jsx`. */
/* Fuente cargada desde las plantillas base: Manrope (familia única, ver DESIGN.md) */
:root{
  /* --vino/--vino-h/--vino-tinte, --fondo/--panel/--texto, --tenue,
     --borde, --ok, --peligro y --ease-spring viven en tokens.css (Fase 3
     rediseño, 2026-07-13) — cargado antes que este archivo en las 4
     plantillas base que lo usan. Fuente única de verdad compartida
     también con Siigo. */
  /* Tokens que ya documentaba DESIGN.md pero nunca se declaraban aquí. */
  --alerta:#8A4F00;
  --home-bg:#1F2430;
  /* Tono neutro de hover/encabezado de tabla — usado con este mismo
     fallback en 8 lugares de Compras sin declararse nunca aquí. */
  --fondo-alt:#F7F8FA;
  /* Colores de grupo botanico ICA, centralizados (Fase 2 rediseño 2026-07-13)
     — antes hardcodeados en .badge-grupo.*, duplicando --alerta y un verde
     casi-igual a --ok. Aves reusa --alerta (mismo valor exacto); Ruscus se
     unifica con --ok (eran 2 tonos de verde casi idénticos, decisión del
     usuario de dejar uno solo); Hydrangea es su primer uso como variable. */
  --grupo-aves:var(--alerta); --grupo-ruscus:var(--ok); --grupo-hydrangea:#1558AC;
}
*{box-sizing:border-box;margin:0;padding:0}
.skip-link{position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden;
  z-index:300;background:var(--vino);color:#fff;padding:10px 16px;border-radius:0 0 8px 0;
  font-size:13px;font-weight:700;text-decoration:none}
.skip-link:focus{left:0;top:0;width:auto;height:auto;overflow:visible}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}
body{font-family:'Manrope',"Segoe UI",system-ui,Arial,sans-serif;background:var(--fondo);
  color:var(--texto);min-height:100vh;padding-left:58px}

/* ── Sidebar ──────────────────────────────────────────────────── */
/* Mini-expandible (rediseño Fase 1, 2026-07-12): colapsado a un riel de
   58px con solo íconos; se expande a 230px con :hover (mouse) o
   :focus-within (teclado — sin esto, un usuario de teclado nunca podría
   expandirlo, ver spec de la Fase 1). */
.sidebar{width:58px;background:#fff;border-right:0.5px solid var(--borde);display:flex;
  flex-direction:column;padding:0;position:fixed;left:0;top:0;height:100vh;flex-shrink:0;
  overflow-y:auto;overflow-x:hidden;transition:width .38s var(--ease-spring);z-index:40}
.sidebar:hover,.sidebar:focus-within{width:230px}
.brand{padding:22px 18px 16px;border-bottom:0.5px solid var(--borde);text-decoration:none;display:block}
.sidebar nav{display:flex;flex-direction:column;gap:1px;padding:14px 10px;flex:1}
.sidebar nav a,.sidebar nav .nav-accion{color:var(--tenue);text-decoration:none;padding:8px 9px;border-radius:8px;
  font-size:13.5px;display:flex;gap:0;align-items:center;
  transition:padding .38s var(--ease-spring), gap .38s var(--ease-spring), background .12s ease, color .12s ease, border-left-color .12s ease;
  border-left:2.5px solid transparent;letter-spacing:0.01em}
.sidebar:hover nav a,.sidebar:focus-within nav a,
.sidebar:hover nav .nav-accion,.sidebar:focus-within nav .nav-accion{padding:8px 12px;gap:11px}
.sidebar nav a .navicon,.sidebar nav .nav-accion .navicon{width:17px;height:17px;flex-shrink:0;opacity:.8}
.sidebar nav a:hover,.sidebar nav .nav-accion:hover{background:var(--fondo);color:var(--texto)}
.sidebar nav a:hover .navicon,.sidebar nav .nav-accion:hover .navicon{opacity:1}
.sidebar nav a.on{color:var(--vino);border-left-color:var(--vino);font-weight:700;background:var(--vino-tinte)}
.sidebar nav a.on .navicon{opacity:1}
.sidebar nav a span,.sidebar nav .nav-accion span,.side-user-info,.export span{
  opacity:0;max-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  transition:opacity .2s ease, max-width .38s var(--ease-spring)}
.sidebar:hover nav a span,.sidebar:hover nav .nav-accion span,
.sidebar:hover .side-user-info,.sidebar:hover .export span,
.sidebar:focus-within nav a span,.sidebar:focus-within nav .nav-accion span,
.sidebar:focus-within .side-user-info,.sidebar:focus-within .export span{
  opacity:1;max-width:160px}
/* Botón de acción en el sidebar (abre un modal en vez de navegar): un
   <button> de verdad porque no es navegación, con el aspecto de un enlace. */
.sidebar nav .nav-accion{background:none;border-top:0;border-right:0;border-bottom:0;
  font:inherit;font-family:inherit;text-align:left;width:100%;cursor:pointer}
.nav-sep{height:1px;background:var(--borde);margin:10px 12px}
.nav-label{font-size:10px;font-weight:700;letter-spacing:0.12em;text-transform:uppercase;
  color:var(--tenue);padding:4px 12px 6px}
.side-footer{border-top:0.5px solid var(--borde);padding:12px 10px}
.side-user{display:flex;align-items:center;gap:0;padding:6px 8px 10px;transition:gap .38s var(--ease-spring)}
.sidebar:hover .side-user,.sidebar:focus-within .side-user{gap:10px}
.side-avatar{width:32px;height:32px;border-radius:50%;background:var(--vino-tinte);
  color:var(--vino);font-family:'Manrope',"Segoe UI",sans-serif;font-weight:800;
  font-size:14px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.side-user-info{min-width:0}
.side-user-name{font-size:13px;font-weight:700;color:var(--texto);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.side-user-role{font-size:10.5px;color:var(--tenue);letter-spacing:0.03em}
.export{color:var(--tenue);text-decoration:none;padding:8px 9px;font-size:13px;border-radius:8px;
  display:flex;align-items:center;gap:0;
  transition:padding .38s var(--ease-spring), gap .38s var(--ease-spring), background .12s ease, color .12s ease}
.sidebar:hover .export,.sidebar:focus-within .export{padding:8px 12px;gap:11px}
.export .navicon{width:16px;height:16px;opacity:.75}
.export:hover{background:var(--fondo);color:var(--texto)}
.export:hover .navicon{opacity:1}

/* ── Contenido ────────────────────────────────────────────────── */
/* max-width 1200 -> 1600 y padding lateral 36 -> 28 (2026-08-12, pedido del
   usuario: "un margen tan grande que no deja aprovechar bien la pantalla").
   Medido en su ventana de 1830 px: quedan ~1773 útiles descontando el riel del
   sidebar, y el tope de 1200 usaba 1128 — o sea ~645 px desperdiciados. Con
   1600 quedan ~1544 de contenido: 416 px más.
   NO se suelta del todo a propósito: en las pantallas de formulario (Ajustes,
   editar factura, perfil de empleado) un campo de texto de 1800 px se lee peor,
   no mejor. La portada (`.home-wrap`, 1100) queda centrada aparte: son tarjetas
   sobre una imagen, no una tabla, y estirarlas la empeora.
   El full-bleed real sigue existiendo para las tablas que lo necesitan
   (`.content.facturas-full`, ver abajo). */
/* ── Informes en React (2026-08-31) ──────────────────────────── */
/* Reemplaza a las 181 líneas de CSS que vivían dentro de `informes.html`, que
   era un documento suelto con su propio diseño. Al entrar al Shell común, la
   mayoría dejó de hacer falta: las tarjetas ahora son `.tile` del tema y el
   encabezado es el `.row-head` de siempre. Queda lo que es propio del informe. */

/* El canvas de un gráfico necesita alto explícito: Chart.js con
   `maintainAspectRatio:false` crece hasta el del contenedor, y sin alto el
   contenedor mide 0 y el gráfico no se ve. El alto lo pasa cada `<Grafico>`. */
.grafico{position:relative;width:100%}
.grafico canvas{width:100%!important;height:100%!important}

/* La fila de filtros. `auto-fit` y no `auto-fill`: son 5 y queremos que ocupen
   el ancho, no que dejen huecos. */
.filtrera{display:grid;gap:10px;margin-bottom:10px;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.click-hint{color:var(--tenue);font-size:12.5px;margin:0 0 18px}
.chart-note{font-size:12px;color:var(--tenue);margin:10px 0 0;
  display:flex;gap:10px;flex-wrap:wrap}
.chart-note b{color:var(--texto);font-weight:700;font-variant-numeric:tabular-nums}
h2.tarjetas-tt .note{font-weight:400;font-size:12.5px;color:var(--tenue)}
/* El pie de la tabla mensual: una fila más, para que las columnas queden
   alineadas con el resto (como `<tfoot>` aparte se desalineaba al scrollear). */
.fila-total td{border-top:2px solid var(--borde);font-weight:700;
  color:var(--texto);background:var(--fondo)}
/* El nombre del mes abre el drill. Botón y no fila clicable: el teclado lo
   alcanza y el lector de pantalla lo anuncia. */
.enlace-mes{background:none;border:0;padding:0;font:inherit;color:var(--vino);
  cursor:pointer;text-align:left}
.enlace-mes:hover{text-decoration:underline}
.enlace-mes:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
.tema-bento .enlace-mes{color:var(--a-lila)}

/* La leyenda de grupos, debajo del resumen. */
.legend-grupos{display:flex;flex-wrap:wrap;gap:8px 18px;margin:0 0 22px;
  font-size:12.5px;color:var(--tenue)}
.legend-grupos .grupo-dot{display:inline-block;width:9px;height:9px;
  border-radius:50%;margin-right:6px;vertical-align:0}

/* Clientes nuevos vs recurrentes: una barra proporcional. Son dos números y un
   donut de dos porciones no agrega nada. */
.mix-bar{display:flex;height:14px;border-radius:999px;overflow:hidden;
  background:var(--fondo);margin-top:14px}
.mix-bar .rec{background:var(--vino)}
.mix-bar .nue{background:var(--vino-tinte)}
.mix-leyenda{display:flex;flex-direction:column;gap:6px;margin-top:12px;
  font-size:12.5px;color:var(--tenue)}
.mix-leyenda b{color:var(--texto);font-variant-numeric:tabular-nums}
.mix-dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px}
.mix-dot.rec{background:var(--vino)}
.mix-dot.nue{background:var(--vino-tinte)}

.drill-sub{margin:0 0 12px;font-size:13px;color:var(--tenue)}
.drill-sub b{color:var(--texto);font-variant-numeric:tabular-nums}
/* Mientras se recarga por un filtro, el informe se atenúa en vez de vaciarse:
   ver la pantalla en blanco entre filtro y filtro se siente roto. */
.informes.cargando{opacity:.55;pointer-events:none;transition:opacity .15s ease}

/* Los tres tonos de la esfera del globo. Están acá y no en el JS porque un
   `<canvas>` no entiende `var(--x)` —hay que resolverlo— y un hex escrito en el
   JSX sería un segundo lugar donde vive un color del sistema. Los lee
   `modules/informes/tokens.js`. */
:root{--globo-esfera-1:#FFFFFF; --globo-esfera-2:#F2F3F5; --globo-esfera-3:#E4E6EA}

/* El globo. `aspect-ratio` y no alto fijo: tiene que ser cuadrado o la esfera
   sale ovalada al proyectar. */
.globe-box{position:relative;width:100%;aspect-ratio:1;min-height:280px;
  max-height:430px;margin:0 auto}
.globe-box canvas{width:100%;height:100%;display:block}
.globe-toast{position:absolute;left:50%;bottom:10px;transform:translateX(-50%) translateY(6px);
  background:var(--panel);border:1px solid var(--borde);border-radius:999px;
  padding:6px 14px;font-size:12.5px;white-space:nowrap;opacity:0;
  transition:opacity .25s ease, transform .25s ease;pointer-events:none;
  box-shadow:0 4px 14px rgba(20,22,28,.10)}
.globe-toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.globe-ctl{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  margin-top:10px;font-size:12.5px;color:var(--tenue)}
.globe-ctl .cuenta b{color:var(--texto);font-variant-numeric:tabular-nums}
.rutas-origin-tag{margin-left:auto}

/* La puerta de entrada: nacional, exportación o ambas. Cubre el contenido
   porque la elección cambia TODO el informe: dejarlo ver detrás invitaría a
   leer números que están por cambiar. */
.puerta{position:fixed;inset:0;z-index:60;display:grid;place-items:center;
  padding:24px;background:rgba(244,245,249,.86);backdrop-filter:blur(7px)}
.puerta-caja{background:var(--panel);border-radius:20px;padding:30px 32px;
  max-width:660px;width:100%;text-align:center;
  box-shadow:0 18px 50px rgba(20,22,28,.16)}
.puerta-caja h2{margin:0 0 5px;font-size:21px;font-weight:800;letter-spacing:-.02em}
.puerta-caja > p{margin:0 0 20px;color:var(--tenue);font-size:13px}
.puerta-ops{display:grid;gap:12px;grid-template-columns:repeat(3,1fr)}
.puerta .op{background:var(--fondo);border:1.5px solid var(--borde);
  border-radius:14px;padding:16px 14px;cursor:pointer;font:inherit;color:inherit;
  display:flex;flex-direction:column;gap:2px;transition:.15s ease}
.puerta .op:hover{border-color:var(--vino);background:var(--vino-tinte)}
.puerta .op:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
.puerta .op b{font-size:14.5px}
.puerta .op span{font-size:11.5px;color:var(--tenue)}
/* El MONTO en el botón no es decoración: es la razón de elegir. Sin él la
   pregunta es a ciegas y uno aprende a apretar siempre lo mismo. */
.puerta .op em{font-style:normal;font-size:19px;font-weight:800;color:var(--vino);
  font-variant-numeric:tabular-nums;margin-top:6px}
.tema-bento .puerta .op em{color:var(--a-lila)}
@media (max-width:760px){ .puerta-ops{grid-template-columns:1fr} }

/* Las tarjetas de grupo, con su foto. Son BOTONES: al hacer clic filtran el
   informe por ese grupo, igual que el anillo. */
.gcards{display:grid;gap:11px;grid-template-columns:repeat(3,1fr);margin-bottom:4px}
.gcard{border:0;border-radius:var(--r-tile,16px);padding:0;display:flex;
  align-items:stretch;overflow:hidden;cursor:pointer;font:inherit;text-align:left;
  transition:transform .25s var(--ease-spring), box-shadow .25s var(--ease-spring)}
.gcard:hover{transform:translateY(-2px);box-shadow:0 8px 20px rgba(20,22,28,.10)}
.gcard:focus-visible{outline:2px solid currentColor;outline-offset:2px}
.gfoto{width:84px;flex-shrink:0;background-size:cover;background-position:center}
.gtxt{display:flex;flex-direction:column;gap:1px;padding:14px 16px;min-width:0}
.gl{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  opacity:.85}
.gv{font-size:21px;font-weight:800;letter-spacing:-.02em;line-height:1.15;
  font-variant-numeric:tabular-nums}
.gs{font-size:11px;opacity:.75}
@media (max-width:760px){ .gcards{grid-template-columns:1fr} }

/* Estacionalidad: mes contra grupo, el color dice cuánto. */
.heat{display:flex;flex-direction:column;gap:4px}
.heat-fila{display:grid;grid-template-columns:104px repeat(var(--cols),1fr);gap:4px;
  align-items:center}
.heat-nom{font-size:10.5px;font-weight:700;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.heat-mes{font-size:9.5px;color:var(--tenue);text-align:center}
.heat-celda{height:22px;border-radius:4px;opacity:var(--o)}

/* Variedades partidas por grupo. */
.vgs{display:flex;flex-direction:column;gap:14px}
.vg-t{font-size:10.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  display:block;margin-bottom:6px}
.vg-fila{display:grid;grid-template-columns:1fr 90px auto;gap:10px;align-items:center;
  margin-bottom:5px}
.vg-n{font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vg-p{height:10px}
.vg-b{display:block;height:10px;border-radius:3px}
.vg-v{font-size:11.5px;font-weight:700;font-variant-numeric:tabular-nums;
  white-space:nowrap}

/* Un número solo, grande, como respuesta de una tarjeta. */
.dato-grande{display:block;font-size:30px;font-weight:800;letter-spacing:-.025em;
  line-height:1.1;font-variant-numeric:tabular-nums;margin-bottom:2px}
.barra-plana{height:9px;border-radius:999px;background:var(--fondo);overflow:hidden;
  margin-top:10px}
.barra-plana span{display:block;height:100%;background:var(--vino);border-radius:999px}
.lista-simple{list-style:none;margin:10px 0 0;padding:0;display:flex;
  flex-direction:column;gap:5px}
.lista-simple li{display:flex;justify-content:space-between;gap:10px;font-size:11.5px;
  color:var(--tenue);border-bottom:1px dotted var(--borde);padding-bottom:4px}
.lista-simple li b{color:var(--texto);font-variant-numeric:tabular-nums}

/* El aviso del hueco sin vendedor. Solo aparece cuando el hueco es grande —
   en el informe nacional es el 96 % y sin decirlo el ranking parece que sobra. */
.aviso-hueco{background:var(--vino-tinte);color:var(--vino);border-radius:10px;
  padding:9px 12px;font-size:12px;margin-top:10px}
.tema-bento .aviso-hueco{background:var(--t-lila);color:var(--a-lila)}

/* Impresión: el informe en PDF sale sin sidebar ni controles. Es el «PDF» de la
   cabecera, que es el diálogo del navegador — no hay un generador aparte que
   pueda quedar desincronizado de lo que se está viendo en pantalla. */
@media print{
  .sidebar,.barra-mod,.filtrera,.click-hint,.acts,.globe-ctl,
  .puerta{display:none!important}
  body{padding-left:0}
  .content{max-width:100%;padding:0}
  .tile{break-inside:avoid;page-break-inside:avoid}
}

/* ── Administración en React (2026-08-31) ────────────────────── */
/* Las clases que reemplazan al markup en línea de las 5 plantillas Jinja que se
   borraron. Estaban como `style="..."` dentro del HTML; acá quedan una vez.
   `.proc-*` NO se tocó: la pantalla de procesos automáticos las sigue usando. */

/* Cabecera de un registro (un error de Monitoreo, una eliminación auditada):
   el badge, la fecha y —si va— el botón de acción, en una línea que envuelve. */
.reg-cab{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.reg-meta{color:var(--tenue);font-size:12px}
.reg-mensaje{margin-top:8px;font-weight:600}
.reg-recom{margin-top:8px;background:var(--vino-tinte);padding:8px 12px;
  border-radius:8px;font-size:13px}
/* La traza y el snapshot: texto técnico, siempre sobre fondo oscuro para que se
   lea como lo que es —una salida de consola— y no como parte de la interfaz. */
.traza{white-space:pre-wrap;font-size:11px;background:#1E1E24;color:#E4E4E7;
  padding:12px;border-radius:8px;overflow:auto;max-height:260px;margin-top:8px;
  font-family:ui-monospace,SFMono-Regular,Consolas,monospace}
/* Un registro ya atendido sigue visible pero deja de pedir atención. */
.apagado{opacity:.55}

/* Permisos por módulo (formulario de usuario). `fieldset` sin borde propio: el
   borde lo lleva cada grupo, que es la unidad que se lee. */
.perms{border:0;padding:0;margin:0;display:flex;flex-direction:column;gap:12px}
.perms.apagado{pointer-events:none}
.perm-group{border:1px solid var(--borde);border-radius:var(--r-control,10px);
  padding:10px 14px}
.perm-nombre{font-weight:600;margin-bottom:2px}
.perm-items{display:flex;flex-wrap:wrap;gap:10px 22px;margin-top:8px}
.perm-check{display:flex;gap:7px;align-items:center;font-weight:400;cursor:pointer}
.tema-bento .perm-group{border-color:var(--linea-control)}

/* ── Tarjetas de navegación (`ui/Tarjeta.jsx`) ────────────────── */
/* La portada de Ajustes: una tarjeta por catálogo y por pantalla del módulo.
   Volvieron el 2026-08-31 a pedido del usuario («cada catálogo con su propia
   tarjeta como era antes, se ve más bonito»). NO son las `.setcard` viejas: esas
   eran de ancho fijo (200px) y del sistema de color anterior, donde `--vino` era
   el rojo. Estas usan los tokens del tema y una rejilla que se acomoda sola.

   `auto-fill` y no `auto-fit`: con 11 catálogos y una ventana ancha, `auto-fit`
   estiraría las últimas dos tarjetas de la fila hasta el ridículo. */
/* El rótulo de cada grupo de tarjetas. Chico a propósito: separa, no compite
   con el h1 de la pantalla. */
.tarjetas-tt{font-size:15px;font-weight:700;margin:0 0 12px;letter-spacing:-.01em}
.tarjetas-tt + .tarjetas{margin-top:0}
.tarjetas{display:grid;gap:14px;margin-bottom:26px;
  grid-template-columns:repeat(auto-fill,minmax(212px,1fr))}
.tarjeta{display:flex;flex-direction:column;gap:2px;text-decoration:none;
  background:var(--panel);border:1px solid var(--borde);border-radius:var(--r-control,12px);
  padding:16px 18px;color:var(--texto);
  transition:transform .3s var(--ease-spring), border-color .2s ease,
             box-shadow .3s var(--ease-spring)}
.tarjeta:hover{transform:translateY(-3px);border-color:var(--vino);
  box-shadow:0 8px 20px rgba(34,38,46,.10)}
.tarjeta:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
.tarjeta-ico{font-size:24px;line-height:1.2;margin-bottom:6px}
/* `block` y no `flex`: con flex, un título de dos renglones («Precios por
   cliente y variedad», «Categorías de ajuste (Cartera)») empujaba el conteo al
   borde derecho de la tarjeta, lejos del texto. Así lo sigue como una palabra
   más. */
.tarjeta-tt{font-weight:700;font-size:14.5px}
/* El conteo no compite con el nombre: es el dato secundario de la tarjeta. */
.tarjeta-n{display:inline-block;margin-left:7px;vertical-align:1px;
  font-size:12px;font-weight:600;color:var(--tenue);
  background:var(--fondo);border-radius:999px;padding:1px 8px;
  font-variant-numeric:tabular-nums}
.tarjeta-ds{color:var(--tenue);font-size:12.5px;margin-top:2px}
.tema-bento .tarjeta{border:none;border-radius:var(--r-tile)}
.tema-bento .tarjeta:hover{background:var(--t-lila)}
.tema-bento .tarjeta:hover .tarjeta-tt{color:var(--a-lila)}
.tema-bento .tarjeta-n{background:var(--fondo)}
.tema-bento .tarjeta:hover .tarjeta-n{background:var(--panel)}

/* ── Barra de módulo (nivel 2 de la navegación) ───────────────── */
/* El sidebar lista los MÓDULOS y esta barra las PANTALLAS del módulo en el que
   estás. Antes las pantallas colgaban del sidebar y el riel llegaba a 17 filas;
   el usuario lo rechazó por saturado el 2026-08-28. La dibuja
   `frontend/src/ui/BarraModulo.jsx`, desde el Shell: una sola barra para los
   once módulos.
   `sticky` y no `fixed`: el sidebar es `fixed` y ya reserva su riel con el
   `padding-left` del body; una barra fija además tendría que repetir esa cuenta
   y se rompería en la vista angosta, donde el sidebar pasa a `static`. */
.barra-mod{position:sticky;top:0;z-index:30;background:var(--panel);
  border-bottom:1px solid var(--borde)}
/* Mismo `max-width` que `.content`: la barra y la pantalla arrancan alineadas. */
.barra-mod-in{display:flex;align-items:center;gap:20px;height:52px;padding:0 28px;
  max-width:1600px;margin:0 auto;
  /* Nómina tiene 8 pantallas y Compras 6: en una ventana angosta la barra se
     desliza en vez de apretar los nombres o partirse en dos filas. */
  overflow-x:auto;scrollbar-width:none}
.barra-mod-in::-webkit-scrollbar{display:none}
.barra-modulo{display:flex;align-items:center;gap:7px;font-size:13px;font-weight:700;
  color:var(--texto);white-space:nowrap;flex-shrink:0;padding-right:20px;
  border-right:1px solid var(--borde);height:26px}
.barra-modulo .navicon{width:16px;height:16px;opacity:.75}
.barra-pags{display:flex;align-items:center;gap:4px}
.barra-pag{text-decoration:none;white-space:nowrap;font-size:13px;color:var(--tenue);
  padding:6px 13px;border-radius:999px;
  transition:background .12s ease, color .12s ease}
.barra-pag:hover{background:var(--fondo);color:var(--texto)}
.barra-pag:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
/* La píldora activa. `--t-lila`/`--a-lila` es el par ya medido del tema (4.96:1)
   y el mismo que usa `.chip-op.activo`: la barra no inventa un color propio. */
.barra-pag.on{background:var(--vino-tinte);color:var(--vino);font-weight:700}
.tema-bento .barra-pag.on{background:var(--t-lila);color:var(--a-lila)}

.content{padding:30px 28px;max-width:1600px;margin:0 auto}
h1{font-family:'Manrope',"Segoe UI",sans-serif;font-size:26px;font-weight:800;
  letter-spacing:-0.015em;margin-bottom:4px;line-height:1.15}
.sub{color:var(--tenue);margin-bottom:22px;font-size:14px}
.row-head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:18px}

/* ── Botones ──────────────────────────────────────────────────── */
.btn{display:inline-block;background:var(--vino);color:#fff;border:none;text-decoration:none;
  padding:10px 18px;border-radius:9px;font-size:14px;font-weight:600;cursor:pointer;
  transition:transform .2s var(--ease-spring), background .15s ease}
.btn:hover{background:var(--vino-h)}
.btn:active{transform:scale(.95)}
.btn.ghost{background:transparent;color:var(--vino);border:1px solid var(--vino)}
.btn.ghost:hover{background:var(--vino-tinte)}
.btn.sm{padding:6px 12px;font-size:13px}
.btn.gray{background:#eef0f3;color:var(--texto)}
.btn.danger{background:transparent;color:var(--peligro);border:1px solid var(--peligro)}
.btn.danger:hover{background:#fdecea}
.btn:disabled,.btn[disabled]{opacity:0.4;cursor:not-allowed;pointer-events:none}
.btn.on    {background:var(--vino);color:#fff;box-shadow:none}
.btn.active{background:var(--vino);color:#fff;box-shadow:none}

/* ── Cards / métricas ─────────────────────────────────────────── */
.cards{display:flex;gap:16px;flex-wrap:wrap;margin-bottom:26px}
.card{background:var(--panel);border:1px solid var(--borde);border-radius:10px;
  padding:18px 20px;min-width:170px}
.card .v{font-size:30px;font-weight:800;color:var(--vino)}
.card .l{color:var(--tenue);font-size:13px}
.setcard{text-decoration:none;color:var(--texto);width:200px;display:block}
.setcard .ic{font-size:26px}
.setcard .tt{font-weight:700;margin-top:6px;color:var(--vino)}
.setcard .ds{color:var(--tenue);font-size:12px;margin-top:2px}

/* ── Tablas ───────────────────────────────────────────────────── */
.panel{background:var(--panel);border:1px solid var(--borde);border-radius:10px;overflow:hidden}
/* Scroll horizontal con indicador de fade — 100% CSS, sin JS. Doble
   degradado: uno "tapa" (mismo color que el fondo, se mueve CON el
   contenido vía background-attachment:local — desaparece cuando ya no hay
   más para scrollear de ese lado) y otro "sombra" (fijo respecto al
   contenedor vía background-attachment:scroll — siempre visible en el
   borde, pero tapado por el degradado anterior cuando no hace falta).
   Sin min-width propio a propósito: el ancho natural del padding+contenido
   de las columnas ya fuerza el scroll cuando no entra, y bajo 900px ICA/
   Facturas heredan min-width:560px de .panel table — evita competir con
   ese min-width condicional que ya usa .panel para otras tablas del sistema. */
.tabla-scroll{
  overflow-x:auto;
  background:
    linear-gradient(to right, var(--panel) 30%, rgba(255,255,255,0)),
    linear-gradient(to right, rgba(255,255,255,0), var(--panel) 70%) 100% 0,
    linear-gradient(to right, rgba(34,38,46,.12), rgba(255,255,255,0) 10%),
    linear-gradient(to left, rgba(34,38,46,.12), rgba(255,255,255,0) 10%) 100% 0;
  background-repeat:no-repeat;
  background-size:40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-attachment:local, local, scroll, scroll;
}
table{width:100%;border-collapse:collapse}
th{background:var(--fondo);color:var(--tenue);text-align:left;font-size:12px;
  padding:11px 14px;font-weight:700;text-transform:uppercase;letter-spacing:.3px}
td{padding:11px 14px;border-top:1px solid var(--borde);font-size:14px}
tr:hover td{background:var(--fondo)}
.acts{display:flex;gap:7px}

/* Tinte por tipo de cliente en Facturas (2026-07-14, refinado 2026-07-15;
   cambiado de verde/azul a ambar/purpura el mismo dia -- el usuario pidio
   "otros 2 colores diferentes" para no confundirse con verde=ok/naranja=aves
   de otros badges del sistema). Nacional = ambar (#B8860B), Exportación =
   púrpura (#5B4B8A) — pareja cálido/frío elegida por el usuario entre 3
   opciones. Borde izquierdo de 5px + fondo con cuerpo suficiente para
   distinguirse de un vistazo. */
.td-num{font-variant-numeric:tabular-nums;white-space:nowrap}
.td-money{color:var(--texto);font-variant-numeric:tabular-nums;font-weight:700;white-space:nowrap}


/* Menú de 3 puntos por factura (Facturas → lista). #menu-flotante es un
   único panel "portal" pegado directo al <body> (no dentro de la tabla),
   con position:fixed y coordenadas puestas por JS — inmune a cualquier
   overflow/transform de contenedores padres (tabla, tarjetas, sidebar),
   sin importar qué tan chico sea ese contenedor. */
  line-height:1;padding:5px 11px;border-radius:7px;color:var(--tenue)}
.dots-panel{display:none;position:fixed;min-width:230px;background:var(--panel);
  border:1px solid var(--borde);border-radius:10px;
  box-shadow:0 10px 28px rgba(34,38,46,.16);padding:6px;z-index:500}
.dots-panel.open{display:block}
.dots-panel .dots-titulo{font-size:11px;font-weight:700;color:var(--tenue);
  text-transform:uppercase;letter-spacing:.3px;padding:6px 10px 4px}
.dots-panel a,.dots-panel button{display:block;width:100%;text-align:left;
  background:transparent;border:none;padding:8px 10px;border-radius:7px;
  font-size:13.5px;color:var(--texto);text-decoration:none;cursor:pointer;
  font-family:inherit}
.dots-panel a:hover,.dots-panel button:hover{background:var(--fondo);color:var(--vino)}
.dots-panel form{margin:0}
/* `.item-menu` es la clase de `ui/Menu.jsx::ItemMenu`. Hereda el mismo estilo
   que los `a`/`button` del panel: un ítem de menú se ve igual en todos los
   menús del sistema, venga de Jinja o de React. */
.dots-panel .item-menu{display:block;width:100%;text-align:left}
/* Combo estricto (`ui/ComboEstricto.jsx`). Reemplaza al `<input list>` +
   `<datalist>`: el datalist lo dibuja el sistema operativo, igual que el
   `<select>`, y además no deja mostrar POR QUÉ un valor no sirve. */
.combo{position:relative;display:flex;flex-direction:column;gap:5px}
/* ⚠️ La POSICIÓN no está acá: la calcula `ui/usePanelFlotante.js` y la aplica en
   línea, porque la lista se dibuja en un portal (`position:fixed`) y no adentro
   del campo. Acá vive solo la apariencia. Si volviera a ser `position:absolute`,
   `.tabla-scroll` la recortaría de nuevo — se veían 7 px de 129 en el
   formulario de factura, medido el 2026-08-31. */
.combo-lista{margin:0;list-style:none;overflow-y:auto;background:var(--panel);
  border:1px solid var(--borde);border-radius:10px;padding:5px;
  box-shadow:0 4px 16px rgba(0,0,0,.10)}
.combo-lista li{padding:7px 10px;border-radius:7px;cursor:pointer;font-size:13px}
.combo-lista li.res,.combo-lista li:hover{background:var(--vino-tinte);color:var(--vino)}
.hint.invalido{color:var(--peligro);font-weight:600}
.tema-bento .combo-lista{border-radius:var(--r-control)}
.tema-bento .combo-lista li{border-radius:9px}

/* Modal (`ui/Modal.jsx`). Sube acá desde el `<style>` propio de 40 líneas que
   tenía `facturas/form.html` — el guardián de estilo prohibe esos bloques
   justamente para que no haya cinco modales distintos en el sistema. */
.mdl-overlay{position:fixed;inset:0;background:rgba(20,22,26,.45);display:flex;
  align-items:center;justify-content:center;z-index:1000;padding:20px}
.mdl-box{background:var(--panel);border-radius:12px;width:100%;
  max-height:85vh;display:flex;flex-direction:column;overflow:hidden;
  box-shadow:0 20px 50px rgba(0,0,0,.25)}
.mdl-head{display:flex;align-items:center;justify-content:space-between;
  padding:16px 20px;border-bottom:1px solid var(--borde)}
.mdl-head h3{margin:0;font-size:15px}
.mdl-close{background:none;border:none;font-size:16px;cursor:pointer;color:var(--tenue)}
.mdl-body{padding:16px 20px;overflow-y:auto}
.mdl-foot{display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;
  border-top:1px solid var(--borde)}
.mdl-table{width:100%;border-collapse:collapse;font-size:13px}
.mdl-table th{text-align:left;font-size:11px;text-transform:uppercase;color:var(--tenue);
  padding:6px 8px;border-bottom:1px solid var(--borde)}
.mdl-table td{padding:6px 8px;border-bottom:1px solid var(--borde)}
.mdl-table .nr{text-align:right}
.mdl-hist{margin-top:14px;padding-top:10px;border-top:1px solid var(--borde)}
.mdl-hist-title{font-size:11px;text-transform:uppercase;color:var(--tenue);margin-bottom:6px}
.mdl-hist-row{font-size:12px;color:var(--tenue);padding:4px 0;
  display:flex;align-items:center;gap:6px}
.mdl-hist-edit{display:flex;align-items:center;gap:6px;flex:1;min-width:0}
.mdl-hist-variedad{flex-shrink:0;white-space:nowrap}
.mdl-hist-meta{flex-shrink:0;white-space:nowrap;font-size:11px}
.tema-bento .mdl-box{border-radius:var(--r-tile)}
.tema-bento .mdl-body input{height:32px}
/* ⚠️ Un icono es DECORATIVO: nunca puede ser el blanco de un clic.
   Sin esto, en un botón cuyo contenido es solo un `<svg>` el clic real del mouse
   llega con `target = <svg>` en vez del botón. Medido el 2026-08-21 con el menú
   de 3 puntos de la lista de Facturas: el botón no reaccionaba al mouse y SÍ a
   `boton.click()` desde JS — que dispara el evento con el botón como target. Un
   test de Vitest sobre el componente pasaba (ahí el clic sintético va al botón),
   así que solo se veía en un navegador de verdad, con un mouse de verdad.
   Va sobre todos los `svg` de un `.btn` y del panel, no sobre el caso puntual:
   el problema es de cualquier botón de solo-icono. */
.btn svg,.dots-panel svg,.item-menu svg{pointer-events:none}
.dots-panel hr{border:none;border-top:1px solid var(--borde);margin:4px 2px}
/* Fila de documento: nombre (abre en pestaña nueva) + ⬇ que descarga directo.
   El hover resalta toda la fila, pero cada mitad conserva su propia acción. */
.dots-panel .dots-fila{display:flex;align-items:center;gap:2px;border-radius:7px}
.dots-panel .dots-fila:hover{background:var(--fondo)}
.dots-panel .dots-fila:hover>a{color:var(--vino)}
.dots-panel .dots-fila>a{flex:1;min-width:0}
.dots-panel .dots-fila>a:hover{background:transparent}
.dots-panel a.dots-descargar{flex:0 0 auto;width:auto;padding:8px 9px;font-size:13px;
  color:var(--tenue);text-align:center}
.dots-panel a.dots-descargar:hover{background:var(--vino);color:#fff}

/* ── Refinamiento visual de Facturas (2026-07-15) — solo esta vista, vía
   clases .facturas-*; no toca .panel/.btn/.searchbar del resto del sistema.
   Mismo minimalismo y paleta (vino/blanco/gris), más aire y detalle. ──── */
/* Full-bleed (2026-07-23): la vista de Facturas usa todo el ancho del área
   de contenido (entre el riel del sidebar y el borde de la ventana) en vez
   del max-width:1200px centrado que usa el resto del sistema — se necesita
   ese ancho completo para que la tabla quepa sin scroll horizontal con
   todas las columnas en una sola línea. Solo afecta esta vista vía
   .content.facturas-full (la pone `claseContenido` del Shell; era el
   `block content_class` de base.html, borrado el 2026-09-06). */
.content.facturas-full{max-width:none;padding:24px 20px}


/* Una sola línea por celda (punto 6 del ajuste 2026-07-23): ninguna fila
   crece en altura por texto largo, así entran más filas en pantalla. */


.td-lugar-entrega{max-width:160px}

  box-shadow:0 1px 2px rgba(34,38,46,.04);
  transition:box-shadow .2s ease, border-color .2s ease}

  transition:transform .15s var(--ease-spring), background .15s ease, box-shadow .15s ease}
@keyframes fila-in{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}

/* Puntos de estado — infraestructura lista para futuros indicadores
   (pendiente / completada / con novedad); hoy no se pintan porque el modelo
   de datos aún no tiene esos estados, salvo el de descarte que ya usa su
   propio badge. */
.dot{width:7px;height:7px;border-radius:50%;display:inline-block;margin-right:5px}
.dot-red{background:var(--peligro)}
.dot-yellow{background:var(--grupo-aves)}
.dot-green{background:var(--grupo-ruscus)}

@media (prefers-reduced-motion: reduce){
}

/* ── "dónde estoy" en formularios largos: el título de la tarjeta que
   contiene el campo con foco se resalta en vino (helper genérico, no solo
   Facturas) ──────────────────────────────────────────────────────── */
.formcard h2{transition:color .15s ease}
.formcard:focus-within h2{color:var(--vino)}
@media (prefers-reduced-motion: reduce){
  .formcard h2{transition:none}
}

/* ── Formularios ──────────────────────────────────────────────── */
.formcard{background:var(--panel);border:1px solid var(--borde);border-radius:10px;
  padding:24px;margin-bottom:16px;
  transition:transform .3s var(--ease-spring), border-color .2s ease, box-shadow .3s var(--ease-spring)}
.formcard:hover{border-color:var(--vino)}
.formcard:not(.ica-grupo):hover{transform:translateY(-3px);box-shadow:0 8px 20px rgba(34,38,46,.10)}
.formcard h2,.formcard h3{font-size:16px;margin-bottom:16px}
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.field{display:flex;flex-direction:column;gap:5px}
.field.full{grid-column:1/-1}
label{font-size:12px;font-weight:700;color:var(--tenue)}
input,select,textarea{padding:9px 11px;border:1px solid var(--borde);border-radius:8px;
  font-size:14px;font-family:inherit;background:#fff;width:100%}
textarea{resize:vertical}
/* ── Foco de los controles ─────────────────────────────────────────────────
   UN solo comportamiento para todo el programa: borde vino + anillo suave.
   Decisión del usuario (2026-08-20), y `DESIGN.md` se corrigió para
   declararlo — antes decía "sin anillo adicional" y el código tenía TRES
   comportamientos distintos conviviendo:
     · el global de acá: solo borde vino
     · `.facturas-search`: anillo de 3px de --vino-tinte
     · `.fl-field`: anillo de 2.5px de vino al 10 %
   Los tres sobre el mismo control, según en qué pantalla estuvieras. Eso es
   exactamente lo que el rediseño vino a matar: "el mismo buscador" en los 11
   módulos.
   ⚠️ El anillo del campo inválido (`input.campo-invalido:focus`) se declara
   más abajo en este archivo y por eso gana: es rojo, y debe ganar. */
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--vino);
  box-shadow:0 0 0 2.5px rgba(139,26,43,.1)}
input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
.auto{color:var(--tenue);font-size:13px;font-weight:600;margin-top:10px}

/* ── Totales ──────────────────────────────────────────────────── */
.tots{display:flex;gap:26px;flex-wrap:wrap;align-items:flex-end}
.tot .l{color:var(--tenue);font-size:12px}
.tot .v{font-size:22px;font-weight:800}
.tot.big{margin-left:auto;padding-left:26px;border-left:1px solid var(--borde)}
.tot.big .l{font-weight:700;color:var(--texto)}
.tot.big .v{color:var(--vino);font-size:32px}
@media (max-width:560px){
  .tot.big{margin-left:0;padding-left:0;border-left:none;width:100%;
    padding-top:14px;border-top:1px solid var(--borde)}
}

/* ── Items factura ────────────────────────────────────────────── */
table.items input,table.items select{padding:6px 8px;font-size:13px}
table.items td{padding:6px}
/* Valor calculado de solo lectura: misma caja que un input, fondo tenue
   (señal de no editable). */
table.items .ro-cell{display:inline-block;min-width:56px;box-sizing:border-box;
  padding:6px 8px;border:1px solid var(--borde);border-radius:8px;
  background:var(--fondo);font-size:13px;text-align:right}
/* Tallos descartados junto al neto de la línea (factura con descarte). */
table.items .c_desc{color:var(--vino);font-size:11px;font-weight:600}
.linkrow{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}

/* ── Toast / flash ────────────────────────────────────────────── */
/* `pointer-events:none` en el contenedor, `auto` en cada toast: `.flash-wrap`
   es fixed y ocupa una columna arriba a la derecha, así que su área vacía se
   quedaba con los clicks de lo que hubiera debajo. Los toasts sí tienen que
   recibirlos — el de "Deshacer" lleva un botón. */
.flash-wrap{position:fixed;top:18px;right:18px;z-index:50;display:flex;flex-direction:column;
  gap:8px;pointer-events:none}
.toast{padding:12px 18px;border-radius:9px;color:#fff;font-weight:600;font-size:14px;
  box-shadow:0 4px 14px rgba(0,0,0,.15);pointer-events:auto}
.toast.ok{background:var(--ok)}.toast.err{background:var(--peligro)}

/* ── Franja de alarma del admin — SIN USO desde el 2026-08-18 ──────────────
   Pintaba las 3 alarmas de fondo (backup, cumpleaños, foto del despacho) arriba
   de cada pantalla. El usuario pidió quitarla y verlas en Administración →
   Monitoreo (`.proc-card` más abajo). Se deja el bloque, no el include: esta
   alarma ya cambió de decisión dos veces (08-11 no, 08-12 sí, 08-18 no), así que
   volver a pintarla es agregar el include de nuevo y nada más.
   El nombre viejo era solo `.alerta-backup`; el alias quedó del rename del
   2026-08-12. */
.alerta-backup,.alerta-admin{display:flex;gap:10px;align-items:flex-start;margin:0 0 16px;
  padding:12px 16px;border-radius:10px;background:#FDECEA;
  border:1px solid var(--peligro);color:#7A2318;font-size:13.5px;line-height:1.45}
.alerta-backup svg,.alerta-admin svg{flex:0 0 auto;margin-top:1px;color:var(--peligro)}
.alerta-backup strong,.alerta-admin strong{display:block;font-weight:700;font-size:14px}
.alerta-backup span,.alerta-admin span{color:#8A3A2E}
/* Despachos va a pantalla completa: ahí la franja cuelga del <body> y no
   hereda el padding de ningún contenedor. */
body > .alerta-backup,body > .alerta-admin{margin:12px 16px 0}
/* ── Procesos automáticos (Monitoreo) — reemplazan la franja de arriba ──── */
.proc-titulo{font-size:15px;font-weight:700;margin:0 0 10px}
.proc-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:12px;margin:0 0 18px}
.proc-card{border:1px solid var(--linea);border-radius:10px;padding:12px 14px;
  background:var(--panel)}
.proc-card.malo{border-color:var(--peligro);background:#FDECEA}
/* El badge de estado usa un rojo clarísimo (#FCE9EC) que sobre el fondo
   de la tarjeta en rojo queda invisible: acá va en blanco. */
.proc-card.malo .badge-status.danger{background:#fff}
.proc-head{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
.proc-head strong{font-size:13.5px}
.proc-cadencia{color:var(--tenue);font-size:12px}
.proc-detalle{margin-top:8px;font-size:12.5px;line-height:1.45;color:#7A2318}
.proc-detalle strong{display:block;font-weight:700;margin-bottom:2px}

.pill{font-size:11px;padding:2px 9px;border-radius:20px;background:var(--vino-tinte);
  color:var(--vino);font-weight:700}
a.plain{color:var(--vino);text-decoration:none;font-weight:600}
a.plain:hover{text-decoration:underline}

/* ── Badges compartidos: grupo botánico ICA y estado (reemplazan los pills
   de color inline duplicados en Compras/ICA/Aforos/Correos) ─────────────── */
.badge-grupo,.badge-status{font-size:12px;font-weight:700;padding:2px 10px;
  border-radius:20px;white-space:nowrap;display:inline-flex;align-items:center;gap:4px}
.badge-grupo.aves,.badge-status.warn{background:#FFF4E5;color:var(--grupo-aves)}
.badge-grupo.ruscus,.badge-status.ok{background:#E7F6EC;color:var(--grupo-ruscus)}
.badge-grupo.hydrangea{background:#EAF3FE;color:var(--grupo-hydrangea)}
.badge-grupo.otro,.badge-status.muted{background:#EEF0F3;color:#5A6270}
.badge-status.danger{background:#FCE9EC;color:var(--peligro)}
.badge-status.info{background:#EFF6FF;color:#2563EB}

/* ── Pantalla de carga ────────────────────────────────────────── */
.loader{position:fixed;inset:0;z-index:200;display:none;align-items:center;
  justify-content:center;background:rgba(245,244,242,.85);
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}
.loader.show{display:flex;animation:lfade .15s ease}
.loader-box{display:flex;flex-direction:column;align-items:center;gap:14px}
.spin{width:48px;height:48px;border:4px solid #E6E1E3;border-top-color:var(--vino);
  border-radius:50%;animation:spin .8s linear infinite}
.spin.sm{width:28px;height:28px;border-width:3px}
.loader-txt{color:var(--vino);font-weight:700;letter-spacing:1px;font-size:13px;
  animation:pulse 1.2s ease-in-out infinite}
@keyframes spin{to{transform:rotate(360deg)}}
@keyframes pulse{0%,100%{opacity:.5}50%{opacity:1}}
@keyframes lfade{from{opacity:0}to{opacity:1}}

/* ── Animaciones de interfaz ──────────────────────────────────── */
.content{animation:rise .28s ease}
@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.card{transition:transform .3s var(--ease-spring), border-color .2s ease, box-shadow .3s var(--ease-spring)}
.card:hover{transform:translateY(-3px);border-color:var(--vino);box-shadow:0 8px 20px rgba(34,38,46,.10)}
.card.hero,.kpi.hero{box-shadow:0 6px 18px rgba(34,38,46,.09);border-color:#EDD9DC}
.panel tbody tr{transition:background .12s ease}
/* Tarjetas de grupo botánico en Movimiento ICA (una por grupo, en factura.html):
   mismo lenguaje de hover que .card, aplicado solo al borde (sin transform,
   porque son tarjetas grandes con tablas de asignación — un lift constante
   mientras el usuario llena inputs sería ruido, no ayuda). */
.formcard.ica-grupo{transition:border-color .15s ease}
.formcard.ica-grupo:hover{border-color:var(--vino)}
.toast{animation:slidein .25s ease, fade2 4s forwards}
@keyframes slidein{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:none}}
/* Termina en `visibility:hidden`, no solo en `opacity:0`. Un elemento
   transparente sigue capturando clicks: el toast de un flash se quedaba
   invisible arriba a la derecha y **dejaba inalcanzable** lo que hubiera
   debajo hasta recargar la página. Encontrado abriendo Despachos con un
   navegador el 2026-08-13: tapaba el botón «Etiquetas Riobamba». */
@keyframes fade2{0%,85%{opacity:1;visibility:visible}
  99%{opacity:0;visibility:visible}100%{opacity:0;visibility:hidden}}
/* El de "Deshacer" NO se desvanece: se quita solo del DOM al resolverse
   (`confirm-modal.js`). Con la animación general se volvía invisible a los 4 s
   mientras su cuenta regresiva es de 5 s — o sea que el último segundo el botón
   estaba ahí, activo, y no se veía, con la barra de progreso todavía corriendo. */
.confirm-toast{animation:slidein .25s ease}

@media (prefers-reduced-motion: reduce){
  .content{animation:none}
  .card,.btn,.panel tbody tr,.sidebar,.sidebar nav a,.export,.side-user,
  .sidebar nav a span,.side-user-info,.export span,.modcard,.formcard,.formcard.ica-grupo,
  .kpi,.chartcard{transition:none!important}
  .card:hover,.kpi:hover,.chartcard:hover,.formcard:not(.ica-grupo):hover{transform:none!important}
  .btn:active{transform:none}
  /* Sin `slidein`, pero `fade2` se queda: no es decoración, es lo que saca al
     toast del paso (ver su comentario arriba). */
  .toast{animation:fade2 4s forwards}
  .confirm-toast{animation:none}
  .spin{animation-duration:1.6s}
  .loader-txt{animation:none}
}

/* ── Barra de búsqueda ────────────────────────────────────────── */
.searchbar{display:flex;gap:8px;align-items:center;margin-bottom:18px}
.searchbar input[type=search]{flex:1;max-width:380px;padding:9px 12px;
  border:1px solid var(--borde);border-radius:9px;font-size:14px}

/* ── Informes ─────────────────────────────────────────────────── */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:20px}
.kpi{background:var(--panel);border:1px solid var(--borde);border-radius:10px;padding:18px 20px;
  transition:transform .3s var(--ease-spring), border-color .2s ease, box-shadow .3s var(--ease-spring)}
.kpi:hover{transform:translateY(-3px);border-color:var(--vino);box-shadow:0 8px 20px rgba(34,38,46,.10)}
.kpi .v{font-size:26px;font-weight:800;color:var(--vino)}
.kpi .l{color:var(--tenue);font-size:13px;margin-top:4px}
.charts{display:grid;grid-template-columns:repeat(auto-fit,minmax(420px,1fr));gap:18px}
.chartcard{background:var(--panel);border:1px solid var(--borde);border-radius:10px;padding:18px 20px;
  transition:transform .3s var(--ease-spring), border-color .2s ease, box-shadow .3s var(--ease-spring)}
.chartcard:hover{transform:translateY(-3px);border-color:var(--vino);box-shadow:0 8px 20px rgba(34,38,46,.10)}
.chartcard h3{margin:0 0 4px;color:var(--vino);font-size:15px}
.chartcard .chart-sub{color:var(--tenue);font-size:12px;margin:0 0 14px}
.chartcard.wide{grid-column:1 / -1}
.kpi.muted .v{color:var(--tenue);font-size:20px}

.filterbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;background:var(--panel);
  border:1px solid var(--borde);border-radius:10px;padding:12px 16px;margin-bottom:18px}
.filterbar label{font-size:11px;color:var(--tenue);text-transform:uppercase;
  letter-spacing:0.04em;display:block;margin-bottom:2px}
.filterbar .fgroup{display:flex;flex-direction:column}
.filterbar select{padding:7px 10px;border:1px solid var(--borde);border-radius:8px;
  font-size:13px;background:#fff;color:var(--texto);min-width:150px}
.filterbar .clear-filters{font-size:12.5px;color:var(--vino);text-decoration:none;
  margin-left:auto;align-self:flex-end;padding:7px 0}
.filterbar .clear-filters:hover{text-decoration:underline}

.grupo-dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px;
  vertical-align:middle}
.legend-grupos{display:flex;flex-wrap:wrap;gap:10px 16px;margin:0 0 14px;font-size:12.5px;color:var(--texto)}

/* ── Pestañas (Documentos) ────────────────────────────────────── */
.doctabs{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}
.doctab{display:inline-flex;align-items:center;gap:8px;text-decoration:none;
  padding:9px 16px;border-radius:10px;background:var(--panel);color:var(--texto);
  border:1px solid #E4E7EC;font-weight:600;font-size:14px;transition:all .15s ease}
.doctab:hover{border-color:var(--vino);color:var(--vino)}
.doctab.on{background:var(--vino);color:#fff;border-color:var(--vino)}
.doctab .badge{font-size:11px;font-weight:800;background:rgba(0,0,0,.12);padding:1px 8px;border-radius:20px}
.doctab.on .badge{background:rgba(255,255,255,.25)}

/* ── Pistas de ayuda ──────────────────────────────────────────── */
.hint{display:block;color:var(--tenue);font-size:11px;margin-top:3px;font-weight:400}
.field input:invalid:not(:placeholder-shown),
.field select:invalid:not(:placeholder-shown){border-color:#E0A0A8}

/* ── Responsivo ───────────────────────────────────────────────── */
@media (max-width: 900px){
  body{padding-left:0}
  .sidebar{width:100%;height:auto;position:static;padding:12px;
    border-right:none;border-bottom:0.5px solid var(--borde);overflow-y:visible}
  .sidebar nav{flex-direction:row;flex-wrap:wrap;gap:5px;padding:6px 0}
  .nav-sep{display:none}
  .nav-label{width:100%;padding:4px 4px 2px}
  .sidebar nav a{padding:8px 11px;font-size:13px;border-left:none;border-radius:8px;
    border-bottom:2px solid transparent}
  .sidebar nav a.on{border-left:none;border-bottom-color:var(--vino);background:var(--vino-tinte)}
  .brand{padding:8px 4px 10px;border-bottom:none}
  .side-footer{border-top:none;padding:6px 0 0;display:flex;align-items:center;
    justify-content:space-between;flex-wrap:wrap;gap:8px}
  .side-user{padding:2px 4px}
  .export{padding:8px 4px}
  .tarjetas{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
  .barra-mod-in{padding:0 16px;gap:14px}
  .content{padding:18px 16px;max-width:100%;margin:0}
  .row-head{flex-direction:column;gap:12px;align-items:stretch}
  .acts{flex-wrap:wrap}
  .grid{grid-template-columns:1fr 1fr}
  .charts{grid-template-columns:1fr}
  .panel{overflow-x:auto}
  .panel table{min-width:560px}
  h1{font-size:24px}
  /* Objetivo táctil: en escritorio .btn.sm prioriza densidad de tabla; en
     tablet/móvil (contexto táctil real) sube a ~44px de alto sin cambiar su
     tamaño visual en desktop. */
  .btn.sm{min-height:44px;display:inline-flex;align-items:center;justify-content:center;
    padding-top:0;padding-bottom:0}
  table.items input,table.items select{min-height:44px}
}
@media (max-width: 560px){
  .grid{grid-template-columns:1fr}
  .kpis{grid-template-columns:1fr 1fr}
  .tots{gap:14px}
  .searchbar{flex-wrap:wrap}
  .searchbar input[type=search]{max-width:100%;width:100%}
  .btn{padding:9px 14px}
}

/* ── Pantalla de inicio (2026-07-14: foto de hydrangeas a pantalla
   completa como fondo fijo, con la barra superior y el saludo flotando
   encima en tarjetas blancas — sustituye el fondo claro con gradiente
   sutil de la versión anterior). ─────────────────────────────────── */
/* ⚠️ **El fondo lo pone React en línea, no esta regla** (2026-09-03): su URL
   la resuelve `url_for` en el servidor y el CSS no puede saber la ruta del
   estático. Acá quedan solo el encuadre y el respaldo.

   Hasta esa fecha la foto se bajaba de `images.unsplash.com` en cada carga —la
   décima imagen externa de esta pantalla, y la más pesada—. Ahora vive en
   `static/img/inicio/fondo.jpg`, 155 kB, por la misma razón por la que AG Grid
   salió del CDN el 2026-09-02: la primera pantalla del sistema no puede
   depender de que un tercero responda. */
.home-body{display:block;position:relative;min-height:100vh;
  background-color:var(--fondo);
  background-position:center; background-size:cover;
  background-repeat:no-repeat; background-attachment:fixed}
.home-top{display:flex;justify-content:space-between;align-items:center;
  padding:16px 36px;max-width:1100px;margin:0 auto;
  background:rgba(255,255,255,.9);backdrop-filter:blur(6px);
  border-radius:0 0 12px 12px}
.home-brand{display:flex;align-items:center;gap:12px}
.home-brand .brand-f{font-size:15px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--vino)}
.home-logo{height:46px;width:auto;display:block}
.home-user{display:flex;align-items:center;gap:14px;color:var(--tenue);font-size:13px}
.home-user span{display:inline-flex;align-items:center;gap:6px}
.home-user .navicon{width:15px;height:15px;flex-shrink:0}
.home-wrap{max-width:1100px;margin:0 auto;padding:8px 36px 28px}
.home-hello{text-align:center;margin:30px 0}
.hello-card{display:inline-block;background:rgba(255,255,255,.94);
  padding:16px 30px;border-radius:12px;box-shadow:0 6px 22px rgba(0,0,0,.18)}
.home-hello h1{font-family:'Manrope',"Segoe UI",sans-serif;font-weight:800;
  font-size:clamp(22px,3.2vw,28px);margin-bottom:4px;color:var(--texto);letter-spacing:-0.02em;
  text-wrap:balance}
.home-hello p{color:var(--tenue);font-size:13px}
.home-hello p::first-letter{text-transform:uppercase}

/* ── Grid de módulos: estructura original (una sola cuadrícula, todas las
   tarjetas al mismo nivel) — el usuario pidió explícitamente conservarla.
   Ahora reutiliza el patrón `.card` plano del resto del sistema en vez de
   foto + duotono. ────────────────────────────────────────────────── */
.home-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.modcard{background:var(--panel);color:var(--texto);border:1px solid var(--borde);
  border-radius:12px;overflow:hidden;text-decoration:none;
  display:flex;flex-direction:column;gap:0;box-shadow:0 4px 16px rgba(0,0,0,.12);
  transition:border-color .15s ease, transform .15s ease, box-shadow .15s ease}
.modcard:hover{border-color:var(--vino);transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.08)}
.modcard:active{transform:translateY(0) scale(.99)}
.modcard:focus-visible{outline:2px solid var(--vino);outline-offset:2px}

.modimg{height:130px;background-size:cover;background-position:center;background-color:var(--vino-tinte)}
.modbody{padding:16px 18px 18px;display:flex;flex-direction:column;flex:1}

/* Entrada escalonada al cargar /inicio — la única pantalla del sistema
   donde se justifica un momento de "llegada" (ver DESIGN.md, registro
   product: nada de coreografías por página, pero un stagger acotado a
   una sola lista sí es legítimo). */
@keyframes home-card-rise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
.home-grid .modcard{animation:home-card-rise .55s cubic-bezier(.16,1,.3,1) both}
.home-grid .modcard:nth-child(1){animation-delay:.03s}
.home-grid .modcard:nth-child(2){animation-delay:.09s}
.home-grid .modcard:nth-child(3){animation-delay:.15s}
.home-grid .modcard:nth-child(4){animation-delay:.21s}
.home-grid .modcard:nth-child(5){animation-delay:.27s}

/* Tarjetas de módulo con icono en vez de foto (ej. panel de Administración,
   donde una foto de stock no encaja con herramientas técnicas). */
.modicon{display:flex;align-items:center;justify-content:center;width:44px;
  height:44px;border-radius:10px;background:var(--vino-tinte);margin-bottom:14px}
.modicon .navicon{width:22px;height:22px;color:var(--vino)}

.modcard .modtitle{font-size:17px;font-weight:800;color:var(--texto);letter-spacing:-0.01em}
.modcard .moddesc{color:var(--tenue);font-size:13px;flex:1;line-height:1.5;margin-top:6px}
.modcard .modgo{font-weight:700;color:var(--vino);font-size:13px;margin-top:14px;
  display:inline-flex;align-items:center;gap:5px;transition:gap .2s ease}
.modcard:hover .modgo{gap:9px}

@media (prefers-reduced-motion: reduce){
  .home-grid .modcard{animation:none}
}


@media (max-width: 820px){
  .home-grid{grid-template-columns:1fr}
  .home-top,.home-wrap{padding-left:18px;padding-right:18px}
}

/* Campo de catálogo con valor fuera de la lista (combo estricto) */
input.campo-invalido{border-color:#B3261E;background:#FEF7F6}
input.campo-invalido:focus{box-shadow:0 0 0 2.5px rgba(179,38,30,.12)}

/* ── Modal de confirmación + toast de deshacer (reemplaza confirm() nativo,
   2026-07-12) ─────────────────────────────────────────────────────────── */
.confirm-scrim{position:fixed;inset:0;background:rgba(34,38,46,.35);z-index:60;
  opacity:0;pointer-events:none;transition:opacity .3s var(--ease-spring)}
.confirm-scrim.open{opacity:1;pointer-events:auto}
.confirm-modal{position:fixed;top:50%;left:50%;transform:translate(-50%,-48%);
  z-index:61;background:var(--panel);border:1px solid var(--borde);
  border-radius:10px;box-shadow:0 20px 48px rgba(0,0,0,.18);
  padding:22px 24px;max-width:420px;width:calc(100% - 40px);
  opacity:0;pointer-events:none;transition:opacity .3s var(--ease-spring), transform .3s var(--ease-spring)}
.confirm-modal.open{opacity:1;pointer-events:auto;transform:translate(-50%,-50%)}
.confirm-modal-msg{font-size:14.5px;color:var(--texto);line-height:1.5;margin:0 0 18px}
.confirm-modal-acts{display:flex;justify-content:flex-end;gap:10px}

.confirm-toast{display:flex;align-items:center;gap:14px;position:relative;
  overflow:hidden;padding-bottom:16px}
.confirm-toast-texto{flex:1}
.confirm-toast-deshacer{all:unset;cursor:pointer;font-weight:800;
  text-decoration:underline;flex-shrink:0;color:#fff}
.confirm-toast-barra-wrap{position:absolute;left:0;right:0;bottom:0;height:3px;
  background:rgba(255,255,255,.3)}
.confirm-toast-barra{width:100%;height:100%;background:#fff;transition:width linear}

@media (prefers-reduced-motion: reduce){
  .confirm-scrim,.confirm-modal{transition:none}
  .confirm-toast-barra{transition:none}
}

/* ── Modal de etiqueta suelta (botón "Nueva etiqueta" del sidebar, 2026-08-18)
   Mismo lenguaje visual que `.confirm-modal` pero con clases propias: ese lo
   crea y lo referencia `confirm-modal.js`, y compartir las clases acoplaría dos
   modales que no tienen nada que ver. Los campos usan los estilos globales de
   `label`/`input`/`textarea`/`.btn`, así que acá solo va la caja. ──────────── */
.etq-scrim{position:fixed;inset:0;background:rgba(34,38,46,.35);z-index:60;
  opacity:0;pointer-events:none;transition:opacity .3s var(--ease-spring)}
.etq-scrim.open{opacity:1;pointer-events:auto}
.etq-modal{position:fixed;top:50%;left:50%;transform:translate(-50%,-48%);
  z-index:61;background:var(--panel);border:1px solid var(--borde);
  border-radius:10px;box-shadow:0 20px 48px rgba(0,0,0,.18);
  padding:22px 24px;max-width:420px;width:calc(100% - 40px);
  opacity:0;pointer-events:none;transition:opacity .3s var(--ease-spring), transform .3s var(--ease-spring)}
.etq-modal.open{opacity:1;pointer-events:auto;transform:translate(-50%,-50%)}
.etq-modal h2{font-size:17px;margin:0 0 2px}
.etq-modal .sub{margin-bottom:18px;font-size:13px}
.etq-campo{display:flex;flex-direction:column;gap:5px;margin-bottom:16px}
.etq-modal textarea{min-height:96px;line-height:1.45}
.etq-modal input[type=number]{width:110px}
.etq-acts{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}

@media (prefers-reduced-motion: reduce){
  .etq-scrim,.etq-modal{transition:none}
}

/* ── Barra de filtros (.fl-*) ─────────────────────────────────────────────
   Vivía en un `<style>` en línea dentro de `compras/templates/compras/lista.html`
   y la usaban DOS módulos: Compras y Estados de Cuenta. O sea que el buscador
   de Estados de Cuenta se renderizaba **sin estilos** — input sin alto, sin
   borde, sin radio y sin el foco vino, y la lupa `⌕` (que necesita el
   `position:absolute` de `.fl-ico`) saliendo como texto suelto delante del
   campo. Medido el 2026-08-20, al migrar Estados de Cuenta a React.
   No hay ningún selector `.fl-*` más en este archivo, así que subirlo acá no
   cambia nada en Compras: son las mismas reglas, sin conflicto de
   especificidad. ─────────────────────────────────────────────────────────── */
.fl-bar{margin-bottom:20px}
.fl-fields{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.fl-field{position:relative;display:flex;align-items:center}
.fl-field input,.fl-field select{height:36px;padding:0 12px;border:1px solid var(--borde);
  border-radius:8px;font-size:13px;font-family:inherit;background:var(--panel);
  color:var(--texto);min-width:0}
.fl-field input:focus-visible,.fl-field select:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
.fl-wide input{padding-left:30px;padding-right:32px;width:220px}
.fl-ico{position:absolute;left:9px;color:var(--tenue);pointer-events:none;
  display:flex;align-items:center}
.fl-field input[type=date]{width:140px}
.fl-field:not(.fl-wide) input:not([type=date]){width:160px}

/* ── Estados de carga (esqueletos) ────────────────────────────────────────
   Para las pantallas de React, que dibujan el sidebar y el encabezado al
   instante y solo esperan los datos. El `#loader` de `ui.js` no sirve acá:
   tapa la pantalla entera, y lo que falta es una tabla.
   Respeta `prefers-reduced-motion` — un pulso infinito es justamente lo que
   esa preferencia pide apagar. `.sr-only` ya existe más arriba (línea 26), no
   se redefine. ──────────────────────────────────────────────────────────── */
.skel-wrap{padding:14px}
.skel-fila{height:38px;border-radius:8px;margin-bottom:8px;
  background:linear-gradient(90deg,var(--fondo) 25%,#EDEFF2 37%,var(--fondo) 63%);
  background-size:400% 100%;animation:skel 1.4s ease infinite}
.skel-fila:last-child{margin-bottom:0}
@keyframes skel{0%{background-position:100% 50%}100%{background-position:0 50%}}
@media (prefers-reduced-motion: reduce){
  .skel-fila{animation:none}
}

/* ── Acción discreta de fila (.btn.plano) ─────────────────────────────────
   Para la acción repetida en cada fila de una lista larga. El listado de
   Estados de Cuenta tenía **86 botones `.btn.ghost.sm` idénticos** con borde
   vino, uno por cliente: el borde se repetía 86 veces y competía con el dato
   que el operador está buscando, que es el nombre. Sin borde ni fondo, la fila
   vuelve a leerse como una lista. Decisión del usuario, 2026-08-20.
   Conserva el objetivo táctil de 44px que `.btn.sm` gana en ≤900px. ─────── */
.btn.plano{background:transparent;color:var(--vino);border:none;font-weight:700;
  padding:6px 8px}
.btn.plano:hover{background:var(--vino-tinte)}
.btn.plano:focus-visible{outline:2px solid var(--vino);outline-offset:2px}

/* ── Aviso informativo (.aviso) ───────────────────────────────────────────
   Un dato que hay que leer ANTES de leer los números de la pantalla. En
   Estados de Cuenta la nota «Cartera solo tiene datos completos desde enero de
   2026» era la letra más chica de la pantalla (12px, `--tenue`, debajo de los
   KPIs) y es justamente lo que explica por qué las facturas viejas salen sin
   pagos. Jerarquía invertida: el que explica iba después y más chico que lo
   explicado. Decisión del usuario, 2026-08-20. ──────────────────────────── */
/* ⚠️ La primera versión de esto (2026-08-20, más temprano) usaba
   `border-left:3px solid` y un fondo tintado. Violaba un Don't explícito de
   `DESIGN.md`: «no usar border-left/border-right de más de 1px como franja de
   acento decorativa en cards o listas», cuya única excepción es el indicador
   del ítem activo del sidebar. Ahora: superficie blanca, borde de 1px como
   toda card del sistema, y el color vive solo en el ícono y en la palabra que
   importa. El aviso sigue leyéndose de un vistazo y deja de inventar un
   lenguaje propio. */
.aviso{display:flex;gap:9px;align-items:center;background:var(--panel);
  border:1px solid var(--borde);border-radius:8px;padding:9px 14px;
  margin-bottom:8px;font-size:13px;line-height:1.45;color:var(--texto)}
.aviso .aviso-ico{flex-shrink:0;display:flex;color:var(--tenue)}
.aviso.peligro .aviso-ico{color:var(--peligro)}
.aviso.ok .aviso-ico{color:var(--ok)}
.aviso strong{font-weight:800}
.aviso.peligro strong{color:var(--peligro)}
.aviso-sub{color:var(--tenue)}

/* ── Filtros como chips (opción C, 2026-08-20) ─────────────────────────────
   Lo que la pantalla está filtrando queda A LA VISTA y se quita desde el
   propio chip, en vez de esconderse dentro de un `<select>` que hay que abrir
   para saber qué dice. El botón «+ Filtro» abre el menú de los que faltan.
   Reemplaza la barra de filtros `.fl-*` en las pantallas migradas; `.fl-*`
   sigue vivo mientras queden módulos en Jinja. ─────────────────────────── */
.chips{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-bottom:18px}
.chip{display:inline-flex;align-items:center;gap:7px;background:var(--vino-tinte);
  color:var(--vino);border:none;border-radius:20px;padding:5px 8px 5px 12px;
  font-size:12px;font-weight:700;font-family:inherit;line-height:1.35}
.chip-quitar{all:unset;display:flex;cursor:pointer;color:inherit;opacity:.7;
  border-radius:50%;padding:1px}
.chip-quitar:hover{opacity:1;background:rgba(139,26,43,.12)}
.chip-quitar:focus-visible{outline:2px solid var(--vino);outline-offset:1px;opacity:1}
.chip select{all:unset;cursor:pointer;font-weight:700;font-family:inherit;
  font-size:12px;color:inherit}
.chip select:focus-visible{outline:2px solid var(--vino);outline-offset:2px;border-radius:4px}
/* ⚠️ El `all:unset` del select le saca TAMBIÉN la flecha nativa, y sin ella el
   chip se lee como texto fijo: nadie descubre que el idioma se puede cambiar.
   Visto en pantalla el 2026-08-20. La flecha se repone con un ::after en la
   etiqueta que lo envuelve. */
.chip-select{display:inline-flex;align-items:center;gap:5px;cursor:pointer}
.chip-select::after{content:"";width:0;height:0;flex-shrink:0;
  border-left:3.5px solid transparent;border-right:3.5px solid transparent;
  border-top:4px solid currentColor;opacity:.65}
.chip-select:hover::after{opacity:1}
.chip-agregar{display:inline-flex;align-items:center;gap:6px;background:transparent;
  color:var(--tenue);border:1px dashed var(--borde);border-radius:20px;
  padding:5px 12px;font-size:12px;font-weight:700;font-family:inherit;
  cursor:pointer;line-height:1.35}
.chip-agregar:hover{border-color:var(--vino);color:var(--vino);border-style:solid}
.chip-agregar:focus-visible{outline:2px solid var(--vino);outline-offset:2px}

/* ── KPIs segmentados (opción C) ───────────────────────────────────────────
   UN panel dividido por bordes de 1px, en vez de N cards separadas: menos
   cajas apiladas para la misma información. Convive con `.kpis`/`.kpi`, que
   siguen sirviendo donde las tarjetas son navegables o clicables.
   ⚠️ El segmento destacado usa `--vino-tinte` como fondo. `DESIGN.md` decía
   «nunca como color de superficie grande»; se ajustó esa regla el 2026-08-20
   por decisión del usuario, acotándola: vale en un segmento de panel, no en
   una superficie de pantalla. ─────────────────────────────────────────── */
.kpis-seg{background:var(--panel);border:1px solid var(--borde);border-radius:10px;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  overflow:hidden;margin-bottom:14px}
.kpis-seg .kseg{display:block;padding:16px 20px;border-left:1px solid var(--borde)}
.kpis-seg .kseg:first-child{border-left:none}
.kpis-seg .kseg-l{color:var(--tenue);font-size:12px;font-weight:700;
  letter-spacing:0.3px;text-transform:uppercase}
.kpis-seg .kseg-v{font-size:26px;font-weight:800;color:var(--texto);
  font-variant-numeric:tabular-nums;margin-top:2px;line-height:1.15}
.kpis-seg .kseg.destacado{background:var(--vino-tinte)}
.kpis-seg .kseg.destacado .kseg-l,.kpis-seg .kseg.destacado .kseg-v{color:var(--vino)}

/* Cabecera de panel: aloja el título y el buscador de la tabla (opción C).
   El buscador vive ACÁ y no en una barra aparte — una capa menos de chrome. */
.panel-cab{display:flex;justify-content:space-between;align-items:center;gap:14px;
  padding:12px 14px;border-bottom:1px solid var(--borde);flex-wrap:wrap}
.panel-cab h3{font-size:15px;font-weight:700;margin:0}
.panel-cab .cuenta{color:var(--tenue);font-weight:500}

@media (max-width: 560px){
  .kpis-seg{grid-template-columns:1fr}
  .kpis-seg .kseg{border-left:none;border-top:1px solid var(--borde)}
  .kpis-seg .kseg:first-child{border-top:none}
}


/* ══════════════════════════════════════════════════════════════════════════
   TEMA BENTO — acotado a las pantallas migradas a React
   ══════════════════════════════════════════════════════════════════════════
   Decisión del usuario del 2026-08-20, elegida sobre 10 direcciones visuales
   (lienzo: «Diez estilos para Santillana»). Mosaico de tiles con tintes
   pastel y acento lila.

   ⚠️ **EL VINO SALE DEL SOFTWARE.** Se le dijo dos veces que `#8B1A2B` está en
   el logo y en los PDFs oficiales DIAN/ICA impresos, y que abandonarlo hace que
   lo digital y lo impreso dejen de parecer la misma empresa. Mantuvo la
   decisión. **Los PDFs y el Excel siguen en vino**: los genera ReportLab y
   openpyxl del lado del servidor y no leen este archivo. O sea que la pantalla
   y el documento que recibe el cliente ya NO comparten paleta. Es la
   consecuencia asumida, no un olvido.

   ⚠️ **EL ALCANCE ES `.tema-bento`, NO EL ARCHIVO.** La clase la pone
   `react_base.html` sobre `#root`, así que solo alcanza a lo que se dibuja
   dentro de React. Lo que queda afuera conserva el vino y Manrope, pero ya NO
   son módulos: son `login.html` y `error.html` (remedido el 09-07 — esta línea
   decía «los 10 que siguen en Jinja», y no queda ninguno).
   El sidebar hereda estas variables porque vive DENTRO del árbol de React
   (`Shell` lo renderiza), así que hasta el 2026-09-02 **cambiaba de color según
   el módulo**: lila en uno migrado, vino en uno sin migrar. Ya no puede pasar
   —todas las entradas son React—, y se deja escrito porque no era un bug: se le
   mostró el parpadeo al usuario y lo aceptó. ⚠️ Esta nota ponía como ejemplo
   «Estados de Cuenta», que **dejó de ser un módulo el 2026-09-07** (se mudó a
   Cartera).

   ⚠️ **POR QUÉ SE REDEFINEN LOS TOKENS EXISTENTES en vez de crear nombres
   nuevos:** las ~48 reglas de este archivo ya referencian `--vino`,
   `--vino-tinte`, `--fondo`, etc. Redefinirlos dentro del scope hace que
   botones, sidebar, chips y avisos sigan al tema sin tocar una sola regla.
   El nombre `--vino` pasa a ser un ROL («el acento»), no un color. Si algún día
   el tema se vuelve global, hay que renombrarlos de verdad.
   ══════════════════════════════════════════════════════════════════════════ */
.tema-bento{
  /* Los tokens de siempre, re-apuntados. El nombre es el rol, no el color. */
  --vino:#6D4AFF; --vino-h:#5A3AE0; --vino-tinte:#EFEAFE;
  --fondo:#F4F5F9; --panel:#FFFFFF; --texto:#171A21;
  /* ⚠️ #6B7280, el gris de la maqueta, daba 4.44:1 sobre este fondo — falla
     4.5:1 por poco, y los rótulos de tile son de 12px (texto de cuerpo).
     Medido el 2026-08-20. #616A78 da 5.47:1 sobre blanco y 5.02:1 sobre el
     fondo, sin cambiar la temperatura del gris. */
  --tenue:#616A78;
  --borde:#E6E8F0; --ok:#0E9F6E; --peligro:#F05252;
  /* ⚠️ `--borde` (#E6E8F0) da 1.22:1 contra el panel blanco: sirve para separar
     zonas, NO para dibujar el contorno de un control. WCAG 1.4.11 pide 3:1 para
     el límite de un componente. `--linea-control` da 3.67:1 sobre blanco,
     3.37:1 sobre el fondo y 3.12:1 sobre el tinte lila — medido el 2026-08-20.
     ✅ Desde el 2026-08-21 lo usan TAMBIÉN las cajas de texto, los `select` y
     los `textarea`: iban con `border:none` sobre `--fondo` y eran invisibles
     fuera de un tile. Con eso quedó cerrada la deuda de 1.4.11 que este mismo
     comentario declaraba abierta el día anterior. */
  --linea-control:#8681A9;
  /* Los cuatro tintes del mosaico y su acento. */
  /* ⚠️ `--a-lila` NO es `--vino`, aunque nació igual (#6D4AFF). Se separaron
     el 2026-08-20: como TEXTO sobre `--t-lila` daba **4.39:1** y falla el 4.5:1
     de texto de cuerpo. Y no era un caso teórico — lo usaban el chip activo de
     Documentos, el encabezado de mes, y la opción resaltada del desplegable, o
     sea justo lo que el operador mira con el teclado. #6540F5 da 4.96:1 sobre el
     tinte. `--vino` sigue en #6D4AFF: ahí es RELLENO, no texto.
     Los otros tres acentos (3.04 / 3.11 / 4.43 sobre su tinte) solo se usan en
     `.tile-v`, que es texto grande — 3:1 — y por eso pasan. Si alguno se usa
     para texto chico, lo caza `test_ningun_par_del_tema_baja_del_minimo`. */
  --t-lila:#EFEAFE;    --a-lila:#6540F5;
  --t-menta:#E4F7EE;   --a-menta:#0E9F6E;
  --t-durazno:#FFEFE6; --a-durazno:#F05252;
  --t-cielo:#E7F1FE;   --a-cielo:#1C64F2;
  /* Radios del mosaico: tile 22, control 14. Mucho más abiertos que los
     10/9 del sistema anterior. */
  --r-tile:22px; --r-control:14px;
  font-family:'Figtree','Segoe UI',system-ui,Arial,sans-serif;
  background:var(--fondo);
}
.tema-bento h1,.tema-bento h2,.tema-bento h3,.tema-bento .brand-f{
  font-family:'Figtree','Segoe UI',system-ui,Arial,sans-serif}
.tema-bento h1{font-weight:800;letter-spacing:-.03em}

/* ⚠️ CIFRA TABULAR OBLIGATORIA EN TODA COLUMNA DE PLATA.
   Medido el 2026-08-20 con Playwright: en Figtree, `1111111111` mide **165 px**
   y `0000000000` mide **256 px** — 91 px de diferencia cada 10 dígitos, porque
   el `1` es muy angosto. Con `tabular-nums` las dos miden 249. Manrope
   perdonaba más este olvido; Figtree no. Sin esto, una columna de saldos se
   desalinea a la vista. */
.tema-bento .num,
.tema-bento td[style*="right"],
.tema-bento .tile-v,
.tema-bento .kseg-v{font-variant-numeric:tabular-nums}

/* ── El mosaico ───────────────────────────────────────────────────────────
   Rejilla de 4 columnas; cada tile declara cuántas ocupa con `--ancho`.
   El tamaño del tile ES jerarquía: el más grande responde la pregunta
   principal de la pantalla. ─────────────────────────────────────────────── */
.tema-bento .tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:14px;margin-bottom:14px}
/* `anchoTotal` de `ui/Tile.jsx`: el tile ocupa la fila entera pase lo que pase
   con `--ancho`. ⚠️ Estaba SIN DEFINIR desde que existe el mosaico —la prop se
   usa en Administración, Informes y ahora Cartera, y no hacía nada—: con la
   rejilla de 4 columnas `ancho={4}` daba el mismo resultado por casualidad, y
   por eso nadie lo notó. Se encontró el 2026-09-01 abriendo Reportes de
   Cartera en un navegador de verdad, no leyendo el CSS. */
.tema-bento .tile.ancho-total{grid-column:1/-1}
.tema-bento .tile{grid-column:span var(--ancho,1);background:var(--panel);
  border:none;border-radius:var(--r-tile);padding:20px 22px;
  transition:transform .3s cubic-bezier(.34,1.4,.64,1), box-shadow .3s ease}
.tema-bento .tile:hover{transform:translateY(-4px);
  box-shadow:0 14px 30px rgba(23,26,33,.10)}
.tema-bento .tile-l{font-size:12px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--tenue)}
.tema-bento .tile-v{font-size:26px;font-weight:800;letter-spacing:-.02em;margin-top:4px;
  line-height:1.15}
.tema-bento .tile-sub{font-size:12.5px;color:var(--tenue);margin-top:2px}
.tema-bento .tile.grande .tile-v{font-size:38px}
/* Los cuatro tintes. El acento del tile se hereda al rótulo y al valor. */
/* ⚠️ EL RÓTULO NO VA EN EL COLOR DEL ACENTO, EL VALOR SÍ. Medido con la
   fórmula de WCAG el 2026-08-20: cada acento sobre su propio tinte da entre
   3,04:1 (menta) y 4,43:1 (cielo). Eso alcanza para el VALOR, que es de 26-38px
   y por lo tanto texto grande (umbral 3:1), pero NO para el rótulo, que es de
   12px y necesita 4,5:1. La primera versión de este bloque pintaba los dos con
   el acento, y los cuatro rótulos fallaban.
   El rótulo va en `--texto`: 14,8:1 a 15,6:1 sobre los cuatro tintes. Sigue
   leyéndose como rótulo por el tamaño, el peso y las mayúsculas, no por el
   color. */
.tema-bento .tile.lila{background:var(--t-lila)}
.tema-bento .tile.lila .tile-v{color:var(--a-lila)}
.tema-bento .tile.menta{background:var(--t-menta)}
.tema-bento .tile.menta .tile-v{color:var(--a-menta)}
.tema-bento .tile.durazno{background:var(--t-durazno)}
.tema-bento .tile.durazno .tile-v{color:var(--a-durazno)}
.tema-bento .tile.cielo{background:var(--t-cielo)}
.tema-bento .tile.cielo .tile-v{color:var(--a-cielo)}
.tema-bento .tile.lila .tile-l,.tema-bento .tile.menta .tile-l,
.tema-bento .tile.durazno .tile-l,.tema-bento .tile.cielo .tile-l{color:var(--texto)}
.tema-bento .tile.lila .tile-sub,.tema-bento .tile.menta .tile-sub,
.tema-bento .tile.durazno .tile-sub,.tema-bento .tile.cielo .tile-sub{color:var(--texto);opacity:.72}
/* Un tile que solo contiene otra cosa (una tabla, unos filtros) no lleva
   padding propio ni se levanta: no es un dato, es un contenedor. */
.tema-bento .tile.hueco{padding:16px 12px}
.tema-bento .tile.hueco:hover{transform:none;box-shadow:none}

/* ── La tabla, dentro de su tile, con scroll propio ───────────────────────
   Decisión del usuario: el mosaico completo entra en una pantalla y la tabla
   scrollea adentro. ⚠️ El costo aceptado son DOS scrolls anidados; para que
   no se pierda el encabezado, `thead` va `position:sticky`. Sin eso, el scroll
   interno deja al operador mirando columnas sin nombre. ──────────────────── */
.tema-bento .tabla-scroll{max-height:var(--alto-tabla,420px);overflow:auto}
.tema-bento .tabla-scroll thead th{position:sticky;top:0;z-index:2;
  background:var(--fondo)}
.tema-bento table td{border-top:none;border-bottom:1px solid var(--borde);
  padding:11px 14px}
.tema-bento table tbody tr:last-child td{border-bottom:none}
.tema-bento tbody tr{transition:background .2s ease}
.tema-bento tbody tr:hover{background:var(--fondo)}
.tema-bento tbody td:first-child{border-radius:12px 0 0 12px}
.tema-bento tbody td:last-child{border-radius:0 12px 12px 0}
.tema-bento th{border:none;letter-spacing:.05em}

/* ── Controles del tema ──────────────────────────────────────────────────── */
.tema-bento .btn{border-radius:var(--r-control);font-weight:600;
  transition:transform .2s cubic-bezier(.34,1.4,.64,1), background .2s ease}
.tema-bento .btn:hover{transform:translateY(-2px)}
.tema-bento .btn:active{transform:translateY(0)}
/* ⚠️ Este botón tenía `border-color:transparent` sobre `--panel`: BLANCO SOBRE
   BLANCO. Se veía como pastilla solo porque los primeros usos cayeron sobre el
   fondo gris de la página; el primero que cayó DENTRO de un tile («Crear
   borrador», Aforos, 2026-08-20) desapareció — quedó como texto suelto al lado
   del botón lila. Y el hover pintaba el texto con `--a-lila` sobre `--t-lila`:
   **4.39:1**, por debajo del 4.5:1 que pide texto de 14px. Las dos cosas
   pasaron porque nada medía; ahora las mide
   `test_el_boton_secundario_se_distingue_de_su_superficie`. */
.tema-bento .btn.ghost{background:var(--panel);border-color:var(--linea-control);
  color:var(--texto)}
.tema-bento .btn.ghost:hover{background:var(--t-lila);color:var(--texto);
  border-color:var(--linea-control)}
/* Tercera vez el mismo error: `background:var(--panel)` sin borde es blanco
   sobre blanco dentro de un tile. Le pasó a `.btn.ghost` (Aforos), a los
   `input` (Correos) y acá al botón neutro de la lista de Facturas. El tema
   asumía que todo control vive sobre el fondo gris de la página. */
.tema-bento .btn.gray{background:var(--panel);
  border:1px solid var(--linea-control);color:var(--texto)}
/* ⚠️ Estos controles tenían `border:none` con `background:var(--fondo)`, y
   `--fondo` **es el color de fondo de la página**. O sea: un input suelto sobre
   el fondo era invisible como control — se veía como texto flotando. Funcionaba
   de casualidad mientras todos los inputs vivían DENTRO de un tile blanco; el
   primero que quedó afuera (el calendario de la barra de filtros de Correos,
   2026-08-21) desapareció.

   Es exactamente el mismo error que tenía `.btn.ghost`, del otro lado: uno era
   blanco sobre blanco dentro del tile, este es gris sobre gris afuera. La causa
   común es la misma y vale escribirla: **el tema asumía que todo control vive
   sobre un tile.**

   El borde de `--linea-control` (3,37:1 sobre el fondo, 3,67:1 sobre el panel)
   arregla las dos cosas de una: se ve en cualquier superficie y recién ahora
   cumple el 3:1 que WCAG 1.4.11 pide para el límite de un control — la deuda
   que quedó anotada al migrar Aforos. */
.tema-bento input,.tema-bento select,.tema-bento textarea,
.tema-bento .fl-field input,.tema-bento .fl-field select{
  border:1px solid var(--linea-control);border-radius:var(--r-control);
  background:var(--fondo);height:38px}
.tema-bento .panel-cab input{background:var(--fondo)}
/* ⚠️ La regla de arriba le pone `height:38px`, `border-radius:14px` y
   `background:var(--fondo)` a TODO `input`. Sobre un checkbox eso da un
   rectángulo gris de 38px de alto con las esquinas redondeadas: se lee como una
   caja de texto vacía, no como algo que se marca. Correos (grupo 3, 2026-08-21)
   es la primera pantalla migrada con checkboxes, así que hasta ahora no había
   mordido — igual que el `select` dentro de un chip.

   Y acá el checkbox NATIVO se conserva, al revés que el `<select>`. La
   diferencia no es de criterio: al `<select>` lo dibuja el sistema operativo la
   LISTA DESPLEGABLE entera, y ningún CSS la alcanza. Un checkbox no tiene
   popup: se resuelve con `accent-color`, y el control del navegador ya trae
   teclado, foco y anuncio para lector de pantalla. Reescribirlo a mano sería
   perder todo eso sin ganar nada. */
/* Tinte de fila (lista de Facturas). Decisión del usuario el 2026-08-21 sobre
   tres opciones: fondo teñido suave, cielo = Exportación y lila = Nacional.

   ⚠️ **Reemplaza la franja de 5px** que tenían `.fila-nacional` /
   `.fila-exportacion` — la franja era la única excepción que quedaba en
   `FRANJAS_PERMITIDAS` del guardián de estilo, anotada como «decisión del
   usuario entre 3 opciones, resolver al migrar Logística». Resuelta.

   El tinte va en el `<td>` y no en el `<tr>`: con `border-collapse` el fondo del
   `tr` queda debajo del de la celda y el hover no lo tapa. */
.tema-bento tbody tr.cielo td{background:var(--t-cielo)}
.tema-bento tbody tr.cielo:hover td{background:#DBE8FD}
.tema-bento tbody tr.lila td{background:var(--t-lila)}
.tema-bento tbody tr.lila:hover td{background:#E4DCFD}
.tema-bento input[type=checkbox]{
  height:16px;width:16px;border:none;border-radius:0;background:none;
  accent-color:var(--vino);cursor:pointer;margin:0;flex-shrink:0}
.tema-bento input:focus,.tema-bento select:focus,.tema-bento textarea:focus{
  outline:2px solid var(--vino);outline-offset:0;box-shadow:none}
/* El panel deja de existir como caja con borde: acá todo es tile. */
.tema-bento .panel{border:none;border-radius:var(--r-tile);background:var(--panel)}
.tema-bento .panel-cab{border-bottom:1px solid var(--borde);padding:6px 12px 12px}
/* Un formulario DENTRO de un tile no puede usar la rejilla de 3 columnas del
   sistema (`.grid`): en un tile de media pantalla con dos campos, un tercio
   quedaba vacío y los dos campos angostos. Auto-fit con mínimo — dos campos
   llenan el tile de media, y en el de ancho completo siguen entrando tres. */
.tema-bento .tile .grid{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}
.tema-bento .panel-cab h3{font-size:15px;font-weight:700}
/* Avisos: sin borde, con el tinte que les corresponde. */
.tema-bento .aviso{border:none;border-radius:var(--r-control);background:var(--panel)}
.tema-bento .aviso.peligro{background:var(--t-durazno)}
.tema-bento .aviso.ok{background:var(--t-menta)}
.tema-bento .chip{border-radius:20px}
/* ⚠️ El select DENTRO de un chip vuelve a quedar desnudo. La regla de arriba
   (`.tema-bento input,select{height:38px;background:var(--fondo)}`) tiene la
   MISMA especificidad que `.chip select{all:unset}` y va después en el archivo,
   así que le ganaba: el chip de idioma se convertía en una caja gris de 38px
   dentro de una píldora de 20. Visto en pantalla el 2026-08-20. */
.tema-bento .chip select{all:unset;cursor:pointer;font-weight:700;
  font-family:inherit;font-size:12px;color:inherit;height:auto;background:transparent}
.tema-bento .kpi,.tema-bento .kpis-seg{border:none;border-radius:var(--r-tile)}

@media (prefers-reduced-motion: reduce){
  .tema-bento .tile,.tema-bento .btn,.tema-bento tbody tr{transition:none}
  .tema-bento .tile:hover,.tema-bento .btn:hover{transform:none}
}
@media (max-width: 900px){
  .tema-bento .tiles{grid-template-columns:repeat(2,minmax(0,1fr))}
  .tema-bento .tile{grid-column:span 1}
  .tema-bento .tile.ancho-total{grid-column:span 2}
}
@media (max-width: 560px){
  .tema-bento .tiles{grid-template-columns:1fr}
  .tema-bento .tile,.tema-bento .tile.ancho-total{grid-column:span 1}
}

/* ── Desplegable propio (.desp) ────────────────────────────────────────────
   Reemplaza al `<select>` nativo, cuya flecha y cuya lista las dibuja el
   sistema operativo y ningún CSS alcanza — al lado del resto de la interfaz se
   veía de otro programa (visto en pantalla el 2026-08-20).
   La lista SÍ lleva sombra: es un overlay que flota sobre el contenido, que es
   el caso que `DESIGN.md` permite. ────────────────────────────────────────── */
.desp{position:relative;display:inline-block}
/* ⚠️ El ancho que estas tres pantallas le daban a su `<select>` y que se
   perdió al cambiarlo por el desplegable propio (2026-09-03,
   `test_ninguna_regla_de_css_apunta_a_un_select_nativo`). **Solo el ancho**:
   el borde, el alto, el relleno y la tipografía ya los trae `.desp-btn`, y
   copiárselos también al contenedor pintaría un segundo borde alrededor. */
.filterbar .desp{min-width:150px}
.fl-field .desp{min-width:0}
.filtros-mes .desp{min-width:200px}

.desp-btn{display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;height:38px;padding:0 12px;background:var(--panel);
  border:1px solid var(--borde);border-radius:8px;font-family:inherit;font-size:13px;
  font-weight:500;color:var(--texto);cursor:pointer;text-align:left;
  transition:border-color .16s ease}
.desp-btn:hover{border-color:var(--vino)}
.desp-btn:focus-visible{outline:none;border-color:var(--vino);
  box-shadow:0 0 0 2.5px rgba(139,26,43,.1)}
.desp-vacio{color:var(--tenue)}
.desp-flecha{flex-shrink:0;color:var(--tenue);transition:transform .18s ease}
.desp-btn[aria-expanded="true"] .desp-flecha{transform:rotate(180deg)}
/* ⚠️ Igual que `.combo-lista`: la posición la calcula `ui/usePanelFlotante.js`
   y va en línea, porque la lista se dibuja en un portal. Acá, solo apariencia. */
.desp-lista{margin:0;padding:5px;list-style:none;overflow-y:auto;
  background:var(--panel);border:1px solid var(--borde);border-radius:10px;
  box-shadow:0 4px 16px rgba(0,0,0,.10)}
.desp-op{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:8px 10px;border-radius:7px;font-size:13px;color:var(--texto);cursor:pointer;
  line-height:1.35}
/* `.res` es la opción resaltada por TECLADO, y por eso se marca aparte del
   hover: quien navega con flechas tiene que ver dónde está sin mover el mouse. */
.desp-op.res{background:var(--vino-tinte);color:var(--vino)}
.desp-op.sel{font-weight:700}
@media (prefers-reduced-motion: reduce){
  .desp-flecha,.desp-btn{transition:none}
}

/* En el tema Bento el desplegable sigue al tema, como el resto de los controles. */
/* Mismo caso que los `input` y que `.btn.ghost`: `background:var(--fondo)` sin
   borde da 1,18:1 contra el tile blanco en el que vive — no se lee como un
   control. El `<button>` del desplegable no lo alcanzaba la regla de `input`
   porque no ES un input. `.chip .desp-btn` sí queda sin borde: ahí el contorno
   lo dibuja la pastilla del chip. */
.tema-bento .desp-btn{border:1px solid var(--linea-control);
  border-radius:var(--r-control);background:var(--fondo)}
.tema-bento .desp-btn:hover{background:#EAECF3}
.tema-bento .desp-btn:focus-visible{outline:2px solid var(--vino);outline-offset:0;
  box-shadow:none;background:var(--fondo)}
.tema-bento .desp-lista{border:none;border-radius:var(--r-control);
  box-shadow:0 10px 26px rgba(23,26,33,.14)}
.tema-bento .desp-op.res{background:var(--t-lila);color:var(--a-lila)}

/* El chip con desplegable adentro: el botón se desnuda y hereda el chip. */
.chip .desp-btn,.tema-bento .chip .desp-btn{height:auto;padding:0;border:none;
  background:transparent;font-size:12px;font-weight:700;color:inherit;gap:5px}
.chip .desp-btn:hover,.tema-bento .chip .desp-btn:hover{background:transparent}
.chip .desp-flecha{color:inherit;opacity:.65}
.chip .desp-lista{left:auto;right:0;min-width:150px}

/* ── Campos de fecha ──────────────────────────────────────────────────────
   El selector de fecha nativo SÍ se conserva: el calendario que abre el
   navegador es mejor que cualquier cosa que se escriba a mano acá, y ya conoce
   el formato local. Lo único que se puede estilizar es el ícono, así que se
   tiñe para que deje de ser el gris del sistema. ────────────────────────── */
input[type=date]::-webkit-calendar-picker-indicator{
  cursor:pointer;opacity:.55;transition:opacity .16s ease}
input[type=date]::-webkit-calendar-picker-indicator:hover{opacity:1}
.tema-bento input[type=date]{color:var(--texto)}


/* ══════════════════════════════════════════════════════════════════════════
   EL SIDEBAR ES BENTO EN LOS 11 MÓDULOS — global, fuera de `.tema-bento`
   ══════════════════════════════════════════════════════════════════════════
   Decisión del usuario del 2026-08-20: quiere que los 11 módulos queden
   exactamente iguales. El sidebar es el ÚNICO componente compartido por todos
   los módulos, y por eso el único que se puede unificar hoy sin dejar nada a
   medias: sus reglas usan solo tokens (`--vino`, `--vino-tinte`, `--borde`,
   `--tenue`), **cero color clavado a mano**.

   ⚠️ **Por qué el resto del programa NO se unifica hoy, aunque se haya pedido
   «todo igual»:** medido el 2026-08-20, las plantillas Jinja tienen **92
   colores hex escritos a mano en 17 archivos** (incluidos tres `#8B1A2B`
   directos). Repuntar los tokens globalmente dejaría cada uno de esos 10
   módulos **mitad lila y mitad vino** — peor que cualquiera de los dos
   extremos. La uniformidad se consigue MIGRANDO cada módulo, no con un CSS
   global. El código React, en cambio, tiene **cero** hex a mano: por eso un
   módulo migrado queda consistente por construcción.

   Efecto de este bloque: se va el parpadeo del sidebar al navegar. La
   navegación es idéntica desde hoy; el contenido difiere hasta que a cada
   módulo le toque su turno.
   ══════════════════════════════════════════════════════════════════════════ */
.sidebar{
  --vino:#6D4AFF; --vino-h:#5A3AE0; --vino-tinte:#EFEAFE;
  font-family:'Figtree','Segoe UI',system-ui,Arial,sans-serif;
}
.sidebar nav a,.sidebar nav .nav-accion,.side-user-name,.side-user-role,
.export span{font-family:inherit}

/* Encabezado de grupo dentro de una tabla (Documentos por mes; Compras y
   Nómina también agrupan). Va DENTRO de la misma tabla en vez de una tabla por
   grupo: con doce meses, doce tablas son doce encabezados de columna repetidos
   y doce scrolls. `scope="colgroup"` para que el lector de pantalla anuncie a
   qué grupo pertenece la fila. */
.fila-grupo th{background:var(--fondo);color:var(--texto);font-size:12.5px;
  font-weight:800;letter-spacing:0;text-transform:none;padding:9px 14px;
  text-align:left;position:static}
.fila-grupo-sub{color:var(--tenue);font-weight:500}
.tema-bento .fila-grupo th{background:var(--t-lila);color:var(--a-lila);border-radius:8px}

/* Chip seleccionable (`.chip-op`) — reemplaza a las pestañas `.doctab`. Un
   grupo donde una opción está activa. Mismo aspecto que el chip de filtro, así
   las pestañas de un módulo no se ven distintas de los filtros de otro. */
.chip-op{background:transparent;color:var(--tenue);border:1px solid var(--borde);
  cursor:pointer;padding:5px 12px;transition:border-color .16s ease, color .16s ease}
.chip-op:hover{border-color:var(--vino);color:var(--vino)}
.chip-op:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
.chip-op.activo{background:var(--vino-tinte);color:var(--vino);border-color:transparent}
.chip-conteo{background:rgba(0,0,0,.06);border-radius:20px;padding:0 6px;font-size:11px;
  font-weight:700;margin-left:2px}
.chip-op.activo .chip-conteo{background:rgba(255,255,255,.6)}
.tema-bento .chip-op{border:none;background:var(--panel)}
.tema-bento .chip-op:hover{background:var(--t-lila);color:var(--a-lila)}
.tema-bento .chip-op.activo{background:var(--t-lila);color:var(--a-lila)}

/* ── Tarjeta de pedido (Compras → `modules/compras/Lista.jsx`) ─────────────
   Sube acá desde el `<style>` de 60 líneas que tenía `compras/lista.html`. El
   guardián de estilo prohíbe esos bloques justamente para que no haya cinco
   variantes de la misma tarjeta repartidas por las plantillas.
   Un «pedido» agrupa las líneas que llegaron juntas (proveedor + fito o
   remisión); la tarjeta es esa unidad. ─────────────────────────────────── */
.pc{background:var(--panel);border:1px solid var(--borde);border-radius:10px;
  margin-bottom:14px;overflow:hidden;
  transition:transform .3s var(--ease-spring), border-color .2s ease, box-shadow .3s var(--ease-spring)}
.pc:hover{transform:translateY(-3px);border-color:var(--vino);box-shadow:0 8px 20px rgba(34,38,46,.10)}
.pc-hdr{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:14px 20px;border-bottom:1px solid var(--borde)}
.pc-hdr-l{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
.pc-prov{font-size:14px;font-weight:700;color:var(--texto);white-space:nowrap}
.pc-fecha{font-size:12px;color:var(--tenue);white-space:nowrap}
.pc-hdr-r{display:flex;align-items:center;gap:16px;flex-shrink:0}
.pc-stat{display:flex;flex-direction:column;align-items:flex-end}
.pc-stat-v{font-size:14px;font-weight:600;font-variant-numeric:tabular-nums;line-height:1.2}
.pc-stat-v.money{color:var(--vino)}
.pc-stat-l{font-size:10px;color:var(--tenue);text-transform:uppercase;letter-spacing:.06em}
.pc-pill{display:inline-flex;align-items:center;padding:2px 8px;border-radius:20px;
  font-size:11px;font-weight:600;white-space:nowrap}
.pc-pill.fito{background:#EAF3FE;color:var(--grupo-hydrangea)}
.pc-pill.rem{background:#F0F4F8;color:#596070}
.pc-tbl{width:100%;border-collapse:collapse;font-size:13px}
.pc-tbl thead th{font-size:10.5px;font-weight:700;color:var(--tenue);
  text-transform:uppercase;letter-spacing:.07em;padding:9px 16px;
  background:var(--fondo-alt,#F7F8FA);border-bottom:1px solid var(--borde);
  white-space:nowrap}
.pc-tbl tbody td{border-bottom:1px solid var(--borde)}
.pc-tbl tbody tr:last-child td{border-bottom:none}
.pc-tbl tbody tr:hover td{background:var(--fondo-alt,#F7F8FA)}
.pc-tbl tfoot td{padding:11px 14px;background:var(--fondo-alt,#F7F8FA);
  border-top:2px solid var(--borde)}
.td-var{font-weight:500}
.td-num{font-variant-numeric:tabular-nums}
.td-money{color:var(--vino);font-variant-numeric:tabular-nums;font-weight:600}
.tfoot-l{color:var(--tenue);font-size:11px;text-transform:uppercase;letter-spacing:.06em}
.empty-icon{font-size:36px;margin-bottom:10px;opacity:.5}
@media (prefers-reduced-motion: reduce){
  .pc{transition:none}
  .pc:hover{transform:none}
}

/* ── Formulario de pedido (Compras → `modules/compras/PedidoForm.jsx`) ─────
   Sube acá desde el `<style>` de 50 líneas que tenía `compras/pedido_form.html`.
   `.mdl-*` NO se repite: el modal de descarte usa el `ui/Modal.jsx` compartido,
   que ya trae esos estilos desde la migración de Facturas. ──────────────── */
.pf-card{background:var(--panel);border:1px solid var(--borde);border-radius:10px;overflow:hidden;
  transition:transform .3s var(--ease-spring), border-color .2s ease, box-shadow .3s var(--ease-spring)}
.pf-card:hover{transform:translateY(-3px);border-color:var(--vino);box-shadow:0 8px 20px rgba(34,38,46,.10)}
.pf-card-title{font-size:13px;font-weight:600;color:var(--tenue);text-transform:uppercase;
  letter-spacing:.07em;padding:14px 20px;border-bottom:1px solid var(--borde)}
.pf-card-title-fl{display:flex;align-items:center;justify-content:space-between}
.pf-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;padding:18px 20px}
@media(max-width:900px){.pf-grid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.pf-grid{grid-template-columns:1fr}}
.pf-table{width:100%;border-collapse:collapse;font-size:13px}
.pf-table thead th{font-size:11px;font-weight:700;color:var(--tenue);text-transform:uppercase;
  letter-spacing:.06em;padding:10px 12px;background:var(--fondo-alt,#F7F8FA);
  border-bottom:1px solid var(--borde);white-space:nowrap}
.pf-table tbody .pf-row td{padding:5px 6px;border-bottom:1px solid var(--borde)}
.pf-table tbody .pf-row:last-child td{border-bottom:none}
.pf-table tbody .pf-row:hover td{background:var(--fondo-alt,#F7F8FA)}
.pf-table tfoot .pf-tot td{padding:8px 12px;font-weight:700;background:var(--fondo-alt,#F7F8FA);
  border-top:2px solid var(--borde)}
.pf-hint{font-size:11px;color:var(--tenue);padding:8px 20px;border-top:1px solid var(--borde)}
/* Inputs dentro de la tabla: sin borde hasta que se los toca, para que la
   grilla se lea como una tabla y no como un muro de cajas. */
.ic{width:100%;padding:7px 9px;border:1px solid transparent;border-radius:8px;
  font-size:13px;font-family:inherit;background:transparent;box-sizing:border-box}
.ic:hover,.ic:focus{border-color:var(--borde);background:var(--panel);outline:none}
.ic:focus-visible{outline:2px solid var(--vino);outline-offset:2px}
.ic[readonly]{color:var(--tenue);cursor:not-allowed}
.ir{text-align:right}
.vc{text-align:right;font-variant-numeric:tabular-nums;color:var(--vino);
  font-weight:600;padding:0 12px;white-space:nowrap}
.bd{background:none;border:none;color:var(--tenue);cursor:pointer;font-size:13px;
  padding:4px 6px;border-radius:4px;line-height:1;transition:all .15s}
.bd:hover:not(:disabled){background:var(--t-peligro,var(--fondo));color:var(--peligro)}
.bd:disabled{opacity:.35;cursor:not-allowed}
@media (prefers-reduced-motion: reduce){
  .pf-card{transition:none}
  .pf-card:hover{transform:none}
}

/* ── Pagos y cuentas de cobro (Compras, grupo 3) ───────────────────────────
   Suben acá desde los `<style>` de `pagos.html` y `cuentas.html`. ─────── */
.sc{background:var(--panel);border:1px solid var(--borde);border-radius:10px;
  margin-bottom:10px;overflow:hidden}
.sc-hdr{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:14px 20px;flex-wrap:wrap}
.sc-hdr-l{display:flex;flex-direction:column;gap:2px}
.sc-prov{font-size:14px;font-weight:700;color:var(--texto)}
.sc-ncmp{font-size:11px;color:var(--tenue)}
.sc-stat{display:flex;flex-direction:column;align-items:flex-end}
.sc-lbl{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--tenue)}
.sc-val{font-size:16px;font-weight:700;font-variant-numeric:tabular-nums}
.sc-deuda{color:var(--vino)}
.cta-row{display:flex;align-items:center;gap:12px;padding:10px 20px;
  border-top:1px solid var(--borde);font-size:13px}
.cta-num{font-weight:700;width:110px}
.cta-fecha{color:var(--tenue);width:80px}
.cta-saldo{flex:1;text-align:right;font-weight:700}
.pago-form{background:var(--fondo);border-top:1px solid var(--borde);padding:14px 20px}
/* El equivalente en pesos: va en un recuadro punteado porque NO es un dato
   guardado, es lo que hay que transferir. Lo calcula el servidor. */
.pf-equiv{font-size:12.5px;color:var(--tenue);margin:10px 0;padding:8px 10px;
  border:1px dashed var(--borde);border-radius:8px}
/* Los dos campos de solo lectura del formulario de cuenta. */
.cc-ro{display:grid;grid-template-columns:1fr 1fr;gap:14px 20px;margin-bottom:16px}
@media(max-width:560px){.cc-ro{grid-template-columns:1fr}}
.ic-ro{background:var(--fondo);color:var(--tenue)}

/* ── Trazabilidad ICA (Compras, grupo 4) ─────────────────────────────────── */
.ica-alertas{margin-bottom:14px;padding:14px 18px}
.ica-alertas-tit{font-weight:600;margin-bottom:8px}
.ica-alertas-pie{margin-top:8px;font-size:12px;color:var(--tenue)}
.ica-filtros{display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin-bottom:14px}
/* ⚠️ El tinte de fila avisa que ESA flor viene de un predio con el registro ICA
   vencido o por vencer. Asignarla invalida la constancia, así que el aviso va
   en la fila y no en una nota al pie. */
.fila-vencido td{background:var(--t-peligro,rgba(220,38,38,.06))}
.fila-proximo td{background:var(--t-alerta,rgba(245,158,11,.08))}

/* ── Facturación Siigo (migración 2026-08-31) ──────────────────────────────
   El panel de proformas al lado del contenido. En el `app.js` viejo esto era
   el sidebar entero; al entrar Siigo al Shell del sistema —que usa el sidebar
   para los módulos— pasó a ser una columna propia (decisión del usuario).
   ⚠️ NO es navegación: es el área de trabajo. Se elige una proforma acá y su
   detalle aparece al lado. ──────────────────────────────────────────────── */
/* ⚠️ **Una columna por omisión, DOS solo cuando el panel está.** Desde que el
   panel de proformas no se dibuja con la selección vacía (2026-09-02), la
   regla de dos columnas fijas dejaba la primera —230 px— para el contenido, y
   la pantalla de Facturas entera salía comprimida en esa franja: KPIs
   apilados, tabla cortada, botones amontonados. Se vio en el navegador, no
   leyendo el CSS.
   `:has()` y no una clase puesta por React a propósito: el layout depende de si
   HAY panel, y eso ya lo dice el DOM — una clase sería un segundo lugar donde
   vive el mismo dato y podría quedar desincronizada. */
.sg-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:18px;align-items:start}
.sg-layout:has(> .sg-panel){grid-template-columns:230px minmax(0,1fr)}
@media(max-width:900px){.sg-layout,.sg-layout:has(> .sg-panel){grid-template-columns:1fr}}
.sg-vista{min-width:0}
.sg-panel{background:var(--panel);border:1px solid var(--borde);border-radius:12px;
  padding:14px;position:sticky;top:18px}
.sg-panel-tit{font-size:10px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--tenue);margin-bottom:10px}
.sg-panel-vacio{font-size:12px;color:var(--tenue);line-height:1.5}
.sg-panel-acts{display:flex;flex-direction:column;gap:6px;margin-top:12px;
  padding-top:12px;border-top:1px solid var(--borde)}
.sg-lista{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}
.sg-item{display:flex;align-items:flex-start;gap:8px;width:100%;padding:8px;
  border:none;background:none;border-radius:9px;cursor:pointer;text-align:left;
  font-family:inherit;transition:background .15s ease}
.sg-item:hover{background:var(--fondo)}
.sg-item-cuerpo{display:flex;flex-direction:column;gap:2px;min-width:0}
.sg-item-nombre{font-size:12.5px;font-weight:600;color:var(--texto);
  display:flex;align-items:center;gap:4px;flex-wrap:wrap}
.sg-item-meta{font-size:11px;color:var(--tenue);font-variant-numeric:tabular-nums}
/* El punto resume el estado de la proforma; lo decide el servidor. */
.pf-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;margin-top:4px;
  background:var(--tenue)}
.pf-dot.ok{background:var(--ok)}
.pf-dot.warn{background:var(--alerta)}
.pf-dot.err{background:var(--peligro)}
/* ⚠️ `.info` FALTABA, y por eso «no avisaba» que el borrador estaba creado:
   el servidor marca la proforma con `dot:"info"` en cuanto Siigo devuelve
   `draft_saved`, pero sin esta regla el punto quedaba del gris de «pendiente»
   y no había forma de distinguirlas. Lo reportó el usuario el 2026-09-02.
   `test_toda_clase_usada_existe_en_el_css` no lo vio: `pf-dot` se compone con
   un template string y el tono llega en una variable. */
.pf-dot.info{background:var(--vino)}

/* La moneda con la que la factura va a quedar en Siigo, bajo el total de la
   proforma. En `distinta` cuando NO coincide con la de la proforma —una
   proforma en dólares facturada como nacional queda en pesos—, que es
   justamente el caso en el que hay que mirar dos veces. */
.pv-emision{display:block;font-size:11px;font-weight:700;color:var(--tenue);
  letter-spacing:.02em;margin-top:2px;text-align:right}
.pv-emision.distinta{color:var(--alerta)}

/* Una proforma que YA está en Siigo (borrador guardado o factura emitida). Se
   tiñe la fila entera, no solo el punto: con seis facturas en la lista el
   punto de 8 px no alcanza para ver de un vistazo cuáles ya se subieron. */
.sg-item.hecho{background:var(--vino-tinte)}
.sg-item.hecho:hover{background:var(--vino-tinte)}
.sg-item.hecho .sg-item-nombre{color:var(--vino)}
.sg-item-estado{font-size:10.5px;font-weight:700;color:var(--vino);
  letter-spacing:.02em;white-space:nowrap}

/* Notas crédito y alias de clientes (Siigo, grupo 2). */
.nc-card{margin-bottom:10px}
.nc-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  margin-bottom:8px}
.sec-title{font-size:13px;font-weight:700;color:var(--tenue);text-transform:uppercase;
  letter-spacing:.07em;margin:20px 0 10px}
.cd-row{display:flex;align-items:center;gap:8px;padding:9px 10px;
  border:1px solid var(--borde);border-radius:10px;margin-bottom:6px;
  background:var(--panel)}
.cd-siigo{flex:1;min-width:0;font-size:13px;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cd-row .combo{flex:1;min-width:0}
@media(max-width:700px){.cd-row{flex-direction:column;align-items:stretch}}

/* Detalle de proforma (Siigo, grupo 3). */
.pv-chips{display:flex;gap:6px;flex-wrap:wrap;margin-top:4px}
.mchip{display:inline-flex;align-items:center;padding:2px 8px;border-radius:20px;
  background:var(--fondo);color:var(--tenue);font-size:11px;font-weight:600;
  white-space:nowrap}
.pv-total{font-size:22px;font-weight:800;font-variant-numeric:tabular-nums;
  color:var(--texto);line-height:1}
.pv-total .cur{font-size:12px;font-weight:700;color:var(--tenue);margin-right:5px}
/* La casilla de autorizar: es la que separa una factura revisada de una emitida
   por error, así que se ve como un control, no como una línea de texto. */
.auth-box{display:flex;align-items:center;gap:9px;padding:11px 13px;margin:12px 0;
  border:1px solid var(--borde);border-radius:10px;background:var(--fondo);
  font-size:13px;cursor:pointer}
.code{background:var(--fondo);border:1px solid var(--borde);border-radius:8px;
  padding:10px 12px;font-size:11.5px;overflow-x:auto;white-space:pre-wrap;
  word-break:break-all;margin:6px 0}
.campo-trm{margin-bottom:16px}
.campo-trm label{display:block;font-size:12px;font-weight:600;color:var(--tenue);
  margin-bottom:6px}
.inline{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:8px}

/* Buscadores remotos y segmentado de modo (Siigo, grupo 4). */
.sg-buscar{margin-top:8px}
.sg-buscar-lista{list-style:none;margin:8px 0 0;padding:0;max-height:280px;
  overflow-y:auto;border:1px solid var(--borde);border-radius:10px}
.sg-buscar-fila{display:flex;align-items:center;justify-content:space-between;
  gap:10px;padding:8px 10px;border-bottom:1px solid var(--borde)}
.sg-buscar-fila:last-child{border-bottom:none}
.sg-buscar-nombre{font-size:13px;font-weight:600}
.sg-buscar-vacio{font-size:12.5px;color:var(--tenue);padding:10px 2px}
.sg-corregir{padding:12px;border:1px solid var(--borde);border-radius:10px;
  background:var(--fondo);margin-top:8px}
/* El segmentado del modo de facturación. */
.seg{display:inline-flex;border:1px solid var(--borde);border-radius:9px;
  overflow:hidden}
.seg button{padding:7px 14px;border:none;background:var(--panel);cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:600;color:var(--tenue);
  border-right:1px solid var(--borde)}
.seg button:last-child{border-right:none}
.seg button:hover:not(:disabled){background:var(--fondo)}
.seg button.on{background:var(--vino);color:var(--panel);cursor:default}

/* Trabajos largos con progreso, y los paneles de tarea (Siigo, grupo 5). */
.sg-panel-tarea{padding:14px 16px;margin-bottom:14px}
.tl-barra{margin:10px 0}
/* Un trabajo de fondo que se cortó. El relleno se apaga y el mensaje pasa a
   ámbar: la barra tiene que verse DISTINTA de una que avanza, o el usuario
   sigue esperando frente a un progreso congelado (2026-09-02). */
.tl-barra.cortado .tl-msg{color:var(--alerta);font-weight:700}
.tl-barra.cortado .tl-lleno{background:var(--alerta);opacity:.45}
.tl-msg{font-size:13px;font-weight:600;color:var(--vino);margin-bottom:6px}
.tl-riel{height:6px;background:var(--borde);border-radius:3px;overflow:hidden}
.tl-lleno{height:100%;background:var(--vino);transition:width .3s ease}
/* El final de un trabajo largo, con su botón de descarga al lado.
   ⚠️ El botón se agregó el 2026-09-03: antes la descarga se disparaba en un
   único instante —cuando el sondeo veía terminar el trabajo— y si la pestaña
   no estaba abierta ahí, el archivo quedaba generado sin forma de bajarlo. */
.tl-fin{margin:10px 0;font-size:13px;color:var(--ok);font-weight:600;
  display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.consec-row{display:flex;gap:14px;padding:10px 0;border-bottom:1px solid var(--borde)}
.consec-row:last-of-type{border-bottom:none}
.consec-lbl{width:150px;flex-shrink:0;font-size:13px;font-weight:700}
.consec-body{flex:1;min-width:0;font-size:13px}
.consec-range{font-variant-numeric:tabular-nums;color:var(--tenue)}
.consec-nums{font-variant-numeric:tabular-nums}
@media(max-width:640px){.consec-row{flex-direction:column;gap:4px}
  .consec-lbl{width:auto}}

/* Bitácora de errores (Siigo, grupo 5). */
.err-card{margin-bottom:10px;padding:14px 16px}
.err-head{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:10px}
.err-title{font-size:13.5px;font-weight:700;flex:1;min-width:0}
.err-body{font-size:12.5px;color:var(--tenue);margin-top:8px}
.pf-chip{display:inline-block;padding:1px 7px;margin:0 3px 3px 0;border-radius:20px;
  background:var(--fondo);font-size:11px;font-variant-numeric:tabular-nums}

/* ══════════════════════════════════════════════════════════════════════════
   ⚠️ **CLASES RESCATADAS de plantillas Jinja borradas (2026-09-01).**

   Al migrar Compras y Siigo a React se borraron las plantillas que llevaban su
   CSS adentro, en un `<style>`. Las clases se siguieron usando desde el JSX,
   pero su CSS se fue con el archivo: **6 pantallas quedaron renderizando con
   estilos a medias o sin ninguno.** La peor fue la lista de cuentas de cobro,
   con 10 clases usadas y 0 definidas — el usuario lo reportó como «se ve super
   feo», y tenía razón: no era gusto, era que no había CSS.

   Lo cuida `test_toda_clase_usada_existe_en_el_css`, que compara los dos lados.
   ══════════════════════════════════════════════════════════════════════════ */

/* Detalle plegable. Lo usan Pagos, la bitácora de Siigo y el detalle de
   proforma. Venía del `styles.css` propio de Siigo. */
.collapse{border:1px solid var(--borde);border-radius:10px;margin-top:14px;
  overflow:hidden;background:var(--panel)}
.collapse > summary{list-style:none;cursor:pointer;padding:11px 15px;
  font-size:13px;font-weight:700;color:var(--texto);display:flex;
  align-items:center;gap:8px;user-select:none}
.collapse > summary::-webkit-details-marker{display:none}
.collapse > summary::before{content:"▸";color:var(--tenue);font-size:11px;
  transition:transform .3s var(--ease-spring)}
.collapse[open] > summary::before{transform:rotate(90deg)}
.collapse > summary:hover{background:var(--fondo)}
.collapse .cl-body{padding:4px 15px 15px;border-top:1px solid var(--borde)}

/* Un dato en negrita dentro de un bloque de texto (notas crédito de Siigo). */
.strong{font-weight:700;color:var(--texto)}

/* Campo de solo lectura: el dato que NO se edita porque ya salió impreso en el
   PDF que se le mandó al proveedor (formulario de cuenta de cobro). */
.field-ro{min-width:0}
.field-ro-label{font-size:11px;font-weight:600;color:var(--tenue);
  text-transform:uppercase;letter-spacing:.06em;margin-bottom:3px}
.field-ro-val{font-size:14px;font-weight:600;color:var(--texto)}

/* Campo dentro de un modal (el descarte del formulario de pedido). */
.mdl-input{width:100%;padding:6px 8px;border:1px solid var(--borde);
  border-radius:6px;font-family:inherit;font-size:13px;box-sizing:border-box}

/* La tabla de pagos dentro de la tarjeta de un proveedor, y el bloque derecho
   de su cabecera. */
.sc-tbl{width:100%;border-collapse:collapse;font-size:13px}
.sc-hdr-r{display:flex;align-items:center;gap:16px;flex-shrink:0}

/* ── Utilidades de celda ───────────────────────────────────────────────
   ⚠️ Van al FINAL del archivo a propósito. `.td-money` está definida DOS
   veces acá (una en la sección de tablas y otra dentro del bloque del
   tema bento, con `color:var(--vino)`), y entre dos reglas de la misma
   especificidad gana la última. Una utilidad que TIÑE una cifra tiene
   que venir después de las dos o no se ve — medido el 2026-09-01: el
   saldo por pagar salía lila, igual que el total. */
/* Utilidades de celda, compartidas por cualquier tabla del sistema.

   ⚠️ Nacieron el 2026-09-01 arreglando `/compras/cuentas`, que se dibujaba
   SIN CSS: sus 10 clases `.cc-*` vivían dentro de un `<style>` de
   `compras/cuentas.html` y se fueron con la plantilla al migrar a React.
   Están acá y son genéricas —no `.cc-algo`— justamente para que no vuelva a
   pasar: el CSS de una pantalla no debe vivir solo en esa pantalla.

   `.td-sub` es el renglón chico bajo el dato principal de una celda (la fecha
   de emisión bajo el número de cuenta). `.td-alerta` tiñe una cifra que pide
   acción —un saldo por pagar—; no es un error, por eso ámbar y no rojo. */
.td-sub{color:var(--tenue);font-size:11.5px;margin-top:1px;line-height:1.3}
.td-alerta{color:var(--alerta)}
/* Una cifra que ES una deuda: el saldo por cobrar de Cartera. Distinta de
   `.td-alerta` (ámbar, «revisar esto») a propósito — acá el rojo dice «esta
   plata no entró». Solo se pinta lo que de verdad se debe: un saldo en 0 o a
   favor va en `.td-money` normal, porque pintar todo de rojo es no pintar. */
.td-peligro{color:var(--peligro)}
/* Una fila que sigue siendo válida pero ya no pide nada (una cuenta pagada).
   Se apaga en vez de desaparecer: sigue siendo el respaldo de un pago. El
   hover la devuelve entera, porque se sigue pudiendo abrir su PDF. */
tbody tr.fila-apagada{opacity:.62}
tbody tr.fila-apagada:hover{opacity:1}
/* El ítem destructivo de un menú de 3 puntos. */
.dots-panel .item-menu.danger{color:var(--peligro)}
/* Un `Aviso` que enumera casos (los clientes con saldo a favor negativo, en
   Cartera). Va acá y no como clase propia: cualquier aviso que liste algo se
   ve igual, y una clase `.aviso-lista` sería un nombre para lo que el
   elemento ya dice. */
.aviso ul{margin:6px 0 0;padding-left:20px}
.aviso li + li{margin-top:2px}
.aviso a{color:inherit;font-weight:700}

/* ⚠️ Rescatada del `<style>` de `cartera/home.html` al migrar esa pantalla a
   React (2026-09-01), y **ya estaba rota antes de eso**: la usa también
   `nomina/organigrama.html` para avisar de un jefe inmediato en círculo, y esa
   página nunca cargó el `<style>` de Cartera — el aviso salía como texto
   plano, sin fondo ni color. El mismo accidente que dejó `/compras/cuentas`
   sin CSS ese mismo día, en otra pantalla y por el mismo motivo: CSS de una
   pantalla escrito dentro de esa pantalla.

   El nombre queda como estaba porque renombrarlo obliga a tocar Nómina, que
   sigue en Jinja. Cuando Nómina migre, esto se reemplaza por `ui/Aviso.jsx` y
   estas tres reglas se borran. */
.cartera-alerta{border-radius:10px;padding:12px 16px;font-size:13.5px;
  font-weight:600;margin-bottom:14px}
.cartera-alerta.danger{background:var(--t-durazno,#FCE9EC);color:var(--peligro)}
.cartera-alerta.warn{background:var(--t-ambar,#FFF4E5);color:var(--alerta)}


/* ══════════════════════════════════════════════════════════════════════════
   CARTERA — la pantalla del cliente (panel de cobro).

   ⚠️ Rescatado del `<style>` de `cartera/cliente.html` al migrar esa pantalla
   a React (2026-09-01). Son ~30 clases: si se hubieran ido con la plantilla,
   la pantalla que registra los pagos de los clientes habría quedado sin CSS,
   que es exactamente lo que le pasó a `/compras/cuentas` ese mismo día y
   estuvo doce días en producción sin que nada avisara.

   Se copian TAL CUAL, sin retocar nada: el layout de esta pantalla lo eligió
   el usuario entre dos opciones el 2026-08-12 y afinarlo «de paso» sería
   cambiarlo sin que nadie lo haya pedido.
   ══════════════════════════════════════════════════════════════════════════ */
.vista-btn.activo{background:var(--vino);color:#fff;border-color:var(--vino)}
.vistas{display:flex;gap:8px;flex-wrap:wrap;margin:18px 0 14px;
  border-bottom:1px solid var(--borde);padding-bottom:12px}
.filtros-mes{display:flex;gap:10px;align-items:center;margin-bottom:10px;flex-wrap:wrap}
.filtros-mes label{font-size:11px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--tenue)}
.filtros-mes select{font-family:inherit;font-size:13px;padding:5px 9px;min-width:200px}
.filtros-mes .filtro-conteo{font-size:12.5px;color:var(--tenue)}

/* ⚠️⚠️ **De `#id` a `.clase` el 2026-09-03, y no es cosmético: las 24 reglas
   de acá abajo estaban MUERTAS.** La pantalla se migró a React el 2026-09-01 y
   `<Tabla>` no pone `id` —solo `className`—, así que todo lo que colgaba de
   `#tabla-facturas` y `#tabla-historial` dejó de aplicar sin que nada avisara:
   las filas compactas que el usuario pidió el 2026-08-12 (de 6 facturas
   visibles a 14), los `nowrap` que impiden que «FV-3-3079» y «$ 1.027,65» se
   partan en dos renglones, el resaltado de la fila marcada, la opacidad de la
   otra moneda y el ocultar la columna N. Crédito fuera de la vista «Todas».

   Se descubrió arreglando el ancho del panel de cobro: al angostar la tabla,
   el texto empezó a partirse **porque el `nowrap` no existía**. Es el mismo
   accidente que el CSS de arriba dice que le pasó a `/compras/cuentas` y
   estuvo doce días en producción — y el mismo del `select` de `.ajuste-row`.
   `ver-todas` sí sobrevivió, porque va por `className`. */
/* La columna de N. Crédito solo existe en la vista «Todas»: en «Pendientes» se
   cobra, y un botón por fila competía con el badge de estado. */
.tabla-facturas:not(.ver-todas) .col-nc{display:none}

.cartera-banner{margin-top:14px;padding:14px 18px;border-radius:10px;
  display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.cartera-banner .ico{font-size:24px;line-height:1}
.cartera-banner .k{font-size:11px;text-transform:uppercase;letter-spacing:.04em;opacity:.85}
.cartera-banner .v{font-size:19px;font-weight:700}
.cartera-banner .nota{font-size:12.5px;margin-top:2px;opacity:.95}
.cartera-banner .cta{margin-left:auto;font-size:12px;opacity:.9}
.cartera-banner.favor{cursor:pointer;background:linear-gradient(135deg,var(--vino),#6e1421);color:#fff}
.cartera-banner.negativo{background:#FFF4E5;border:1px solid var(--alerta);color:var(--alerta)}

/* ⚠️ 430 px, no 330 (2026-09-03, elección del usuario entre tres maquetas).
   Con 330 el panel tenía 298 px útiles y una fila de ajuste necesita 397: la
   fila se salía, le comía el margen interno a TODO el panel y el `overflow`
   de abajo **cortaba el botón «×»** de quitar el ajuste. Y la categoría más
   larga del catálogo —«Comisión/valor de transferencia», 237 px— no entraba
   en el desplegable. La tabla de facturas cede 100 px: usaba 980 y no
   desbordaba, así que le sobraban. */
.cobro-grid{display:grid;grid-template-columns:minmax(0,1fr) 430px;gap:16px;align-items:start}
/* El corte sube de 1100 a 1250: con el panel en 430, a 1100 px la tabla se
   quedaba con 654 y ahí sí se apretaba. */
@media (max-width:1250px){.cobro-grid{grid-template-columns:minmax(0,1fr)}}

/* `.panel` de style.css es `overflow:hidden`, así que una tabla más ancha que el
   panel queda cortada SIN scroll: en un pago de 14 facturas se perdían 853 px
   —Monto, Método, Eliminar— sin forma de llegar a ellos. */
.tabla-scroll{overflow-x:auto;max-width:100%}

/* Filas compactas (pedido del usuario 2026-08-12): se veían solo 6 facturas sin
   scroll. La fila medía 82 px y el culpable NO era el padding sino el botón de
   N. Crédito: con el texto largo se partía en dos líneas y medía 59 px de alto
   él solo. Texto corto + `nowrap` + padding propio = 6 filas -> 14. */
.tabla-facturas thead th{padding:7px 10px}
.tabla-facturas tbody td{padding:5px 10px;font-size:13px}
/* Discreto por defecto y con forma de botón al apuntarlo: había uno con borde
   vino en CADA fila, compitiendo con el badge VENCIDA y ensuciando el escaneo de
   la lista. Sigue visible siempre (no solo al hover) porque si aparece recién al
   pasar el mouse, con teclado o en táctil no se descubre. */
.tabla-facturas .btn-nc{white-space:nowrap;padding:3px 9px;font-size:11.5px;
  background:transparent;border-color:transparent;color:var(--tenue);
  transition:color .12s,background .12s,border-color .12s}
.tabla-facturas tr:hover .btn-nc{color:var(--vino)}
.tabla-facturas .btn-nc:hover{background:var(--vino);border-color:var(--vino);color:#fff}
.tabla-facturas .btn-nc:focus-visible{border-color:var(--vino);color:var(--vino)}
.tabla-facturas .badge-status{padding:1px 7px;font-size:10px}
/* Vínculo entre una factura anulada y la que la reemplaza (2026-08-19). Va bajo
   el número, en gris y chico: es contexto, no el dato principal de la fila. */
.rel-anulada{display:block;font-family:var(--fuente);font-size:10.5px;
  color:var(--tenue);font-weight:400;margin-top:1px;letter-spacing:0}
.tabla-facturas .chk-factura{width:15px;height:15px}
.tabla-facturas .col-fecha{white-space:nowrap}
.tabla-facturas .sub-celda{display:inline}
.tabla-historial .col-fecha{white-space:nowrap}
.tabla-historial .col-facturas{max-width:340px}
.tabla-historial .mas-facturas{font-family:inherit;font-size:11px;font-weight:700;
  color:var(--vino);background:var(--vino-tinte);border:1px solid var(--vino);
  border-radius:20px;padding:1px 8px;margin-left:6px;cursor:pointer;white-space:nowrap}
.tabla-historial .mas-facturas:hover{background:var(--vino);color:#fff}
.tabla-facturas .mono,.tabla-historial .mono{font-family:ui-monospace,Consolas,monospace;
  font-weight:600;white-space:nowrap}
.tabla-facturas .num,.tabla-historial .num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.tabla-facturas .sub-celda,.tabla-historial .sub-celda{font-size:11px;color:var(--tenue);font-weight:400}
.tabla-facturas .vacio,.tabla-historial .vacio{color:var(--tenue)}
.tabla-facturas .chk-factura{width:16px;height:16px;margin:0;accent-color:var(--vino);cursor:pointer}
.tabla-facturas tr.fila-cobrable{cursor:pointer}
.tabla-facturas tr.marcada td{background:var(--vino-tinte)}
.tabla-facturas tr.otra-moneda{opacity:.4}
.text-ok{color:var(--ok)}
.text-peligro{color:var(--peligro)}

.cobro-panel{background:var(--panel);border:1px solid var(--vino);border-radius:10px;
  overflow:hidden;position:sticky;top:14px}
.cobro-panel .cab{background:var(--vino);color:#fff;padding:11px 15px;font-size:12px;
  font-weight:800;letter-spacing:.05em;text-transform:uppercase}
/* `min-width:0`: sin esto un hijo más ancho que la columna estira el grid
   entero y el padding del panel se pierde de ese lado. */
.cobro-panel .cuerpo{padding:15px;display:grid;gap:12px;min-width:0}
.cobro-panel .cuerpo>*{min-width:0}
.cobro-panel .campo label{display:block;font-size:11px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--tenue);margin-bottom:4px}
.cobro-panel .campo input,.cobro-panel .campo select,.cobro-panel .campo .desp{width:100%}
.cobro-panel .ayuda-campo{font-size:11.5px;color:var(--tenue);margin-top:4px}
.cobro-panel .grupo-efectivo{display:grid;gap:12px}
.cobro-panel .mas-campos summary{font-size:12px;font-weight:700;color:var(--tenue);
  cursor:pointer;padding:4px 0}
.cobro-panel .mas-campos[open]{display:grid;gap:12px}
/* ⚠️⚠️ **El `flex:1` apuntaba a un `<select>` que ya no existe.** Este bloque
   se copió tal cual del `<style>` de `cartera/cliente.html`, donde la
   categoría del ajuste era un `<select>` nativo. Al migrar la pantalla a React
   (2026-09-01) pasó a ser el desplegable propio del sistema —un `div.desp`—,
   así que la regla dejó de aplicarle a nada: el control se quedó con su ancho
   fijo, no se encogió más, y la fila desbordó el panel. Apunta al `.desp`, y
   el `min-width:0` es lo que le permite achicarse por debajo de su contenido
   (un ítem de flex no lo hace solo). */
.cobro-panel .ajuste-row{display:flex;gap:8px;align-items:center}
.cobro-panel .ajuste-row .desp{flex:1;min-width:0}
.cobro-panel .ajuste-row input{width:110px;flex:none}

.reparto{display:grid;gap:3px;font-size:12px;max-height:230px;overflow-y:auto}
.reparto .ln{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:baseline;
  padding:6px 9px;border-radius:6px;background:var(--fondo)}
.reparto .ln .f{font-family:ui-monospace,Consolas,monospace;font-weight:700;font-size:11.5px}
.reparto .ln .m{font-variant-numeric:tabular-nums;font-weight:700}
.reparto .ln .et{display:block;font-size:9.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;opacity:.85}
.reparto .ln.completa{background:#E8F4EC;color:var(--ok)}
.reparto .ln.parcial{background:#FFF4E5;color:var(--alerta)}
.cobro-tot{border-top:1px solid var(--borde);padding-top:10px;margin-top:10px;
  display:grid;gap:4px;font-size:12.5px}
.cobro-tot .r{display:flex;justify-content:space-between;gap:12px}
.cobro-tot .r .v{font-variant-numeric:tabular-nums;font-weight:700}
.cobro-vacio{color:var(--tenue);font-size:12.5px;text-align:center;padding:18px 8px}
.cobro-aviso{border-radius:7px;padding:9px 11px;font-size:12px;font-weight:650;margin-top:10px}
.cobro-aviso.ok{background:#E8F4EC;color:var(--ok)}
.cobro-aviso.av{background:#FFF4E5;color:var(--alerta)}
.cobro-aviso.mal{background:#FCE9EC;color:var(--peligro)}

.tabla-historial .expandir{padding:2px 7px;line-height:1.2}
.detalle-pago{background:var(--fondo);border:1px solid var(--borde);border-radius:8px;
  padding:12px 14px;margin:4px 0 10px}
.detalle-cab{font-size:10.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--tenue);margin-bottom:8px}
.detalle-tabla{width:100%;border-collapse:collapse;font-size:12.5px}
.detalle-tabla th{font-size:10px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--tenue);text-align:left;padding:5px 8px;border-bottom:1px solid var(--borde)}
.detalle-tabla td{padding:5px 8px;border-bottom:1px solid var(--borde)}
.detalle-tabla tr:last-child td{border-bottom:0}
.detalle-pie{display:flex;gap:16px;flex-wrap:wrap;margin-top:9px;padding-top:9px;
  border-top:1px dashed var(--borde);font-size:11.5px;color:var(--tenue)}
.detalle-totales{margin-top:10px;padding-top:10px;border-top:1px solid var(--borde);
  display:grid;gap:3px;max-width:340px;font-size:12.5px}
.detalle-totales .fila-tot{display:flex;justify-content:space-between;gap:14px}
.detalle-totales .fila-tot .v{font-variant-numeric:tabular-nums;font-weight:600}
.detalle-totales .fila-tot.costo{color:var(--alerta)}
.detalle-totales .fila-tot.total{margin-top:4px;padding-top:5px;
  border-top:1px solid var(--borde);font-weight:800}

.form-edicion{margin-top:12px;padding-top:12px;border-top:2px solid var(--vino)}
.form-edicion .edicion-facturas{display:grid;gap:2px;margin-bottom:10px;
  max-height:170px;overflow-y:auto;border:1px solid var(--borde);
  border-radius:7px;padding:5px;background:var(--panel)}
.form-edicion .edicion-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:10px;margin-bottom:10px}
.form-edicion .edicion-grid .campo.full{grid-column:1/-1}
.form-edicion .campo label{display:block;font-size:11px;font-weight:800;
  letter-spacing:.04em;text-transform:uppercase;color:var(--tenue);margin-bottom:4px}
.form-edicion .campo input,.form-edicion .campo select,.form-edicion .campo .desp{width:100%}
.form-edicion .edicion-costos{margin-bottom:10px;max-width:340px}
/* Mismo caso que `.cobro-panel .ajuste-row`: el `select` se fue con la
   migración a React y el `flex:1` quedó apuntando al vacío. */
.form-edicion .ajuste-row{display:flex;gap:8px;margin-bottom:5px;align-items:center}
.form-edicion .ajuste-row .desp{flex:1;min-width:0}
.form-edicion .ajuste-row input{width:110px;flex:none}
.form-edicion .edicion-acciones{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.form-edicion .edicion-nota{font-size:11.5px;color:var(--tenue)}
.form-edicion .edicion-aviso:not(:empty){margin-bottom:10px;padding:9px 11px;
  border-radius:7px;font-size:12px;font-weight:650;
  background:#FFF4E5;color:var(--alerta)}


/* ⚠️ Estas seis se usaban en `cartera/cliente.html` y **nunca tuvieron CSS**:
   `.ajustes-lista`, `.fila-chk`, `.fac`, `.meta`, `.mto` y `tr.fila-detalle`
   estaban escritas en el HTML sin una sola regla que las alcanzara. Lo
   encontró `test_toda_clase_usada_existe_en_el_css` al migrar la pantalla a
   React (2026-09-01); antes de ese guardián nada podía verlo. La lista de
   ajustes se apilaba sin separación y las tres columnas de cada fila de
   edición quedaban pegadas una a la otra.
   `.edicion-costos-tit` es nueva: reemplaza un `style=` de seis propiedades
   escrito dentro de la plantilla. */
.cobro-panel .ajustes-lista{display:flex;flex-direction:column;gap:8px}
.cobro-panel .ajustes-lista:empty{display:none}
.form-edicion .fila-chk{display:grid;grid-template-columns:auto 1fr auto auto;
  align-items:center;gap:8px;padding:5px 7px;border-radius:7px;font-size:12.5px}
.form-edicion .fila-chk:hover{background:var(--fondo)}
.form-edicion .fila-chk .fac{font-weight:700;font-variant-numeric:tabular-nums}
.form-edicion .fila-chk .meta{color:var(--tenue);font-size:11.5px}
.form-edicion .fila-chk .mto{font-variant-numeric:tabular-nums;
  color:var(--tenue);min-width:70px;text-align:right}
.edicion-costos-tit{font-size:11px;font-weight:800;letter-spacing:.04em;
  text-transform:uppercase;color:var(--tenue);margin-bottom:5px}
/* La fila que se despliega bajo un pago del historial. No lleva el hover de
   fila normal: es contenido, no una fila más que se pueda elegir. */
tr.fila-detalle > td{background:var(--fondo);padding:0 14px 14px}
tr.fila-detalle:hover > td{background:var(--fondo)}

/* ── Pantalla sin barra lateral (Despachos) ───────────────────────
   `body` cede 58 px al sidebar fijo; cuando el shell no lo dibuja, esos
   58 px quedarían como un margen izquierdo sin nada del otro lado.
   `:has()` lo resuelve sin tocar `react_base.html`, que es compartido por
   los módulos que SÍ llevan barra. (El mismo recurso que en `.sg-layout`.)

   ⚠️ El `max-width:1600px` de `.content` también se anula: la grilla de
   Despachos tiene 9 columnas y el ancho es justamente lo que se busca. */
body:has(.content.sin-barra){padding-left:0}
.content.sin-barra{max-width:none;padding:0}
/* ══════════════════════════════════════════════════════════════════════════
   Despachos — la planilla en vivo
   ══════════════════════════════════════════════════════════════════════════
   Movido desde el `<style>` de `despachos/templates/despachos.html` el
   2026-09-02, al migrar la pantalla a React. Es el mismo CSS, con tres
   cambios:

   - Se fue `body{display:block;padding-left:0}`: la cáscara React lo resuelve
     con `.content.sin-barra` (más arriba en este archivo), que además no pisa
     el layout de las demás pantallas.
   - Se fueron `.desp-menu*`: el desplegable de Etiquetas ahora es el
     componente `Menu` del sistema, el mismo que usan Compras y Cartera.
   - `font-family:'Manrope'` pasó a `inherit`, 8 veces. La pantalla vive dentro
     de `.tema-bento`, donde la tipografía es Figtree; dejar Manrope escrita a
     mano la habría hecho la única pantalla migrada con dos tipografías.

   ⚠️ **La pestaña activa cambia de vino a lila**, como en los otros 9 módulos
   migrados: `--vino` se redefine dentro de `.tema-bento`. No es una decisión
   nueva de esta pantalla, es la del tema.
   ══════════════════════════════════════════════════════════════════════════ */
.desp-topbar{display:flex;align-items:center;justify-content:space-between;gap:14px;
  background:#fff;border-bottom:1px solid var(--borde);padding:8px 24px;position:sticky;top:0;z-index:5}
.desp-topbar .back{display:flex;align-items:center;gap:7px;color:var(--tenue);text-decoration:none;
  font-size:13px;padding:6px 12px;border-radius:8px;border:1px solid var(--borde);transition:.12s;
  background:#fff;font-family:inherit;cursor:pointer}
.desp-topbar .back:hover{background:var(--fondo);color:var(--texto)}
.desp-estado{font-size:12px;color:var(--tenue)}
/* ⚠️⚠️ **El alto de la grilla se REPARTE, no se resta a mano.**
   Hasta el 2026-09-07 había TRES `calc(100vh - N)` escritos a mano sobre
   `.desp-grid` —140px pelado, 192px con la banda de la foto y 110px en pantalla
   completa—, o sea que cualquier cambio en lo que rodea la grilla (una fila más
   de pestañas, un botón más alto, la banda) la sacaba de la ventana y había que
   recalcular los tres. Ya pasó: el desborde de ~113px del 2026-08-19 lo destapó
   un cambio ajeno.
   Ahora `.desp-wrap` ocupa el alto de la ventana menos la barra superior, y de
   ahí para abajo cada nivel es `flex:1; min-height:0` hasta la grilla. La banda
   de la foto y las pestañas se descuentan **solas**, porque son hermanas de la
   grilla dentro del mismo flex.
   📌 Queda UN número, `--desp-barra`, y es el alto de la barra que está justo
   encima —lo único que separa al wrap de la ventana—. Medido en el navegador el
   2026-09-07: 55px en 1366, 1500 y 1920 de ancho. Lo cuida
   `scripts/verificar_despachos_pantalla.py` con umbral 0.
   ⚠️ `min-height:0` en cada nivel NO es decorativo: sin él un hijo flex se
   niega a encogerse por debajo de su contenido y la grilla vuelve a desbordar. */
:root{--desp-barra:55px}
.desp-wrap{width:100%;padding:10px 20px 16px;box-sizing:border-box;
  height:calc(100dvh - var(--desp-barra));display:flex;flex-direction:column}
.desp-tabla-area{display:flex;flex-direction:column;flex:1;min-height:0}
.desp-tabs{display:flex;align-items:center;gap:8px;flex-wrap:nowrap;overflow-x:auto;
  margin-bottom:8px;padding-bottom:2px}
.desp-tabs::-webkit-scrollbar{height:4px}
.desp-tab-btn,.desp-control{height:30px;box-sizing:border-box;padding:0 13px;
  border-radius:8px;border:1px solid var(--borde);background:#fff;font-weight:600;
  font-size:13px;cursor:pointer;color:var(--tenue);font-family:inherit;
  white-space:nowrap;flex:none;transition:.12s}
.desp-tab-btn.activo{background:var(--vino);color:#fff;border-color:var(--vino)}
.desp-control:hover{background:var(--fondo);color:var(--texto)}
.desp-separador{width:1px;height:20px;background:var(--borde);flex:none;margin:0 2px}
/* Punto en la pestaña de un día que ya terminó y no quedó registrado en
   `despachos_historial`. Va en la propia pestaña y no como control nuevo:
   esa barra ya lleva 9 controles y es un pendiente abierto del módulo. */
.desp-tab-btn .desp-punto{display:inline-block;width:6px;height:6px;border-radius:50%;
  background:var(--vino);margin-left:6px;vertical-align:middle}
.desp-tab-btn.activo .desp-punto{background:#fff}
/* Banda de estado de la foto del día. Bordes en vez de sombras y el vino
   como único acento, igual que el resto del sistema (DESIGN.md). */
.desp-foto{display:flex;align-items:center;gap:10px;margin-bottom:8px;padding:7px 12px;
  border:1px solid var(--borde);border-radius:8px;font-size:12.5px;color:var(--tenue)}
.desp-foto.falta{border-color:var(--vino);color:var(--vino);background:#fdf5f6}
.desp-foto form{margin:0 0 0 auto}
.desp-foto .desp-foto-btn{height:28px;padding:0 12px;border-radius:8px;cursor:pointer;
  border:1px solid var(--borde);background:#fff;color:var(--tenue);font-weight:600;
  font-size:12px;font-family:inherit;white-space:nowrap;transition:.12s}
.desp-foto .desp-foto-btn:hover{background:var(--fondo);color:var(--texto)}
.desp-foto.falta .desp-foto-btn{border-color:var(--vino);background:var(--vino);color:#fff}
.desp-panel{display:none}
.desp-panel.activo{display:flex;flex-direction:column;flex:1;min-height:0}
.desp-grid{flex:1;min-height:0;width:100%;margin-bottom:0;font-size:12px}
/* ⚠️ Acá había un segundo `calc(100vh - 192px)` para descontarle a la grilla
   los 52px de la banda de la foto. Se fue el 2026-09-07 con el reparto por
   flex: la banda es hermana de la grilla, así que su alto ya se descuenta solo
   —esté o no esté—. El comentario que estaba acá además contradecía su propio
   cierre: hablaba de un desborde «pendiente aparte» que se había cerrado el
   2026-08-19. */
.desp-grid .ag-header-cell-text{font-size:12px}
.celda-bloqueada{background-color:#ffe3b3 !important}
/* ⚠️ Acá había 4 reglas colgando de `.ag-theme-alpine` — el hover de fila y el
   aspecto de la fila fija del resumen— y se borraron el 2026-09-07 porque
   **ningún archivo pone esa clase**: el div lleva solo `.desp-grid`, y
   `grilla.js` no importa ningún CSS de AG Grid a propósito (lo explica ahí).
   Encima `.ag-floating-bottom` es el nombre viejo: en AG Grid 36 la fila fija
   es `.ag-grid-pinned-bottom-rows`. O sea que el aspecto del resumen sale del
   tema por defecto de AG Grid y estas reglas no pintaban nada. Medido el
   2026-09-06, borrado tras comprobarlo otra vez el 09-07. */
.finca-dot{display:inline-block;width:7px;height:7px;border-radius:50%;
  margin-right:6px;vertical-align:middle;flex:none}
.desp-buscador{height:30px;box-sizing:border-box;padding:0 12px;border:1px solid var(--borde);
  border-radius:8px;font-family:inherit;font-size:13px;min-width:180px;width:180px;
  color:var(--texto);flex:none}
/* El `:focus` propio que tenía se fue: `input:focus` (global) ya pone el
   mismo borde, y el guardián de estilo exige que haya UNO solo — dos
   selectores de foco son dos comportamientos que empiezan a divergir. */
.desp-filtro-fincas{display:flex;align-items:center;gap:12px;font-size:12.5px;
  color:var(--tenue);white-space:nowrap;flex:none}
.desp-filtro-fincas label{display:flex;align-items:center;gap:5px;cursor:pointer}
.desp-filtro-fincas input[type=checkbox]{cursor:pointer}
select.desp-control{width:120px;min-width:0;max-width:120px;font-weight:600;
  color:var(--tenue);text-overflow:ellipsis;overflow:hidden;white-space:nowrap}

/* Casilla de selección de fila: sin el espacio en blanco que dejaba el
   ancho por defecto de AG Grid alrededor del check. */
.ag-theme-alpine .ag-cell.ag-selection-checkbox-cell{justify-content:center;padding:0}

/* Editor de celda con buscador (reemplaza el <select> simple de AG Grid
   para los campos de catálogo: cliente/variedad/finca/proveedor). */
.buscador-editor{background:#fff;border:1px solid var(--borde);border-radius:8px;
  box-shadow:0 6px 20px rgba(0,0,0,.12);min-width:240px;max-width:360px;
  font-family:inherit;overflow:hidden}
.buscador-editor-input{width:100%;box-sizing:border-box;padding:9px 12px;border:none;
  border-bottom:1px solid var(--borde);font-family:inherit;font-size:13.5px;outline:none}
.buscador-editor-lista{max-height:220px;overflow-y:auto}
.buscador-editor-item{padding:8px 12px;font-size:13.5px;cursor:pointer;white-space:nowrap}
.buscador-editor-item.resaltado{background:var(--vino-tinte);color:var(--vino)}
.buscador-editor-vacio{padding:10px 12px;font-size:13px;color:var(--tenue)}

/* Presencia: iniciales de quienes están conectados ahora mismo. */
.desp-presencia{display:flex;align-items:center}
.desp-avatar{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;color:#fff;font-size:12px;font-weight:700;
  font-family:inherit;border:2px solid #fff;margin-left:-8px;
  box-shadow:0 0 0 1px rgba(0,0,0,.06)}
.desp-avatar:first-child{margin-left:0}
.desp-toast.mostrar{opacity:1;transform:translateY(0)}

/* Pantalla completa: solo el buscador + la grilla del día activo. */
/* Pantalla completa: el mismo reparto por flex, sin descontar la barra —que
   ahí no se ve—. Antes esto tenía el TERCER `calc(100vh - N)` a mano. */
.desp-tabla-area:fullscreen{background:#fff;padding:24px;box-sizing:border-box;
  height:100dvh}
.modal-facturas-overlay.mostrar{display:flex;animation:modalFondo .18s ease}
.modal-facturas-overlay.mostrar .modal-facturas{animation:modalPop .32s var(--ease-spring)}
@keyframes modalFondo{from{opacity:0}to{opacity:1}}
@keyframes modalPop{from{opacity:0;transform:translateY(10px) scale(.96)}
  to{opacity:1;transform:translateY(0) scale(1)}}
.modal-facturas{background:#fff;border-radius:16px;width:100%;max-width:420px;
  max-height:82vh;overflow:hidden;display:flex;flex-direction:column;
  box-shadow:0 24px 60px rgba(0,0,0,.28);font-family:inherit}
.modal-facturas-acciones{display:flex;align-items:center;gap:8px;margin-bottom:12px}
.modal-facturas-contador{margin-left:auto;font-size:12px;font-weight:700;
  color:var(--vino);background:var(--vino-tinte);padding:4px 10px;border-radius:20px;
  white-space:nowrap}
.modal-facturas-lista{display:flex;flex-direction:column;gap:4px;max-height:280px;
  overflow-y:auto}
.modal-facturas-lista label{display:flex;align-items:center;gap:10px;font-size:13.5px;
  padding:8px 10px;border-radius:10px;cursor:pointer;border:1px solid transparent;
  transition:.12s;color:var(--texto)}
.modal-facturas-lista label:hover{background:var(--fondo)}
.modal-facturas-lista label:has(input:checked){background:var(--vino-tinte);
  border-color:var(--vino)}
.modal-facturas-lista input[type=checkbox]{width:16px;height:16px;accent-color:var(--vino);
  cursor:pointer;flex:none}
.modal-facturas-avatar{display:flex;align-items:center;justify-content:center;
  width:26px;height:26px;border-radius:50%;background:var(--fondo);color:var(--tenue);
  font-size:11px;font-weight:800;flex:none;transition:.12s}
.modal-facturas-lista label:has(input:checked) .modal-facturas-avatar{
  background:var(--vino);color:#fff}
.modal-facturas-nombre{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.transporte-errores{margin:0 0 14px 18px;padding:0;font-size:13px;line-height:1.6}
/* Colores de los avatares de presencia (Despachos).
   Diez colores fuertes y bien separados entre sí: no son colores de marca ni
   dicen nada del negocio — su único trabajo es que dos personas conectadas a
   la vez no se confundan de un vistazo. Por eso NO salen de los tokens del
   tema (que son vino/lila y grises) y viven acá como una paleta aparte.
   ⚠️ El color de cada persona se elige con un hash de su nombre, así que le
   toca siempre el mismo. Cambiar el ORDEN de esta lista le cambia el color a
   todo el mundo. */
.desp-avatar.desp-c0{background:#e63946}
.desp-avatar.desp-c1{background:#f4a261}
.desp-avatar.desp-c2{background:#2a9d8f}
.desp-avatar.desp-c3{background:#457b9d}
.desp-avatar.desp-c4{background:#9b5de5}
.desp-avatar.desp-c5{background:#f15bb5}
.desp-avatar.desp-c6{background:#00b4d8}
.desp-avatar.desp-c7{background:#fb8500}
.desp-avatar.desp-c8{background:#588157}
.desp-avatar.desp-c9{background:#e76f51}

/* Nombre destacado dentro de una tabla (el enlace principal de la fila).
   Genérica a propósito: es lo que la lista de Empleados necesitaba, y las
   otras tablas del sistema tenían el mismo `font-weight:600` escrito a mano
   en un `style=` dentro de la plantilla. */
.td-fuerte{font-weight:600}

/* ── Nómina ───────────────────────────────────────────────────────────────
   Solo lo que la portada necesita y no existía. El resto de la pantalla usa
   las clases del sistema (`.panel`, `.kpi`, `.badge-status`, `.tabla-*`). */

/* El aviso de cumpleaños. Va arriba de todo porque es de las pocas cosas del
   sistema que piden hacer algo HOY.

   ⚠️ **La pantalla en Jinja lo marcaba con `border-left:4px`, y eso NO se
   copió**: `DESIGN.md` prohíbe las franjas de acento de más de 1 px, y el
   guardián `test_ninguna_franja_de_acento_de_mas_de_1px` lo cazó al moverlo
   (la plantilla lo tenía en un `<style>` propio, donde nunca lo vio nadie).
   Se resuelve como el proyecto ya resolvió el caso equivalente en Logística:
   **tinte de fondo suave**, con un color que ya está en la paleta. */
.nom-cumple{background:var(--t-durazno);border:1px solid transparent;
  margin-bottom:20px;padding:16px 20px;font-size:15px}
.nom-cumple div + div{margin-top:6px}
.nom-cumple-nombre{font-weight:700;color:var(--vino)}

/* Los KPI que además son enlaces a su lista ya filtrada. */
.nom-kpi-enlace{text-decoration:none}
.nom-kpi-alerta{color:var(--peligro)}

/* La pantalla vacía: solo se ve cuando no hay NINGÚN empleado cargado, o sea
   una vez en la vida del sistema. */
.nom-vacio{text-align:center;padding:36px}
.nom-vacio-titulo{font-size:15px;font-weight:600;margin-bottom:6px}
.nom-vacio-acciones{display:flex;gap:8px;justify-content:center;margin-top:16px}

/* Los filtros de las pantallas de novedades. La barra en Jinja era un `<form>`
   GET; en React los filtros viven en la URL y se aplican al cambiarlos, así
   que el `<form>` desapareció pero el aspecto es el mismo. */
.nom-filtros{margin-bottom:16px}
/* Los botones de aprobar/rechazar van juntos en la misma celda. */
.nom-acciones{display:flex;gap:6px}

/* ── Nómina · calendario, organigrama, catálogos e importación ────────────
   Movido desde los `<style>` de `calendario.html` y `organigrama.html` al
   migrarlas (2026-09-02). Mismo CSS, con un cambio: la franja de 3 px de la
   tarjeta del organigrama pasó a 1 px — `DESIGN.md` prohíbe los acentos más
   gruesos y el guardián de estilo lo caza (igual que pasó con el aviso de
   cumpleaños). */

/* El calendario del mes. */
table.cal{width:100%;border-collapse:collapse;table-layout:fixed}
table.cal th{font-size:11px;color:var(--tenue);text-transform:uppercase;
  padding:6px;text-align:left;font-weight:700}
td.cal-day{border:1px solid var(--borde);vertical-align:top;height:96px;
  padding:5px;border-radius:8px}
td.cal-empty{border:none}
td.cal-today{border:1.5px solid var(--vino);background:var(--vino-tinte,#F5E9EA)}
.cal-num{font-weight:700;font-size:13px;margin-bottom:3px}
.cal-evt{font-size:10.5px;line-height:1.25;margin-bottom:2px;padding:1px 5px;
  border-radius:5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Un color por tipo de evento: el calendario se lee de un vistazo, sin leyenda. */
.cal-cumple{background:#FFF4E5}
.cal-vacaciones{background:#E7F6EC}
.cal-incapacidad{background:#FCE9EC}
.cal-permiso{background:#EEF0F3}
.cal-vence{background:#FDF3D6}
.cal-evento{background:var(--vino-tinte,#F5E9EA);color:var(--vino);font-weight:600}
.nom-cal-panel{padding:12px}
.nom-cal-nav{display:flex;gap:8px;align-items:center}
.nom-cal-mes{min-width:150px;text-align:center;text-transform:capitalize}
.nom-cal-evento{margin-bottom:14px}
.nom-cal-form{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;
  margin-top:10px;padding:14px;border:1px solid var(--borde);border-radius:10px}
.nom-cal-ancho{flex:1;min-width:200px}

/* El organigrama: un árbol con sangría y una línea que marca la rama. */
.org-root,.org-root ul{list-style:none;margin:0;padding:0}
/* ⚠️ 1 px y no 2: `DESIGN.md` prohíbe las franjas más gruesas y el
   guardián lo caza. Es la línea que marca la rama del árbol, y a 1 px se
   lee igual. */
.org-root ul{margin-left:22px;padding-left:16px;border-left:1px solid var(--borde)}
.org-root li{margin:8px 0;position:relative}
.org-card{display:inline-block;text-decoration:none;border:1px solid var(--borde);
  border-left:1px solid var(--vino);border-radius:8px;padding:8px 14px;
  background:var(--panel);min-width:210px;transition:border-color .12s}
.org-card:hover{border-color:var(--vino)}
.org-nombre{font-weight:700;font-size:13.5px;color:var(--texto)}
.org-cargo{font-size:12px;color:var(--vino)}
.org-meta{font-size:11px;color:var(--tenue)}
/* Jefatura en círculo: ámbar, el mismo «mirá esto» del resto del sistema. El
   vino queda reservado al acento de marca. */
.org-card-ciclo{border-left-color:var(--alerta,#B8860B)}
.org-aviso{font-size:11px;color:var(--alerta,#B8860B);font-weight:600;margin-top:4px}
.nom-org-scroll{overflow-x:auto}

/* Catálogos: renombrar es un campo por fila, con su ✓ al lado. */
.nom-cat-rename{display:flex;gap:8px;align-items:center;margin:0}
.nom-cat-rename input{min-width:180px}
.nom-cat-nuevo{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;margin:0}

/* Importación. */
.nom-imp-titulo{margin-top:0}
.nom-imp-texto{margin-bottom:10px}
.nom-imp-archivo{max-width:420px}
.nom-imp-inicial{display:flex;gap:9px;align-items:flex-start;cursor:pointer;
  font-weight:400;margin-top:14px;max-width:640px}
.nom-imp-acts{margin-top:16px}
.nom-imp-confirmar{margin-top:16px}
.nom-imp-nota{margin-top:8px}

/* ── Nómina · perfil del empleado y su formulario ─────────────────────────
   Movido de `empleado_perfil.html` y `empleado_form.html` al migrarlas
   (2026-09-02), que eran las dos últimas plantillas del módulo. */
.nom-perfil-cabeza{display:flex;gap:16px;align-items:center}
.nom-perfil-foto{width:64px;height:64px;border-radius:50%;object-fit:cover;
  border:1px solid var(--borde);font-size:24px}
.nom-perfil-nombre{margin-bottom:2px}
.nom-perfil-estado{margin-left:8px}
.nom-perfil-acciones{margin-top:18px;display:flex;gap:10px;flex-wrap:wrap}

/* Un formulario que se abre con su botón. En Jinja era un `<details>`: evita
   que una pestaña arranque con nueve campos vacíos ocupando la pantalla. */
.nom-desplegar{margin:10px 0 14px}
.nom-desplegar-caja{margin-top:12px;padding:14px;border:1px solid var(--borde);
  border-radius:10px}
.nom-form-linea{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;margin:0}
.nom-form-ancho{flex:1;min-width:220px}
.nom-form-titulo{margin-top:0}
.nom-form-acts{margin-top:16px}
.nom-form-check{display:flex;gap:8px;align-items:center;cursor:pointer;
  font-weight:400}
/* Los certificados que genera el sistema, en una línea aparte del expediente. */
.nom-generables{display:flex;gap:8px;align-items:center;flex-wrap:wrap;
  margin:14px 0}

/* ⚠️ `.panel` NO tiene relleno, y es a propósito: `Tabla` lo usa así para que
   la tabla llegue al borde de la caja. Las pantallas que ponen texto suelto
   adentro —el perfil del empleado y su formulario— necesitan el suyo, o la
   primera línea queda pegada al borde superior y se ve cortada (medido en el
   navegador el 2026-09-02: el panel y su primer campo empezaban los dos en
   y=226). */
.nom-panel{padding:16px 18px}
.nom-panel > h3:first-child{margin-top:0}

/* ── Despachos · la suma rápida al arrastrar ──────────────────────────────
   Pedido del usuario (2026-09-03): arrastrar sobre celdas de números y ver la
   suma «en color llamativo», como en Excel. Va arriba, fija y a la vista: el
   sentido de la función es no tener que sacar la cuenta a mano, así que si
   hubiera que buscar el número no serviría de nada. */
/* ⚠️⚠️ **FLOTANTE, y no es una decisión estética.** La primera versión iba en
   el flujo normal, y al aparecer EMPUJABA la grilla hacia abajo: el puntero
   quedaba por encima de las filas y el arrastre se rompía a mitad de camino.
   Trazado en el navegador el 2026-09-03: la fila detectada iba 0 → 1 y después
   volvía a 0 y se quedaba ahí, con el mouse bajando. O sea que la barra que
   muestra la suma impedía hacer la suma.
   `position:fixed` la saca del flujo: aparece y desaparece sin mover un píxel
   de la tabla. */
/* ⚠️ **Abajo a la derecha, no arriba.** Se pidió «en la parte superior», y
   así se hizo primero — pero medido en el navegador tapaba el buscador y el
   botón de Transporte, que están justo ahí. Abajo a la derecha no se cruza con
   ningún control, es donde Excel muestra su suma, y queda igual de a la vista
   porque el fondo de color la separa de todo. */
.desp-suma{position:fixed;bottom:18px;right:24px;
  z-index:60;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding:8px 16px;border-radius:10px;
  background:var(--vino);color:#fff;box-shadow:0 6px 20px rgba(0,0,0,.18);
  /* No se puede seleccionar ni recibir el mouse: está encima de la pantalla
     mientras se arrastra, y no debe interceptar nada. */
  pointer-events:none;user-select:none}
.desp-suma-valor{font-size:19px;font-weight:800;font-variant-numeric:tabular-nums}
.desp-suma-etiqueta{font-size:13px;font-weight:600;opacity:.95}
.desp-suma-detalle{font-size:12px;opacity:.8;margin-left:auto}

/* Las celdas dentro del rango que se está sumando. El fondo es el tinte del
   acento —no el acento pleno— para que el número siga leyéndose. */
.celda-sumando{background:var(--vino-tinte,#EFEAFE) !important;
  box-shadow:inset 0 0 0 1px var(--vino)}


/* ── Ventana «Generar estado de cuenta» (Cartera, 2026-09-07) ──────────────
   Reemplaza a la pantalla del módulo `estados_cuenta`, eliminado ese día. Sin
   un solo color a mano: todo por tokens, que es lo que exige el guardián de
   estilo (`test_ningun_color_escrito_a_mano`). */
.ec-modal .field label{font-size:11px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--tenue)}
.ec-modal input[type=date]{font:inherit;padding:7px 9px;border:1px solid var(--borde);
  border-radius:8px;background:var(--panel);color:var(--texto)}
/* El total que dice qué va a decir el documento. Va destacado porque es el dato
   que evita mandarle al cliente un PDF sin haberlo mirado. */
.ec-cuenta{margin-top:16px;padding:12px 14px;border-radius:9px;
  background:var(--vino-tinte);display:flex;align-items:baseline;
  justify-content:space-between;gap:12px;flex-wrap:wrap}
.ec-total{font-weight:800;font-size:18px;color:var(--vino);
  font-variant-numeric:tabular-nums}
.ec-error{color:var(--peligro);font-weight:600;font-size:13px}


/* ── «Ver necesidad»: la necesidad de un día (Movimiento ICA) ─────────────── */
/* El modal se parte en dos: el calendario del mes a la izquierda y el
   resultado del día elegido a la derecha. Se apila en pantallas angostas. */
.nec-cuerpo{display:grid;grid-template-columns:250px 1fr;gap:18px;
  align-items:start}
.nec-cal{border-right:1px solid var(--borde);padding-right:16px}
.nec-res{min-width:0}
@media (max-width:760px){
  .nec-cuerpo{grid-template-columns:1fr}
  .nec-cal{border-right:0;border-bottom:1px solid var(--borde);
    padding-right:0;padding-bottom:14px}
}

.nec-cal-nav{display:flex;align-items:center;gap:6px;margin-bottom:10px}
.nec-cal-mes{flex:1;text-align:center;font-size:13.5px;text-transform:capitalize}
.nec-cal-dias,.nec-cal-grid{display:grid;
  grid-template-columns:repeat(7,minmax(0,1fr));gap:3px}
.nec-cal-dias span{text-align:center;font-size:10.5px;font-weight:700;
  color:var(--tenue)}
/* ⚠️ Altura fija, NO `aspect-ratio`: con `aspect-ratio` el ancho mínimo de la
   celda se deriva de la altura de la fila y la cuadrícula desborda su columna
   —se ven 3 de las 7 columnas—. Visto al maquetar esto el 2026-09-09. */
.nec-dia,.nec-dia-hueco{height:32px;min-width:0}
.nec-dia{position:relative;display:flex;align-items:center;justify-content:center;
  border:1px solid transparent;background:transparent;border-radius:9px;
  font:inherit;font-size:13px;font-weight:600;color:var(--texto);cursor:pointer;
  font-variant-numeric:tabular-nums;padding:0}
.nec-dia:hover:not(:disabled){background:var(--vino-tinte)}
.nec-dia:disabled{color:var(--borde);cursor:default}
.nec-dia-flojo{font-weight:400;color:var(--tenue)}
.nec-dia-hoy{border-color:var(--linea-control,var(--tenue))}
.nec-dia-elegido{background:var(--vino);color:#fff;font-weight:800}
.nec-dia-elegido.nec-dia-flojo{color:#fff}
.nec-dia-punto{display:inline-block;width:5px;height:5px;border-radius:50%;
  background:var(--vino)}
.nec-dia .nec-dia-punto{position:absolute;bottom:4px;left:50%;
  transform:translateX(-50%)}
.nec-dia-elegido .nec-dia-punto{background:#fff}
.nec-cal-pie{margin-top:12px;padding-top:10px;border-top:1px solid var(--borde);
  font-size:11.5px;color:var(--tenue);display:flex;align-items:center;gap:6px}

.nec-tit{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  margin-bottom:14px}
.nec-tit strong{font-size:15px}
.nec-tit span{font-size:12.5px;color:var(--tenue)}
.nec-grupos{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}
@media (max-width:560px){.nec-grupos{grid-template-columns:1fr}}
/* El fondo lo pone el JSX con el color del grupo, que manda la API: es código
   fijo de negocio y tiene una sola fuente de verdad (`informes.color_grupo`). */
.nec-grupo{border-radius:11px;padding:11px 12px;display:flex;
  flex-direction:column;gap:8px}
.nec-grupo-falta{font-size:23px;font-weight:800;line-height:1.05;
  font-variant-numeric:tabular-nums}
.nec-grupo-falta small{display:block;font-size:11px;font-weight:700;
  color:var(--tenue);margin-top:3px}
.nec-grupo-ok{font-size:15px;font-weight:800;color:var(--ok)}
.nec-grupo-vacio{font-size:13px;color:var(--tenue)}
.nec-grupo-detalle{display:flex;flex-direction:column;gap:2px;font-size:11.5px;
  color:var(--tenue);font-variant-numeric:tabular-nums}
.nec-grupo-detalle strong{color:var(--texto)}

.nec-subtit{margin:18px 0 8px;font-size:11px;font-weight:800;letter-spacing:.08em;
  text-transform:uppercase;color:var(--tenue)}
.nec-tabla{border:1px solid var(--borde);border-radius:11px;overflow:hidden}
.nec-fila-sin-finca td{color:var(--tenue)}
.nec-aviso{margin-top:12px;border-radius:10px;padding:10px 12px;font-size:12.5px;
  background:var(--t-durazno,var(--fondo));color:var(--texto)}
.nec-vacio{padding:38px 10px;text-align:center;color:var(--tenue);font-size:13.5px}
.nec-vacio strong{display:block;color:var(--texto);font-size:14.5px;
  margin-bottom:4px}


/* ── Perfil de cliente (Ajustes → Clientes) ──────────────────────────────── */
/* Dos columnas: la ficha del cliente siempre a la vista a la izquierda, y a la
   derecha lo que cambia (precios, actividad, facturas). Se apila en angosto. */
.perf-cuerpo{display:grid;grid-template-columns:290px 1fr;gap:20px;
  align-items:start}
@media (max-width:900px){.perf-cuerpo{grid-template-columns:1fr}}
.perf-col{display:flex;flex-direction:column;gap:18px;min-width:0}

.perf-ficha{background:var(--panel);border:1px solid var(--borde);
  border-radius:var(--r-tile,12px);padding:15px 16px}
.perf-ficha-cab{display:flex;align-items:center;gap:8px;font-size:11.5px;
  font-weight:700;color:var(--tenue);margin-bottom:12px}
.perf-ficha-cab span{flex:1}
.perf-grupo+.perf-grupo{margin-top:14px;padding-top:12px;
  border-top:1px solid var(--borde)}
.perf-grupo-nom{font-size:11px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;color:var(--vino);margin-bottom:8px}
.perf-campo+.perf-campo{margin-top:9px}
.perf-campo-r{font-size:10.5px;font-weight:700;letter-spacing:.03em;
  text-transform:uppercase;color:var(--tenue)}
.perf-campo-v{font-size:13.5px;font-weight:600;word-break:break-word}
.perf-campo-v.vacio{color:var(--tenue);font-weight:400;font-style:italic}

.perf-tiles{display:grid;grid-template-columns:repeat(5,1fr);gap:10px}
@media (max-width:1100px){.perf-tiles{grid-template-columns:repeat(3,1fr)}}
@media (max-width:640px){.perf-tiles{grid-template-columns:repeat(2,1fr)}}
.perf-tile{background:var(--panel);border:1px solid var(--borde);
  border-radius:var(--r-tile,12px);padding:11px 13px}
.perf-tile.alerta{background:var(--t-durazno,var(--fondo));border-color:transparent}
.perf-tile-r{font-size:11px;font-weight:700;color:var(--tenue)}
.perf-tile-v{font-size:19px;font-weight:800;letter-spacing:-.02em;margin-top:2px;
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.perf-tile.alerta .perf-tile-v{color:var(--alerta)}
.perf-tile-v.sin,.perf-tile-v.cargando{color:var(--tenue)}
.perf-tile-s{font-size:11px;color:var(--tenue);margin-top:1px}

/* La variedad, con su badge de grupo y el aviso de fuera de catálogo. */
.perf-var{display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap}
.perf-sinprecio{color:var(--tenue);font-style:italic}
/* Las variedades facturadas sin precio van en la misma tabla, resaltadas: son
   el trabajo pendiente sobre esta lista, no otra lista. */
.perf-fila-sin td{background:var(--t-durazno,var(--fondo))}

/* La fila de alta, pegada al pie de la tabla de precios. */
.perf-alta{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  margin-top:10px;padding:11px 13px;border:1px dashed var(--linea-control);
  border-radius:var(--r-tile,12px);background:var(--fondo)}
.perf-alta>*:first-child{flex:1;min-width:200px}
.perf-alta input[name="valor_tallo"]{width:110px}

.perf-barra-caja{display:inline-block;vertical-align:middle;width:100px;
  height:7px;border-radius:4px;background:var(--fondo);overflow:hidden}
.perf-barra{display:block;height:100%;border-radius:4px;background:var(--vino);
  min-width:3px}
