/* ══════════════════════════════════════════════════════════════════════════
   SISTEMA DE DISEÑO — tokens de @b2box/design-tokens
   ══════════════════════════════════════════════════════════════════════════

   Los valores de acá NO se eligieron para esta app: salen del design system de
   B2BOX (packages/design-tokens del monorepo), el mismo que usa el Storybook.
   Se copian en OKLCH tal como están allá y no se traducen a hex: si se
   convirtieran, la próxima vez que allá cambie un color nadie notaría que acá
   quedó el viejo.

   DOS COSAS QUE EL DESIGN SYSTEM DICE, Y QUE CONVIENE NO OLVIDAR:

   1. EL PRIMARIO NO ES LIMA. Textual: "Ink, not lime: the primary action is an
      ink pill, and lime is the brand accent reserved for the single main CTA
      per view." El lima es el acento de marca, no el color de todos los
      botones — pintar cada botón de lima es justo lo que el sistema evita.

   2. NO TRAE TEMA OSCURO, y explica por qué: un darkTheme va ahí sólo si la
      aplicación puede cambiar de tema. Esta puede. Los valores oscuros de más
      abajo NO vienen del design system: se derivan invirtiendo la misma rampa
      de neutros, que es lo más cerca que se puede estar sin inventar colores
      que allá no existen.
*/

:root {
  /* ── Marca (lima neón). brand[300] es el color de B2BOX. ──────────────── */
  --brand-50:oklch(0.992 0.023 117.6);
  --brand-100:oklch(0.981 0.055 119.6);
  --brand-200:oklch(0.957 0.141 120.2);
  --brand-300:oklch(0.925 0.228 125.3);
  --brand-400:oklch(0.813 0.199 125.4);
  --brand-500:oklch(0.7 0.17 125.4);
  --brand-600:oklch(0.588 0.142 125.5);
  --brand-700:oklch(0.475 0.113 125.6);
  --brand-800:oklch(0.362 0.084 125.6);
  --brand-900:oklch(0.287 0.062 127.3);
  --brand-950:oklch(0.222 0.047 127.2);

  /* ── Neutros: gris cálido; llevan el matiz de marca en muy poca saturación ── */
  --n-50:oklch(0.974 0.005 117.9);
  --n-100:oklch(0.946 0.01 119.6);
  --n-200:oklch(0.88 0.015 119.1);
  --n-300:oklch(0.764 0.018 123.2);
  --n-400:oklch(0.648 0.02 127.3);
  --n-500:oklch(0.573 0.021 127.4);
  --n-600:oklch(0.497 0.021 127.4);
  --n-700:oklch(0.42 0.017 128.9);
  --n-800:oklch(0.358 0.017 130.1);
  --n-900:oklch(0.297 0.017 131.2);
  --n-950:oklch(0.202 0.018 127.4);

  /* ── Semánticos ───────────────────────────────────────────────────────── */
  --verde:oklch(0.925 0.228 125.3);
  --verde-hover:oklch(0.957 0.141 120.2);
  --verde-activo:oklch(0.362 0.084 125.6);
  --warn:oklch(0.918 0.167 101.8);  --err:oklch(0.577 0.215 27.3);  --info:oklch(0.815 0.177 162.6);

  --bg-app:oklch(0.974 0.005 117.9);      --bg-panel:oklch(1 0 0);  --bg-elevado:oklch(0.974 0.005 117.9);
  --bd-sutil:oklch(0.946 0.01 119.6);     --bd-hover:oklch(0.88 0.015 119.1);
  --tx-1:oklch(0.202 0.018 127.4);     --tx-2:oklch(0.497 0.021 127.4);  --tx-3:oklch(0.648 0.02 127.3);
  --input-bg:oklch(1 0 0); --input-bd:oklch(0.88 0.015 119.1);

  --verde-texto:oklch(0.362 0.084 125.6);
  --ok-bg:oklch(0.981 0.055 119.6);       --ok-texto:oklch(0.362 0.084 125.6);
  --warn-bg:oklch(0.975 0.051 98.8);     --warn-texto:oklch(0.315 0.065 96.7);
  --err-bg:oklch(0.936 0.031 17.7);  --err-texto:oklch(0.396 0.133 25.7);
  --info-bg:oklch(0.967 0.046 172.6);        --info-texto:oklch(0.311 0.059 170.2);
  --cache-bg:oklch(0.946 0.01 119.6);    --cache-texto:oklch(0.297 0.017 131.2);
  --usuario-bg:oklch(0.967 0.046 172.6);     --usuario-texto:oklch(0.311 0.059 170.2);

  /* La ACCIÓN PRIMARIA es tinta, no lima (ver arriba). */
  --accion:oklch(0.202 0.018 127.4);  --accion-txt:oklch(0.974 0.005 117.9);  --foco:oklch(0.925 0.228 125.3);

  /* ── Forma y tipografía, del mismo paquete ────────────────────────────── */
  --r-chico:0.5rem; --r-grande:0.75rem; --r-pill:calc(infinity * 1px);
  /* Altura de los controles: botones, inputs y selects sobre el mismo ritmo. */
  --control-sm:2rem; --control-md:2.5rem; --control-lg:2.875rem;
  --sombra:none;
  --e1:4px; --e2:8px; --e3:12px; --e4:16px; --e5:24px; --e6:32px; --e7:48px;
  --t-mini:0.75rem; --t-chico:0.75rem; --t-base:0.875rem; --t-medio:1rem; --t-grande:1.25rem;
  /* Manrope e IBM Plex Mono son las del design system. Acá NO están los .woff2
     —esta app no carga fuentes de red— así que se nombran igual y se cae al
     stack del sistema: el día que se copien los archivos, entran solas. */
  --fuente:"Manrope Variable", "Manrope", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --mono:"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Alias de compatibilidad: los <style> de cada pantalla leen estos nombres. */
  --bd:var(--bd-sutil); --mut:var(--tx-2); --bg:var(--bg-app); --azul:var(--verde);
  --bd-2:var(--bd-hover); --borde:var(--bd-sutil);
  --error:var(--err-texto); --ok:var(--verde-texto);
  --bg-1:var(--bg-app); --bg-2:var(--bg-panel); --bg-3:var(--bg-elevado);
  --acento:var(--verde);
}

/* ── OSCURO. Derivado, no del design system (ver la nota de arriba): la misma
      rampa de neutros leída al revés. El lima se mantiene igual porque es la
      marca; lo que cambia es sobre qué se apoya. ─────────────────────────── */
:root[data-theme="dark"] {
  --bg-app:oklch(0.202 0.018 127.4);
  --bg-panel:oklch(0.297 0.017 131.2);
  --bg-elevado:oklch(0.358 0.017 130.1);
  --bd-sutil:oklch(0.358 0.017 130.1);
  --bd-hover:oklch(0.42 0.017 128.9);
  --tx-1:oklch(0.974 0.005 117.9);
  --tx-2:oklch(0.764 0.018 123.2);
  --tx-3:oklch(0.648 0.02 127.3);
  --input-bg:oklch(0.202 0.018 127.4);
  --input-bd:oklch(0.42 0.017 128.9);
  --verde-texto:oklch(0.925 0.228 125.3);
  --verde:oklch(0.925 0.228 125.3);
  --verde-hover:oklch(0.957 0.141 120.2);
  --verde-activo:oklch(0.813 0.199 125.4);
  --accion:oklch(0.974 0.005 117.9);
  --accion-txt:oklch(0.202 0.018 127.4);
  --ok-bg:color-mix(in oklch, oklch(0.925 0.228 125.3) 12%, transparent);
  --ok-texto:oklch(0.925 0.228 125.3);
  --warn-bg:color-mix(in oklch, oklch(0.918 0.167 101.8) 14%, transparent);
  --warn-texto:oklch(0.937 0.129 100.8);
  --err-bg:color-mix(in oklch, oklch(0.649 0.178 25.4) 16%, transparent);
  --err-texto:oklch(0.792 0.105 21.6);
  --info-bg:color-mix(in oklch, oklch(0.815 0.177 162.6) 16%, transparent);
  --info-texto:oklch(0.891 0.112 167.6);
  --cache-bg:oklch(0.358 0.017 130.1);
  --cache-texto:oklch(0.764 0.018 123.2);
  --usuario-bg:color-mix(in oklch, oklch(0.815 0.177 162.6) 14%, transparent);
  --usuario-texto:oklch(0.891 0.112 167.6);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg-app:oklch(0.202 0.018 127.4);
    --bg-panel:oklch(0.297 0.017 131.2);
    --bg-elevado:oklch(0.358 0.017 130.1);
    --bd-sutil:oklch(0.358 0.017 130.1);
    --bd-hover:oklch(0.42 0.017 128.9);
    --tx-1:oklch(0.974 0.005 117.9);
    --tx-2:oklch(0.764 0.018 123.2);
    --tx-3:oklch(0.648 0.02 127.3);
    --input-bg:oklch(0.202 0.018 127.4);
    --input-bd:oklch(0.42 0.017 128.9);
    --verde-texto:oklch(0.925 0.228 125.3);
    --verde:oklch(0.925 0.228 125.3);
    --verde-hover:oklch(0.957 0.141 120.2);
    --verde-activo:oklch(0.813 0.199 125.4);
    --accion:oklch(0.974 0.005 117.9);
    --accion-txt:oklch(0.202 0.018 127.4);
    --ok-bg:color-mix(in oklch, oklch(0.925 0.228 125.3) 12%, transparent);
    --ok-texto:oklch(0.925 0.228 125.3);
    --warn-bg:color-mix(in oklch, oklch(0.918 0.167 101.8) 14%, transparent);
    --warn-texto:oklch(0.937 0.129 100.8);
    --err-bg:color-mix(in oklch, oklch(0.649 0.178 25.4) 16%, transparent);
    --err-texto:oklch(0.792 0.105 21.6);
    --info-bg:color-mix(in oklch, oklch(0.815 0.177 162.6) 16%, transparent);
    --info-texto:oklch(0.891 0.112 167.6);
    --cache-bg:oklch(0.358 0.017 130.1);
    --cache-texto:oklch(0.764 0.018 123.2);
    --usuario-bg:color-mix(in oklch, oklch(0.815 0.177 162.6) 14%, transparent);
    --usuario-texto:oklch(0.891 0.112 167.6);
  }
}


* { box-sizing:border-box; }
body { font-family:var(--fuente); margin:0; background:var(--bg-app); color:var(--tx-1);
  font-size:var(--t-base); line-height:1.55; -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale; }
a { color:var(--info-texto); }

/* --- Header: barra fina y sobria, borde inferior. NO el bloque azul de antes.
       El verde solo puntua (el "logo" y el acento de la pestaña activa). --- */
/* ── Encabezado ─────────────────────────────────────────────────────────────
   Apilaba logo, título, una línea de descripción y once pestañas: cuatro cosas
   antes de llegar al trabajo. Ahora la marca y las pestañas comparten fila —
   sobra espacio a la derecha — y el conjunto queda fijo arriba, porque en la
   bandeja se scrollea mucho y perder la navegación obliga a volver al principio
   para cambiar de pantalla.

   El ancho acompaña al de `main`: sin eso, el título arranca pegado al borde y
   el contenido veinticuatro píxeles adentro, y esa desalineación se nota aunque
   nadie sepa decir por qué. */
header { position:sticky; top:0; z-index:20;
  background:var(--bg-panel); color:var(--tx-1);
  padding:var(--e3) var(--e5); border-bottom:1px solid var(--bd-sutil); }
header > * { max-width:1120px; margin-left:auto; margin-right:auto; }

/* DOS FILAS, NO UNA. Intentar meter la marca y once pestañas en la misma línea
   funciona hasta que no entran — y entonces la navegación se parte, las últimas
   dos pestañas caen sueltas debajo y el botón de tema queda flotando encima.
   Una fila para la identidad y otra para navegar es predecible con cualquier
   cantidad de pestañas y con cualquier ancho de pantalla. */
header .fila-1 { display:flex; align-items:center; justify-content:space-between;
  gap:var(--e4); max-width:1120px; margin:0 auto; }
header .fila-1 .der { display:flex; align-items:center; gap:var(--e3); }

/* La navegación en su propia línea, alineada con el contenido. Si no entra,
   scrollea en horizontal en vez de partirse: el orden de las pestañas es
   información (lo más usado primero) y partirlas lo destruye. */
.nav { display:flex; gap:var(--e5); align-items:center; margin:var(--e2) auto 0;
  max-width:1120px; flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden;
  scrollbar-width:none; }
.nav::-webkit-scrollbar { display:none; }
.nav a { white-space:nowrap; flex:0 0 auto; }
header h1 { margin:0 0 0 var(--e2); font-size:var(--t-base); font-weight:500;
  letter-spacing:0; color:var(--tx-2); }
/* El punto verde era la marca cuando no había logo. Con el logo al lado es una
   segunda marca para la misma cosa: solo queda si no hay imagen. */
header h1::before { content:none; }
header .marca:not(:has(.marca-logo)) h1::before { content:""; display:inline-block;
  width:8px; height:8px; border-radius:2px; background:var(--verde);
  margin-right:var(--e2); vertical-align:middle; }

main { max-width:1120px; margin:0 auto; padding:var(--e5) var(--e5) var(--e7); }
.panel { background:var(--bg-panel); border:1px solid var(--bd-sutil); border-radius:var(--r-grande);
  padding:var(--e5); margin-bottom:var(--e4); overflow:hidden; }
/* La variante de marca de card.tsx: borde lima y fondo lavado. Para el bloque
   que hay que mirar primero, no para todos. */
.panel.destacado { border-color:var(--verde); background:var(--brand-50); }
/* Un h2 arranca el panel: no necesita margen arriba, ya lo pone el padding. */
.panel > h2:first-child { margin-top:0; }
h2 { font-size:var(--t-medio); font-weight:600; letter-spacing:-.01em; margin:0 0 var(--e3); }
h3 { font-size:var(--t-base); font-weight:600; margin:var(--e4) 0 var(--e2); }
.grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--e3); }
label { display:block; font-size:var(--t-mini); font-weight:600; color:var(--tx-3);
  margin-bottom:var(--e1); text-transform:uppercase; letter-spacing:.05em; }
input,select,textarea { width:100%; padding:0 var(--e3); background:var(--input-bg); color:var(--tx-1);
  border:1px solid var(--input-bd); border-radius:var(--r-chico); font-size:var(--t-base); font-family:inherit;
  height:var(--control-md); transition:border-color .12s, box-shadow .12s; }
/* El textarea es el único que no tiene altura de control: crece con el texto. */
textarea { height:auto; padding:var(--e2) var(--e3); }
input:focus,select:focus,textarea:focus { outline:none; border-color:var(--foco); box-shadow:0 0 0 2px color-mix(in oklch, var(--foco) 45%, transparent); }
textarea { resize:vertical; min-height:62px; }
::placeholder { color:var(--tx-3); }
/* Boton primario: verde con TEXTO OSCURO (asi lo hace Supabase). Padding ajustado. */
/* ── BOTONES, con los patrones de @b2box/ui ─────────────────────────────────
   Copiados de button-variants.ts, no inventados: píldora completa, texto en
   negrita, y altura de control fija para que botones, inputs y selects queden
   alineados en la misma línea.

   EL DEFAULT ES TINTA, no lima. Lo dice el design system: el lima es el acento
   de marca, reservado al único CTA de cada vista. Con todos los botones en
   lima, el que importa deja de destacar. */
button { background:var(--accion); color:var(--accion-txt); border:1px solid transparent;
  border-radius:var(--r-pill); height:var(--control-md); padding:0 var(--e4);
  font-size:var(--t-base); font-weight:700; cursor:pointer; font-family:inherit;
  display:inline-flex; align-items:center; justify-content:center; gap:6px;
  white-space:nowrap; user-select:none; transition:all .15s ease; }
button:hover { opacity:.8; }
button:active { opacity:.7; }
button:disabled { opacity:.5; pointer-events:none; }

/* EL CTA DE LA VISTA. Único que SE LEVANTA al pasar el mouse — textual del
   design system: "it lifts on hover, nothing else does". Si se levantaran
   todos, el gesto dejaría de señalar cuál es el que importa. */
button.primario, button.cta { background:var(--verde); color:var(--brand-950); }
button.primario:hover, button.cta:hover { background:var(--verde-hover); opacity:1;
  transform:translateY(-2px); box-shadow:0 4px 12px color-mix(in oklch, var(--verde) 40%, transparent); }
button.primario:active, button.cta:active { transform:translateY(0); box-shadow:none; }

/* Secundario ("ghost"): sin fondo hasta que se lo toca. */
button.sec { background:transparent; color:var(--tx-2); border-color:transparent; font-weight:600; }
button.sec:hover { background:var(--bg-elevado); color:var(--tx-1); opacity:1; }

/* Contorno: en hover INVIERTE, como allá. */
button.outline { background:var(--bg-panel); color:var(--tx-1); border:2px solid var(--tx-1); }
button.outline:hover { background:var(--tx-1); color:var(--bg-panel); opacity:1; }

/* Destructivo: fondo lavado, no rojo pleno — un botón rojo entero grita más de
   lo que la acción suele merecer. */
button.danger { background:var(--err-bg); color:var(--err-texto); border-color:transparent; }
button.danger:hover { background:var(--err-bg); opacity:.75; }
button:disabled { opacity:.5; cursor:not-allowed; }
/* Foco visible en todo lo interactivo: el despachante navega con teclado. */
a:focus-visible, button:focus-visible, summary:focus-visible, [tabindex]:focus-visible { outline:2px solid var(--verde); outline-offset:2px; border-radius:var(--r-chico); }
#preview { max-width:100%; max-height:220px; border-radius:var(--r-chico); margin-top:12px; display:none; border:1px solid var(--bd-sutil); }

/* Galeria de fotos del producto. La primera se marca porque es la que encabeza
   la fila en el historial (es la miniatura que se guarda). */
.fotos { display:flex; flex-wrap:wrap; gap:8px; margin-top:12px; }
.fotos:empty { margin-top:0; }
.foto-item { position:relative; width:96px; height:96px; border-radius:var(--r-chico); overflow:hidden; border:1px solid var(--bd-sutil); }
.foto-item img { width:100%; height:100%; object-fit:cover; display:block; }
.foto-item .quitar { position:absolute; top:2px; right:2px; width:20px; height:20px; line-height:18px; padding:0;
  border-radius:var(--r-pill); border:none; background:rgba(0,0,0,.62); color:#fff; font-size:var(--t-base); cursor:pointer; }
.foto-item .quitar:hover { background:rgba(0,0,0,.85); }
.foto-item .orden { position:absolute; bottom:2px; left:2px; padding:0 5px; border-radius:var(--r-pill);
  background:rgba(0,0,0,.62); color:#fff; font-size:10px; letter-spacing:.02em; }

/* --- Separar productos: muchas fotos -> grupos por producto (ver app.js). ---
   Vive dentro del panel de fotos (centrado), asi que se vuelve a alinear a la
   izquierda: las cards son contenido, no un titular. */
#separar { margin-top:12px; text-align:left; }
.separar-aviso { border:1px solid var(--bd-sutil); background:var(--bg-elevado); border-radius:var(--r-grande); padding:14px; }
.separar-txt { font-size:var(--t-base); color:var(--tx-1); margin-bottom:10px; }
.separar-acciones { display:flex; gap:8px; flex-wrap:wrap; justify-content:center; }
.grupos-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(240px, 1fr)); gap:12px; margin:12px 0; }
.grupo-card { display:flex; flex-direction:column; gap:8px; padding:12px;
  border:1px solid var(--bd-sutil); border-radius:var(--r-grande); background:var(--bg-panel); }
.grupo-titulo { font-weight:600; font-size:var(--t-base); }
.grupo-desc { font-size:var(--t-chico); color:var(--tx-2); line-height:1.4; }
.grupo-minis { display:flex; flex-wrap:wrap; gap:6px; }
.grupo-minis img { width:72px; height:72px; object-fit:cover; border-radius:var(--r-chico); border:1px solid var(--bd-sutil); }
/* El boton abajo de todo, parejo entre cards de distinta altura. */
.grupo-card button { margin-top:auto; align-self:flex-start; }
/* Cards de sugerencias: la #1 (ganadora) destaca con borde verde y fondo apenas
   teñido; las #2/#3 quedan neutras y mas apagadas. */
.card { border:1px solid var(--bd-sutil); border-left:3px solid var(--bd-hover); border-radius:var(--r-chico); padding:16px; margin-bottom:12px; background:var(--bg-panel); }
.card.top { border-color:var(--verde); border-left:3px solid var(--verde); background:var(--brand-50); }
.codigo { font-family:var(--mono); font-size:var(--t-grande); font-weight:600; color:var(--tx-1); letter-spacing:.01em; }
.card.top .codigo { color:var(--verde-texto); }
.ruta { font-size:var(--t-chico); color:var(--tx-3); margin:8px 0; line-height:1.55; }
.chips { display:flex; gap:8px; flex-wrap:wrap; margin:8px 0; }
/* Chips/badges: fondo tenue del color semantico + texto del mismo tono, borde
   sutil, radio alto. Todos con el mismo tratamiento sobrio. */
.chip { background:var(--bg-elevado); color:var(--tx-2); border:1px solid var(--bd-sutil); border-radius:var(--r-pill); padding:3px 10px; font-size:var(--t-chico); font-weight:600; }
.chip.die { background:var(--info-bg); color:var(--info-texto); border-color:color-mix(in srgb, var(--info) 30%, transparent); }
.chip.conf { background:var(--ok-bg); color:var(--ok-texto); border-color:color-mix(in srgb, var(--verde) 32%, transparent); }
.chip.warn { background:var(--warn-bg); color:var(--warn-texto); border-color:color-mix(in srgb, var(--warn) 34%, transparent); }
.just { font-size:var(--t-base); line-height:1.55; margin-top:8px; color:var(--tx-2); }
.tributos { margin-top:12px; padding:10px 12px; background:var(--bg-elevado); border:1px solid var(--bd-sutil); border-radius:var(--r-chico); }
.tributos-tit { font-size:var(--t-mini); font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--tx-3); margin-bottom:8px; }
.tributos-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(96px, 1fr)); gap:6px; }
.trib { display:flex; flex-direction:column; gap:1px; padding:6px 8px; background:var(--bg-panel); border:1px solid var(--bd-sutil); border-radius:var(--r-chico); }
.trib-k { font-size:var(--t-mini); color:var(--tx-3); }
.trib-v { font-size:var(--t-base); font-weight:600; color:var(--tx-1); font-family:var(--mono); }
.trib.cero .trib-v { color:var(--tx-3); }
.trib.sd { border-style:dashed; }
.trib.sd .trib-v { color:var(--warn-texto); }
.tributos-nota { font-size:var(--t-mini); color:var(--tx-3); line-height:1.5; margin-top:8px; }
.interv-lista { margin:8px 0 0; padding-left:18px; font-size:var(--t-base); line-height:1.55; }
.interv-lista li { margin-bottom:4px; }
.interv-alcance { font-size:var(--t-mini); color:var(--tx-3); font-weight:600; }
.interv-norma { font-size:var(--t-mini); color:var(--tx-2); }
.verif-fecha { font-size:var(--t-mini); color:var(--tx-3); }
.verif-cab { display:flex; align-items:center; gap:8px; margin-bottom:4px; }
.verif-nota { font-size:var(--t-base); line-height:1.5; }
.verif-badge { font-size:var(--t-mini); font-weight:700; letter-spacing:.03em; padding:2px 8px; border-radius:var(--r-pill); border:1px solid transparent; }
.verif-badge.si { background:var(--err-bg); color:var(--err-texto); border-color:color-mix(in srgb, var(--err) 40%, transparent); }
.verif-badge.no { background:var(--ok-bg); color:var(--ok-texto); border-color:color-mix(in srgb, var(--verde) 40%, transparent); }
.verif-badge.warn { background:var(--warn-bg); color:var(--warn-texto); border-color:color-mix(in srgb, var(--warn) 44%, transparent); }
.alerta.verif.si { background:var(--err-bg); border-color:color-mix(in srgb, var(--err) 40%, transparent); border-left-color:var(--err); }
.alerta.verif.no { background:var(--ok-bg); border-color:color-mix(in srgb, var(--verde) 40%, transparent); border-left-color:var(--verde); }
.alerta.verif.warn { background:var(--warn-bg); border-left-color:var(--warn); }
.conv { margin-top:14px; padding:12px; background:var(--bg-elevado); border:1px solid var(--bd-sutil); border-radius:var(--r-chico); }
.conv-tit { font-size:var(--t-chico); font-weight:600; color:var(--tx-2); margin-bottom:8px; }
.conv-fila { display:flex; flex-wrap:wrap; gap:12px; align-items:center; }
.conv-fila label { font-size:var(--t-base); color:var(--tx-2); display:inline-flex; align-items:center; gap:6px; }
.conv-fila input { width:80px; }
.conv-fila input, .conv-fila select { padding:6px 8px; border:1px solid var(--input-bd); border-radius:var(--r-chico); background:var(--input-bg); color:var(--tx-1); font-size:var(--t-base); }
.conv-out { margin-top:10px; font-size:var(--t-base); color:var(--tx-1); }
button.mini.sugerida { outline:2px solid var(--verde); outline-offset:2px; }
.trib-col { font-size:var(--t-mini); line-height:1.5; color:var(--tx-2); }
.trib-col .trib-c b { color:var(--tx-1); font-weight:600; }
.marca { display:flex; align-items:center; gap:var(--e2); }
.marca h1 { margin:0; }
/* ── Marca: B2BOX PRO × Altitude 71 ─────────────────────────────────────────
   Dos logos de forma distinta —uno apaisado con texto, otro circular— así que
   NO comparten regla: el ancho lo manda la altura, y forzar los dos a la misma
   caja deformaba uno de los dos. */
/* LAS DOS MARCAS PESAN IGUAL: misma altura de letra. Los dos archivos están
   recortados al texto, así que igualar la altura iguala la tipografía — B2BOX
   sale más compacto (4.2:1) y ALTITUDE más largo (5.9:1), pero ninguno manda. */
.marca-logo { height:24px; width:auto; flex:0 0 auto; object-fit:contain; display:block; }
.marca-logo-alt { height:24px; border-radius:0; }

.marca-x { color:var(--tx-3); font-size:var(--t-medio); line-height:1;
  margin:0 var(--e1); font-weight:300; }

/* Instancias "solo B2BOX" (MARCA=b2box en el server): sin la × ni ALTITUDE, y
   sin las pestañas que esa instancia no tiene (gastos del consolidado y órdenes
   de B2BOX APP). La clase la pone auth-client.js/util.js según /api/config; el
   server además responde 404 en esos endpoints. El !important gana sobre los
   :root.rol-* que revelan las pestañas por rol. */
:root.marca-solo-b2box .marca-x,
:root.marca-solo-b2box .marca-logo-alt { display:none; }
:root.marca-solo-b2box .nav a#nav-gastos,
:root.marca-solo-b2box .nav a#nav-ordenes,
:root.marca-solo-b2box .nav a#nav-cotizacion { display:none !important; }

/* EN OSCURO el logo de B2BOX no se vería: es negro sobre header negro. Se
   INVIERTE, que lo deja blanco limpio — el logo es monocromo, así que no hay
   ningún color que la inversión pueda arruinar. (Con el logo anterior, que
   tenía el "PRO" en azul, esto no servía: el azul salía naranja. Por eso antes
   iba con un recuadro blanco atrás, que era un parche.) */
:root[data-theme="dark"] .marca-logo:not(.marca-logo-alt),
:root:not([data-theme="light"]) .marca-logo:not(.marca-logo-alt) { filter:invert(1); }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .marca-logo:not(.marca-logo-alt) { filter:none; }
}
/* El de Altitude es la inversión EXACTA del de B2BOX: el archivo es texto
   BLANCO (viene así), o sea nativo del tema oscuro. En claro se invierte a
   negro; en oscuro va tal cual. Si los dos usaran la misma regla, uno de los
   dos desaparecería siempre. */
.marca-logo-alt { filter:invert(1); }
:root[data-theme="dark"] .marca-logo-alt,
:root:not([data-theme="light"]) .marca-logo-alt { filter:none; box-shadow:none; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .marca-logo-alt { filter:invert(1); }
}
.marca-login { justify-content:center; margin-bottom:12px; }
.hist-prod { display:flex; align-items:flex-start; gap:10px; }
.hist-thumb { width:44px; height:44px; flex:0 0 44px; object-fit:cover; border-radius:var(--r-chico); border:1px solid var(--bd-sutil); background:var(--bg-elevado); }
.hist-thumb.vacio { display:inline-flex; align-items:center; justify-content:center; color:var(--tx-3); font-size:var(--t-base); }
.hist-prod-det { display:flex; align-items:flex-start; gap:16px; }
.hist-thumb-det { width:140px; height:140px; flex:0 0 140px; object-fit:cover; border-radius:var(--r-grande); border:1px solid var(--bd-sutil); background:var(--bg-elevado); }
@media (max-width:600px) { .hist-prod-det { flex-direction:column; } .hist-thumb-det { width:100%; height:auto; max-height:220px; } }
.alerta { background:var(--warn-bg); border:1px solid color-mix(in srgb, var(--warn) 40%, transparent); border-left:4px solid var(--warn); border-radius:var(--r-chico); padding:12px 14px; margin:12px 0; font-size:var(--t-base); line-height:1.5; color:var(--tx-1); }
.alerta b { color:var(--warn-texto); }
.error { background:var(--err-bg); border:1px solid color-mix(in srgb, var(--err) 40%, transparent); border-left:4px solid var(--err); color:var(--err-texto); border-radius:var(--r-chico); padding:12px 14px; font-size:var(--t-base); }
/* Banner de revision: tiene que ser IMPOSIBLE de pasar por alto. Es lo que
   separa un resultado usable de uno que hay que revisar a mano antes de
   declarar nada. Rojo tenue + borde fuerte + texto que grita, sin el bloque
   rojo saturado de antes. */
.revision { background:var(--err-bg); border:1px solid color-mix(in srgb, var(--err) 45%, transparent); border-left:4px solid var(--err); color:var(--tx-1); border-radius:var(--r-grande); padding:16px 18px; margin-bottom:16px; font-size:var(--t-base); line-height:1.55; }
.revision h3 { margin:0 0 8px; font-size:var(--t-medio); text-transform:uppercase; letter-spacing:.4px; color:var(--err-texto); }
.revision ul { margin:8px 0 0; padding-left:20px; }
/* Las hermanas especificas que el modelo no eligio: se listan DENTRO del aviso
   para poder juzgar la residual sin abrir nada. Monoespaciado el codigo, que es
   lo que se compara de un vistazo. */
.revision-alts { margin:6px 0 8px; padding-left:18px; font-size:var(--t-base); }
.revision-alts li { margin:2px 0; }
.revision-alts b { font-family:var(--mono); font-size:var(--t-chico); }
.revision li { margin-bottom:5px; }
.revision b { color:var(--err-texto); }
.chip.rev { background:var(--err-bg); color:var(--err-texto); border-color:color-mix(in srgb, var(--err) 34%, transparent); }
table { width:100%; border-collapse:collapse; font-size:var(--t-base); }
th,td { padding:var(--e2) var(--e3); text-align:right; color:var(--tx-1); }
th:first-child,td:first-child { text-align:left; padding-left:0; }
th:last-child,td:last-child { padding-right:0; }
/* Los números en columna solo se comparan si tienen todos el mismo ancho. */
td { font-variant-numeric:tabular-nums; }
/* Una línea por fila es ruido cuando hay veinte. Se marca la cabecera y listo. */
tbody tr + tr td { border-top:1px solid var(--bd-sutil); }
thead th { font-size:var(--t-mini); text-transform:uppercase; letter-spacing:.05em;
  color:var(--tx-3); font-weight:600; padding-bottom:var(--e2);
  border-bottom:1px solid var(--bd-sutil); }
tbody tr:hover td { background:var(--bg-elevado); }
tr.total td { font-weight:700; font-size:var(--t-medio); border-top:2px solid var(--tx-1); border-bottom:0; }
.nota { font-size:var(--t-mini); color:var(--tx-3); }
.hint { font-size:var(--t-chico); color:var(--tx-2); margin-top:6px; line-height:1.5; }
.pdf-error { color:var(--err-texto); font-weight:600; }
table.tecnicos td:nth-child(2) { text-align:left; }
/* --- Correccion --- */
.chip.cache { background:var(--cache-bg); color:var(--cache-texto); border-color:color-mix(in srgb, #8B5CF6 32%, transparent); }
.chip.ok { background:var(--verde); color:#1C1C1C; border-color:var(--verde); }
button.mini { height:var(--control-sm); padding:0 14px; font-size:var(--t-chico); font-weight:600; }
/* Secundario "ghost": transparente, borde sutil, texto secundario. */
button.sec { background:transparent; color:var(--tx-2); border:1px solid var(--bd-sutil); }
button.sec:hover { background:var(--bg-elevado); border-color:var(--bd-hover); color:var(--tx-1); }
.acciones { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin-top:10px; }
.fila-manual { display:flex; gap:8px; align-items:flex-end; flex-wrap:wrap; }
.fila-manual > div { flex:1; min-width:200px; }
.aviso-ok { background:var(--ok-bg); border:1px solid color-mix(in srgb, var(--verde) 38%, transparent); border-left:4px solid var(--verde); color:var(--ok-texto); border-radius:var(--r-chico); padding:12px 14px; font-size:var(--t-base); margin-top:12px; }
.tasa { font-weight:700; color:var(--tx-1); }
/* ── Barras de estado ───────────────────────────────────────────────────────
   Son dos: la fecha del arancel y la tasa de corrección. Ocupaban dos franjas
   grises de ancho completo, cada una con su borde, antes de llegar al trabajo —
   dos líneas de dato de contexto compitiendo con lo que se vino a hacer.

   Ahora van juntas, sin fondo, alineadas con el contenido y en gris terciario.
   Siguen ahí para quien las busque; dejan de ser lo segundo que se mira. */
.estado { font-size:var(--t-mini); color:var(--tx-3); padding:var(--e2) var(--e5) 0;
  max-width:1120px; margin:0 auto; background:none; border:none; letter-spacing:.01em; }
.estado + .estado { padding-top:var(--e1); }
.estado:last-of-type { padding-bottom:var(--e2); border-bottom:1px solid var(--bd-sutil);
  max-width:none; padding-left:calc(50vw - 560px); padding-right:calc(50vw - 560px); }
@media (max-width:1160px) {
  .estado:last-of-type { padding-left:var(--e5); padding-right:var(--e5); }
}
h2 { font-size:var(--t-base); margin:0 0 14px; color:var(--tx-1); font-weight:600; }
/* Spinner: usa currentColor, asi sirve igual dentro del boton primario (texto
   oscuro sobre verde) que dentro de un boton ghost. */
.spin { display:inline-block; width:13px; height:13px; border:2px solid color-mix(in srgb, currentColor 30%, transparent); border-top-color:currentColor; border-radius:50%; animation:g .7s linear infinite; vertical-align:-2px; margin-right:7px; }
@keyframes g { to { transform:rotate(360deg); } }

/* --- Modo rapido: la foto al centro es EL elemento de esta vista. Zona de drop
   clara, borde punteado sutil que se ilumina en verde al hover/focus. --- */
.panel.foto { text-align:center; border:1px dashed var(--bd-sutil); transition:border-color .15s; }
/* La explicación va alineada a la izquierda aunque el panel centre sus
   controles: cuatro renglones centrados obligan a buscar dónde arranca cada
   línea, y eso se lee más lento. */
.panel.foto .hint, .panel.foto p { text-align:left; max-width:62ch; margin-left:auto; margin-right:auto; }
.panel.foto:hover, .panel.foto:focus-within { border-color:var(--verde); }
.panel.foto input[type=file] { max-width:420px; margin:0 auto 4px; }
.panel.foto #btn { margin-top:16px; padding:12px 34px; font-size:var(--t-medio); }
.panel.foto label { text-align:left; }
.hint.centro { text-align:center; max-width:520px; margin-left:auto; margin-right:auto; }

/* --- Secciones plegables (datos opcionales / modo completo): se leen como
   "opcional, abri si querES", no como campos que faltan. Titulo tenue, se
   enciende al hover y una linea al abrir. --- */
details.opcional { background:var(--bg-panel); border:1px solid var(--bd-sutil); border-radius:var(--r-grande); margin-bottom:20px; box-shadow:var(--sombra); }
details.opcional > summary { cursor:pointer; padding:14px 20px; font-weight:600; font-size:var(--t-base); color:var(--tx-2); list-style:none; display:flex; align-items:center; }
details.opcional > summary:hover { color:var(--tx-1); }
details.opcional[open] > summary { color:var(--tx-1); border-bottom:1px solid var(--bd-sutil); }
details.opcional > summary::before { content:"\25B8"; display:inline-block; margin-right:10px; color:var(--tx-3); transition:transform .15s; }
details.opcional[open] > summary::before { transform:rotate(90deg); }
details.opcional > summary::-webkit-details-marker { display:none; }
details.opcional .cuerpo { padding:16px 20px 20px; }
#modo-completo > summary { color:var(--verde-texto); }

/* --- Links dev del nav (⚙ Prompts / 🔎 Inspector): paginas aparte, algo mas
       tenues que Clasificar/Historial. --- */
.nav a.nav-oculto { display:none; }

/* Zona de arrastrar-y-soltar CONTENIDA (una caja, no cubre la pantalla). */
.zona-drop { border:2px dashed var(--bd-2,var(--bd)); border-radius:var(--r-grande); padding:22px 20px;
  text-align:center; margin-bottom:18px; color:var(--tx-2); transition:border-color .12s, background .12s; }
.zona-drop.activo { border-color:#16a34a; background:rgba(22,163,74,.10); color:#16a34a; }
.zona-drop-txt { font-size:var(--t-base); line-height:1.6; }
.zona-drop-sub { font-size:var(--t-chico); color:var(--tx-3); }
/* Las de dev van mas calladas de COLOR, no de tamano: un cuerpo distinto en la
   misma fila es lo que hacia que la barra se viera despareja. */
.nav a.nav-dev { color:var(--tx-3); }
.nav a.nav-dev:hover { color:var(--tx-1); }

/* --- Pregunta dirigida: un paso, no un formulario (azul sobrio, info). --- */
.pregunta { background:var(--info-bg); border:1px solid color-mix(in srgb, var(--info) 30%, transparent); border-left:4px solid var(--info); border-radius:var(--r-grande); padding:18px 20px; margin-bottom:20px; }
.pregunta h3 { margin:0 0 6px; font-size:var(--t-medio); color:var(--info-texto); }
.pregunta .sub { font-size:var(--t-base); color:var(--tx-2); line-height:1.5; margin-bottom:14px; }
.pregunta .opciones { display:flex; gap:12px; flex-wrap:wrap; }
.pregunta .opciones button { min-width:150px; }
.pregunta .respondidas { font-size:var(--t-chico); color:var(--tx-2); margin-top:12px; }
.chip.usuario { background:var(--usuario-bg); color:var(--usuario-texto); border-color:color-mix(in srgb, var(--info) 30%, transparent); }

/* --- Navegacion entre vistas (pestañas sobrias, acento verde en la activa) --- */
.nav { display:flex; gap:var(--e5); align-items:baseline; margin-top:var(--e3); flex-wrap:wrap; }
.nav a { color:var(--tx-2); font-size:var(--t-base); text-decoration:none;
  border-bottom:2px solid transparent; padding-bottom:var(--e2); transition:color .12s; }
.nav a:hover { color:var(--tx-1); }
.nav a.activo { color:var(--tx-1); font-weight:600; border-bottom-color:var(--verde); }

/* Tabs con permiso: OCULTAS por defecto para que no parpadeen antes de saber el
   rol (si no, un despachante ve un instante las tabs de admin). Se revelan cuando
   /api/me confirma, con clases en <html>: rol-dev / rol-bandeja / rol-historial. */
.nav a.nav-dev, .nav a.nav-gated { display:none; }
:root.rol-dev .nav a.nav-dev { display:inline; }
/* Gastos la ven también los de la bandeja: el despachante carga y corrige las
   tarifas del consolidado, y no puede corregir lo que no ve. */
:root.rol-bandeja .nav a#nav-gastos { display:inline; }
/* Mismo criterio para lo que NO es un tab (el botón de orden de prueba): oculto
   de entrada, revelado recién cuando /api/me confirma el rol. */
.solo-dev { display:none; }
:root.rol-dev .solo-dev { display:inline-block; }
:root.rol-bandeja .nav a#nav-bandeja { display:inline; }
/* Órdenes de B2BOX APP: mismo permiso que la bandeja — es el mismo circuito,
   visto por envío en vez de por producto. Se revela POR ID (como las demás):
   una tab nueva que no se agregue acá queda oculta para todos, que es lo que
   pasó al agregar esta. */
:root.rol-bandeja .nav a#nav-ordenes { display:inline; }
:root.rol-historial .nav a#nav-historial { display:inline; }
/* Auditoría (control de cambios): admin, head_of_dev y dev — gate propio porque
   'dev' pelado no tiene rol-dev (esa clase es es_admin_o_head). */
:root.rol-auditoria .nav a#nav-auditoria { display:inline; }

/* Campanita: la 🔔 vive SIEMPRE pegada al tab Bandeja (afordancia), y se "prende"
   cuando hay pendientes sin ver; el badge rojo con el conteo aparece solo si >0.
   Se ve desde cualquier página; el poller vive en util.js. */
#nav-bandeja { position:relative; }
.nav-bell-legacy { margin-left:6px; line-height:1; opacity:.5;
  vertical-align:middle; transition:opacity .2s ease; }
.nav-bell.activa { opacity:1; }
.nav-badge {
  display:inline-flex; align-items:center; justify-content:center;
  min-width:16px; height:16px; padding:0 5px; margin-left:4px;
  font-size:var(--t-mini); font-weight:700; line-height:1; color:#fff;
  background:var(--err); border-radius:var(--r-pill); vertical-align:middle;
}
/* El atributo hidden pierde contra display:inline-flex: hay que forzarlo. */
.nav-badge[hidden] { display:none; }
.nav-badge.pulso { animation:campana-pulso .5s ease; }

/* Toast: aviso flotante que reemplaza al alert() nativo. Abajo a la derecha,
   entra deslizando, se va solo. */
.toast-cont { position:fixed; right:16px; bottom:16px; z-index:9999; display:flex; flex-direction:column; gap:8px; max-width:min(360px, calc(100vw - 32px)); }
.toast {
  background:var(--bg-panel, #1b1f24); color:var(--tx-1); border:1px solid var(--bd);
  border-left:4px solid var(--mut); border-radius:var(--r-chico, 8px);
  padding:11px 14px; font-size:var(--t-base); line-height:1.4; box-shadow:0 6px 24px rgba(0,0,0,.28);
  opacity:0; transform:translateY(8px); transition:opacity .2s ease, transform .2s ease;
}
.toast.visible { opacity:1; transform:translateY(0); }
.toast-error { border-left-color:var(--err); }
.toast-ok { border-left-color:var(--verde); }
.toast-info { border-left-color:var(--info); }

/* Panel "ya clasificaste algo parecido": reusa .panel/.card, con un acento verde
   sutil para que se lea como atajo (no como una alerta). */
.panel.similares { border-left:3px solid var(--verde); }
.card.similar { border-style:dashed; }
.similar-item { padding:8px 0; border-top:1px solid var(--bd-sutil); }
.similar-item:first-of-type { border-top:none; }
@keyframes campana-pulso {
  0% { transform:scale(1); }
  35% { transform:scale(1.45); }
  100% { transform:scale(1); }
}

/* --- Toggle de tema: boton-icono ghost, arriba a la derecha del header. --- */
.tema { position:static; flex:0 0 auto; width:34px; height:34px; padding:0; font-size:var(--t-medio); line-height:1; display:flex; align-items:center; justify-content:center; background:transparent; color:var(--tx-2); border:1px solid var(--bd-sutil); border-radius:var(--r-chico); }
.tema:hover { background:var(--bg-panel); border-color:var(--bd-hover); color:var(--tx-1); }

/* --- Responsive: nada de scroll horizontal en pantallas chicas. --- */
@media (max-width:600px) {
  main { padding:16px; }
  header { padding:12px 16px; }
  .estado { padding:var(--e1) var(--e4); }
  .tema { top:12px; right:12px; }
  .panel { padding:16px; }
  /* Nav: se envuelve en vez de desbordar, y el email/salir baja a su renglón. */
  .nav { flex-wrap:wrap; gap:12px 14px; row-gap:8px; }
  .nav .sesion { margin-left:0; width:100%; justify-content:flex-end; }
  /* Tablas anchas (historial, aranceles, lote): scroll horizontal propio. */
  .panel > table, table.hist, table.cot, table.an-tbl { display:block; overflow-x:auto; white-space:nowrap; }
  /* Separar productos: una card por renglon, que en 360px dos columnas no entran. */
  .grupos-grid { grid-template-columns:1fr; }
  .barra-conf { left:12px; right:12px; transform:none; }
}

/* Barra de sesion: email + salir, alineado a la derecha del nav. */
.nav .sesion { margin-left: auto; display: inline-flex; align-items: center; gap: 10px; }

/* ── Sesión (fila 1, a la derecha) ──────────────────────────────────────────
   El email y el botón se pisaban: el email se cortaba justo debajo del botón.
   Ahora el email se recorta con puntos suspensivos si no entra, en vez de
   meterse abajo de otra cosa. */
.fila-1 .sesion { display:inline-flex; align-items:center; gap:var(--e3); margin:0; min-width:0; }
.fila-1 .sesion .quien { color:var(--tx-3); font-size:var(--t-chico);
  max-width:22ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Salir no es la acción principal de ninguna pantalla: no puede ser el botón
   más llamativo que se ve al entrar. */
.fila-1 .sesion .salir, .sesion .salir {
  background:transparent; color:var(--tx-2); border:1px solid var(--bd-sutil);
  padding:var(--e1) var(--e3); font-size:var(--t-chico); font-weight:500; }
.fila-1 .sesion .salir:hover, .sesion .salir:hover {
  background:var(--bg-elevado); border-color:var(--bd-hover); color:var(--tx-1); }

/* El indicador de la campanita: un punto que se prende, no un emoji. */
.nav-bell { width:6px; height:6px; border-radius:var(--r-pill); background:var(--tx-3);
  display:inline-block; margin-left:var(--e2); vertical-align:middle; opacity:.45; }
.nav-bell.activa { background:var(--warn); opacity:1; }
.nav .sesion .quien { font-size:var(--t-chico); opacity: .8; }
.nav .sesion .salir { padding: 4px 12px; font-size:var(--t-chico); cursor: pointer; }
.nav { display: flex; align-items: center; gap: 16px; }

/* --- Tanda: clasificar varios grupos de una, con progreso --- */
/* La barra sola no alcanza: cada producto tarda decenas de segundos, asi que lo
   que informa es POR CUAL VA y los resultados que ya salieron. */
/* El `label` global es display:block + UPPERCASE y el `input` global es
   width:100%. Sobre un checkbox eso lo estira a todo el ancho y desarma la
   card, asi que las tres cosas se pisan aca a proposito. */
.grupo-chk { display:flex; align-items:center; gap:6px; font-size:var(--t-chico); opacity:.85;
  cursor:pointer; text-transform:none; letter-spacing:normal; font-weight:normal;
  color:var(--tx-2); margin:0; }
.grupo-chk input[type=checkbox] { width:auto; flex:0 0 auto; margin:0; cursor:pointer; }
.tanda-box { margin-top:14px; padding:12px; border:1px solid var(--borde); border-radius:var(--r-grande); }
.tanda-cab { font-size:.9rem; margin-bottom:8px; }
.tanda-barra { height:8px; border-radius:var(--r-chico); background:rgba(127,127,127,.25); overflow:hidden; }
.tanda-barra span { display:block; height:100%; background:var(--ok, #2ecc71); transition:width .3s ease; }
.tanda-lista { margin-top:12px; display:flex; flex-direction:column; gap:8px; }
.tanda-item { font-size:.88rem; padding:8px; border-radius:var(--r-chico); background:rgba(127,127,127,.08); }
.tanda-item.mal { background:rgba(220,80,80,.12); }
.tanda-err { color:var(--error, #d9534f); }
.tanda-desc { opacity:.75; margin-top:2px; }
.tanda-box button { margin-top:12px; }

@media (max-width:600px) {
  .tanda-box { padding:10px; }
  .separar-acciones { flex-direction:column; align-items:stretch; }
  .separar-acciones button { width:100%; }
}

/* --- Intervenciones: categoria visible y descartadas plegadas --- */
/* Una PROHIBICION se renderizaba igual que un requisito: el campo `categoria`
   existia en el dato y no se usaba nunca. */
.interv-cat { font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.04em;
  padding:1px 6px; border-radius:var(--r-grande); margin-right:6px; vertical-align:middle; }
.cat-proh { background:#7f1d1d; color:#fecaca; }
.cat-req  { background:#78350f; color:#fde68a; }
.cat-int  { background:#1e3a5f; color:#bfdbfe; }
.cat-lea  { background:#3f3f46; color:#e4e4e7; }
.interv-lista.apagada { opacity:.6; }
.interv-motivo { font-size:var(--t-chico); color:var(--tx-3); margin-top:2px; }
.interv-off { margin-top:10px; }
.interv-off summary { cursor:pointer; font-size:var(--t-chico); color:var(--tx-2); }

/* --- "Para importar necesitás": la lista con tildes ---
   Lo primero que el despachante busca, así que va destacado ARRIBA de la nota. Se
   usan los tokens del tema (no colores fijos): esta app arranca en CLARO y un
   #fecaca sobre blanco no se lee. */
.cert-req { margin:2px 0 10px; padding:10px 12px; border-radius:var(--r-grande);
  background:var(--warn-bg); border:1px solid var(--bd-sutil); }
.cert-req-tit { font-size:var(--t-mini); font-weight:700; text-transform:uppercase; letter-spacing:.04em;
  color:var(--tx-2); margin-bottom:6px; }
.cert-req ul { margin:0; padding:0; list-style:none; }
.cert-req li { margin:2px 0; font-size:var(--t-base); }
.cert-req li.proh > label > b { color:var(--err-texto); }
.cert-req-crudo { font-size:var(--t-mini); color:var(--tx-3); margin-top:1px; }
.cert-req.vacio { font-size:var(--t-base); color:var(--tx-2); background:var(--bg-elevado); }

/* Cada línea es un label entero: se tilda haciendo clic en cualquier parte, que
   en el celular es la diferencia entre usable y no usable. */
.cert-lista li > label { display:grid; grid-template-columns:auto 1fr; gap:0 8px;
  align-items:start; cursor:pointer; padding:5px 6px; border-radius:var(--r-chico);
  text-transform:none; letter-spacing:normal; font-weight:400; color:var(--tx-1);
  font-size:var(--t-base); margin:0; }
.cert-lista li > label:hover { background:var(--bg-elevado); }
.cert-lista li > label > *:not(.cert-check) { grid-column:2; }
.cert-check { width:16px; height:16px; margin:3px 0 0; padding:0; accent-color:var(--verde); cursor:pointer; }
.cert-lista.apagada { opacity:.65; }
.cert-vacio { font-size:var(--t-base); color:var(--tx-2); padding:4px 6px; }
.cert-sep { margin:10px 0 4px; font-size:var(--t-mini); text-transform:uppercase; letter-spacing:.04em;
  color:var(--tx-3); border-top:1px solid var(--bd-sutil); padding-top:8px; }
.cert-guardado { min-height:14px; margin-top:6px; font-size:var(--t-mini); color:var(--tx-3); }

/* Impuestos internos por producto en la cotización: el check va siempre, el % solo
   al tildarlo. Ley 24.674 alcanza a pocos rubros, así que un input más en cada
   fila sería ruido permanente para un caso raro. */
.p-ii { display:inline-flex; align-items:center; gap:3px; margin-left:8px; text-transform:none;
  letter-spacing:normal; font-weight:600; font-size:var(--t-mini); color:var(--tx-2); }
.p-ii input[type="checkbox"] { width:14px; height:14px; margin:0; padding:0; accent-color:var(--verde); cursor:pointer; }
.p-ii .ii-pct { width:56px; }
.ii-pct-sig { color:var(--tx-3); }

/* Desglose del gasto por tipo. Separa las corridas de EVALUACION del gasto real:
   una corrida cuesta varios dólares y, mezclada, hace que el total de producción
   deje de significar lo que dice. */
.ctx-desglose:empty { display:none; }
.ctx-desglose { margin:14px 0; padding:12px 14px; border:1px solid var(--bd-sutil);
  border-radius:var(--r-grande); background:var(--bg-panel); }
.ctx-tit { font-size:var(--t-mini); font-weight:700; text-transform:uppercase; letter-spacing:.04em;
  color:var(--tx-2); margin-bottom:8px; }
.ctx-item { display:flex; justify-content:space-between; gap:12px; padding:3px 0; font-size:var(--t-base); }
.ctx-item small { color:var(--tx-3); }
.ctx-item.ctx-eval { color:var(--tx-2); }
.ctx-nota { margin-top:8px; padding-top:8px; border-top:1px solid var(--bd-sutil);
  font-size:var(--t-chico); color:var(--tx-2); }

/* --- Órdenes de B2BOX APP: validar la operación entera ---
   La unidad acá es el ENVÍO, no el producto. El resumen va arriba y destacado
   porque es lo que decide si la operación conviene; los productos van abajo,
   editables de a uno. */
.ord-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(280px,1fr));
  gap:var(--e3); margin-top:var(--e3); }
/* .ord-card es un <button> con VARIAS líneas adentro, y el botón base del
   design system trae altura fija (2.5rem), contenido centrado y white-space
   nowrap — para botones de UNA línea. Sin resetear esas tres cosas, la tarjeta
   queda de 40px y su contenido desborda centrado por arriba y por abajo,
   pisando lo que tenga alrededor. */
.ord-card { display:flex; flex-direction:column; gap:6px; align-items:stretch;
  justify-content:flex-start; text-align:left; height:auto; white-space:normal;
  padding:14px; border:1px solid var(--bd-sutil); border-radius:var(--r-grande);
  background:var(--bg-panel); color:var(--tx-1); font:inherit; font-weight:400; cursor:pointer; }
/* CUIDADO: .ord-card es un <button>, así que hereda `background: var(--verde)`
   del botón primario. La regla de arriba lo pisa en reposo, pero al pasar el
   mouse `button:hover` volvía a pintarlo de verde entero y el texto quedaba
   ilegible — gris y naranja sobre verde. Todo botón que no parece un botón
   tiene que reafirmar su fondo en :hover y :active, no solo en reposo. */
.ord-card:hover, .ord-card:active, .ord-card:focus-visible {
  background:var(--bg-elevado); border-color:var(--bd-hover); color:var(--tx-1); }
.ord-card.ord-listo { opacity:.7; }
.ord-card-tit { font-weight:600; font-size:var(--t-base); }
/* Los montos NO se parten en dos renglones: "FOB US$" arriba y "17.000,00"
   abajo es un número que hay que reconstruir leyendo. Si no entran a lo ancho,
   la tarjeta crece; el número queda entero. */
.ord-card-meta, .ord-card-nums { display:flex; justify-content:space-between; gap:var(--e3);
  font-size:var(--t-chico); color:var(--tx-2); }
.ord-card-meta > span, .ord-card-nums > span { white-space:nowrap; }
.ord-card-nums > span { font-variant-numeric:tabular-nums; }
.ord-cert { color:var(--warn-texto); font-weight:600; }
.ord-estado { font-size:var(--t-mini); font-weight:700; text-transform:uppercase; letter-spacing:.04em; }
.ord-estado.ok { color:var(--verde-texto); }
.ord-estado.pend { color:var(--warn-texto); }

/* El resumen del envío: los números que se miran antes de aprobar nada. */
.ord-resumen { display:grid; grid-template-columns:repeat(auto-fit, minmax(130px,1fr)); gap:10px; margin:14px 0; }
.ord-kpi { padding:10px 12px; border:1px solid var(--bd-sutil); border-radius:var(--r-grande); background:var(--bg-elevado); }
.ord-kpi span { display:block; font-size:var(--t-mini); text-transform:uppercase; letter-spacing:.04em; color:var(--tx-3); }
.ord-kpi b { font-size:var(--t-grande); }
.ord-kpi.destacado { background:var(--warn-bg); }
.ord-kpi.alerta { background:var(--err-bg); }
.ord-kpi.alerta b { color:var(--err-texto); }
.ord-certs { padding:10px 12px; border-radius:var(--r-chico); background:var(--warn-bg); font-size:var(--t-base); }

.ord-prod.aprobado { opacity:.72; }
.ord-prod-cab { display:flex; justify-content:space-between; align-items:flex-start; gap:12px; }
.ord-ok { color:var(--verde-texto); font-weight:600; font-size:var(--t-base); white-space:nowrap; }
.ord-alertas { display:flex; flex-wrap:wrap; gap:6px; margin:10px 0; }
.ord-alerta { font-size:var(--t-mini); font-weight:700; padding:2px 8px; border-radius:var(--r-grande); cursor:help; }
.ord-alerta.al-grave { background:var(--err-bg); color:var(--err-texto); }
.ord-alerta.al-media { background:var(--warn-bg); color:var(--warn-texto); }
.ord-req { margin:10px 0; }
.ord-req-tit { font-size:var(--t-mini); font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--tx-2); }
.ord-req ul { margin:4px 0 0; padding-left:18px; font-size:var(--t-base); }
.ord-editar { display:flex; gap:12px; flex-wrap:wrap; margin:12px 0; }
.ord-editar label { flex:1 1 200px; }
.ord-ar-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(110px,1fr)); gap:8px; margin-top:6px; }
.ord-ar-grid label { font-size:var(--t-mini); }

@media (max-width:600px) {
  .ord-resumen { grid-template-columns:repeat(2,1fr); }
  .ord-prod-cab { flex-direction:column; }
}

/* El botón de la tanda mientras trabaja: deshabilitado se ve distinto y el texto
   dice en qué va. Sin esto el despachante lo tocaba de nuevo creyendo que no
   había arrancado, y cada clic de más sería otra tanda de llamadas al modelo. */
button[data-trabajando] { opacity:.75; cursor:progress; }
button[data-trabajando]::before { content:"⏳ "; }

/* Barra de acciones de la pantalla de Órdenes (el botón de orden de prueba). */
.ord-acciones { display:flex; align-items:center; gap:var(--e3); margin:0 0 var(--e4);
  flex-wrap:wrap; justify-content:flex-end; }
.ord-acciones .hint { margin:0; }

/* El costo de los certificados como % del FOB, debajo del monto. Es el número
   que decide: 2.050 dólares no dicen nada hasta saber contra qué se comparan. */
.ord-kpi small { display:block; font-size:var(--t-mini); color:var(--tx-3); margin-top:2px; }
.ord-kpi.destacado small { color:inherit; opacity:.75; }

/* ── El costo de la orden ────────────────────────────────────────────────────
   Es lo que decide si la operación se hace. Va debajo del resumen y arriba de
   los productos: se lee antes de mirar producto por producto. */
.ord-gastos { margin:14px 0 0; border:1px solid var(--bd-sutil); border-radius:var(--r-grande); padding:10px 12px; }
.ord-gastos summary { cursor:pointer; font-size:var(--t-base); color:var(--tx-2); }
.ord-gastos .ord-ar-grid { margin-top:10px; }

.ord-costeo { margin-top:14px; }
.ord-costeo.calculando { opacity:.55; }
.cost-cab { font-size:var(--t-chico); text-transform:uppercase; letter-spacing:.04em; color:var(--tx-3); margin-bottom:8px; }
/* 190px no alcanzaba para "Tasa estadística" + su monto: la etiqueta se partía
   en dos renglones y la fila quedaba el doble de alta que sus vecinas. */
.cost-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:0 var(--e5); }
.cost-fila { display:flex; justify-content:space-between; align-items:baseline; gap:var(--e3);
  padding:var(--e2) 0; border-bottom:1px solid var(--bd-sutil); font-size:var(--t-base); }
.cost-fila > span { color:var(--tx-2); white-space:nowrap; }
.cost-fila b { font-variant-numeric:tabular-nums; }
.cost-fila.sub { border-bottom-width:2px; border-bottom-style:solid; font-weight:600; }
.cost-fila.destaca b { color:var(--warn-texto); }

.cost-totales { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:10px; margin-top:14px; }
.cost-total { border:1px solid var(--bd-sutil); border-radius:var(--r-grande); padding:10px 12px; }
.cost-total span { display:block; font-size:var(--t-chico); color:var(--tx-3); }
.cost-total b { display:block; font-size:var(--t-grande); font-variant-numeric:tabular-nums; margin-top:2px; }
.cost-total small { display:block; font-size:var(--t-mini); color:var(--tx-3); margin-top:3px; }
/* Lo que vuelve, en verde: no es un costo. */
.cost-total.recupera b { color:var(--ok-texto); }
/* El número con el que se decide. */
.cost-total.manda { border-color:var(--info-texto); background:var(--info-bg); }
.cost-total.manda b { color:var(--info-texto); }

.cost-faltan { margin-top:10px; font-size:var(--t-chico); color:var(--tx-3);
  border-left:3px solid var(--warn-texto); padding-left:10px; }

/* Escenario del envío (LCL/FCL) y de dónde salieron los gastos. */
.ord-escenario { display:flex; align-items:flex-end; gap:14px; flex-wrap:wrap; margin-bottom:4px; }
.ord-escenario .hint { margin:0; flex:1 1 220px; }
.ord-escenario .hint.aviso { color:var(--warn-texto); }
/* Un gasto que puso la tarifa, no el usuario: se distingue del que él escribió. */
.ord-gasto.auto { color:var(--tx-2); font-style:italic; }

/* ── Visor de fotos ─────────────────────────────────────────────────────────
   Tocar una miniatura la abre grande. Ver el visor en util.js. */
.visor { position:fixed; inset:0; z-index:100; display:flex; align-items:center; justify-content:center;
  background:rgba(0,0,0,.86); padding:48px 56px; }
.visor[hidden] { display:none; }
.visor-img { max-width:100%; max-height:100%; object-fit:contain;
  border-radius:var(--r-chico); background:#fff; box-shadow:0 8px 40px rgba(0,0,0,.5); }
.visor-cerrar, .visor-nav { position:absolute; background:rgba(0,0,0,.45); color:#fff;
  border:1px solid rgba(255,255,255,.25); border-radius:var(--r-grande); cursor:pointer; line-height:1;
  display:flex; align-items:center; justify-content:center; }
.visor-cerrar { top:14px; right:16px; width:38px; height:38px; font-size:var(--t-medio); }
.visor-nav { top:50%; transform:translateY(-50%); width:42px; height:60px; font-size:30px; }
.visor-prev { left:10px; }
.visor-sig { right:10px; }
.visor-cerrar:hover, .visor-nav:hover { background:rgba(0,0,0,.75); }
.visor-nav[hidden] { display:none; }
.visor-pie { position:absolute; bottom:14px; left:50%; transform:translateX(-50%);
  color:rgba(255,255,255,.85); font-size:var(--t-chico); }
/* Sin scroll de fondo mientras el visor está abierto. */
body.con-visor { overflow:hidden; }
/* La miniatura avisa que se puede tocar. */
.fotos img, .fotos-b img, .foto-item img, .hist-thumb, .hist-thumb-det, .thumb { cursor:zoom-in; }

@media (max-width:600px) {
  .visor { padding:40px 8px; }
  .visor-nav { width:36px; height:52px; font-size:26px; }
}


/* ══════════════════════════════════════════════════════════════════════════
   ACABADO — lo que se nota sin poder señalarlo
   ══════════════════════════════════════════════════════════════════════════ */

/* Los códigos NCM y los montos, en cifras de ancho fijo: sin esto, dos números
   uno debajo del otro no se pueden comparar de un vistazo. */
code, .codigo, .mono, .num { font-family:var(--mono); font-variant-numeric:tabular-nums; }

/* Los títulos apretados: a tamaño grande, el tracking normal se ve suelto. */
h1, h2, h3 { letter-spacing:-.015em; }

/* Texto de apoyo: gris, chico, y con aire arriba. Es la clase más usada de
   todas y estaba definida distinto en cada pantalla. */
.hint { font-size:var(--t-chico); color:var(--tx-3); line-height:1.5; }

/* Nada de saltos bruscos al pasar el mouse. */
a, button, summary, .card, input, select, textarea { transition:background-color .12s ease, border-color .12s ease, color .12s ease; }

/* Respeta a quien pidió menos animación. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration:.01ms !important; transition-duration:.01ms !important; }
}

/* La imagen nunca desborda su caja. */
img { max-width:100%; }

/* Barras de scroll discretas: en una pantalla con varias listas, tres barras
   grises anchas son tres líneas que no dicen nada. */
* { scrollbar-width:thin; scrollbar-color:var(--bd-hover) transparent; }
::-webkit-scrollbar { width:10px; height:10px; }
::-webkit-scrollbar-thumb { background:var(--bd-hover); border-radius:var(--r-pill);
  border:3px solid var(--bg-app); }
::-webkit-scrollbar-track { background:transparent; }

/* Punto de estado. Reemplaza a los círculos de emoji: cada plataforma los
   dibujaba distinto, no seguían el tema y no se alineaban con el texto. */
.punto { display:inline-block; width:7px; height:7px; border-radius:var(--r-pill);
  margin-right:var(--e2); vertical-align:middle; background:var(--tx-3); }
.punto.pend { background:var(--warn); }
.punto.rev  { background:var(--info); }
.punto.ok   { background:var(--verde); }
.punto.err  { background:var(--err); }

/* ── Tabla del historial ────────────────────────────────────────────────────
   Las filas quedaban del doble de alto que su contenido porque dos columnas se
   partían: la fecha ("04:33 p. m." cortado al medio) y los tributos, que son
   seis valores metidos en un ancho de tres. */
.hist-tabla td, table td { vertical-align:top; }
/* Una fecha partida en dos renglones deja de leerse como una fecha. */
td.nota, .hist-fecha { white-space:nowrap; }
/* Los tributos: seis pares etiqueta-valor. En vez de un párrafo apretado, se
   dejan respirar y se corta por par, no por palabra. */
.tributos-inline, td .tribs { line-height:1.65; }

/* La corrección del despachante, con el código anterior. "Corregido" a secas no
   dice qué cambió — y quien lo abre mañana necesita ver de dónde a dónde, sobre
   todo si ya cotizó con el anterior. */
.correccion-b { margin-top:var(--e3); padding:var(--e3);
  background:var(--warn-bg); border-left:3px solid var(--warn-texto);
  border-radius:var(--r-chico); font-size:var(--t-chico); color:var(--warn-texto); }
.corr-de-a { margin-top:var(--e1); font-family:var(--mono); font-size:var(--t-base); }
.corr-viejo { text-decoration:line-through; opacity:.65; }
.corr-nuevo { font-weight:600; }
.correccion-b .nota { color:inherit; opacity:.85; margin-top:var(--e1); }

/* Corregir algo ya confirmado: existe, pero no es la operación de todos los
   días. Plegado y en tono de advertencia, para que quien lo abre sepa que está
   tocando algo que ya viajó al admin. */
.corregir-resuelta { border:1px dashed var(--warn-texto); background:var(--warn-bg); }
.corregir-resuelta summary { cursor:pointer; font-size:var(--t-chico); color:var(--warn-texto); font-weight:600; }
.corregir-resuelta .nota { color:var(--warn-texto); opacity:.9; margin-top:var(--e2); }

/* Las reglas aprendidas: cada una es una restricción que el modelo va a seguir. */
.regla-item { padding:var(--e3) 0; border-top:1px solid var(--bd-sutil); }
.regla-item:first-child { border-top:none; }
.regla-prod { font-size:var(--t-chico); color:var(--tx-2); margin-top:var(--e1); }
.regla-txt { margin-top:var(--e2); padding:var(--e2) var(--e3); font-size:var(--t-base);
  background:var(--bg-elevado); border-left:2px solid var(--verde); border-radius:0 var(--r-chico) var(--r-chico) 0; }

/* ── Modal ──────────────────────────────────────────────────────────────────
   Usado por el alta/edición de gastos. Fondo oscuro, caja centrada, y el fondo
   sin scroll: lo que se está cargando afecta a las cotizaciones de todos, así
   que conviene que ocupe toda la atención. */
.modal { position:fixed; inset:0; z-index:60; background:rgba(0,0,0,.55);
  display:flex; align-items:center; justify-content:center; padding:var(--e5); overflow-y:auto; }
.modal[hidden] { display:none; }
body.con-modal { overflow:hidden; }
.modal-caja { background:var(--bg-panel); border:1px solid var(--bd-sutil);
  border-radius:var(--r-grande); padding:var(--e5); width:100%; max-width:620px;
  max-height:90vh; overflow-y:auto; }
.modal-cab { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--e4); }
.modal-cab h2 { margin:0; }
.modal-cab .hint { margin:var(--e1) 0 0; }
.modal-caja > label { margin-top:var(--e4); }
.modal-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:var(--e4); margin-top:var(--e4); }
.modal-grid .hint { margin-top:var(--e1); }
.modal-pie { display:flex; justify-content:flex-end; gap:var(--e2); margin-top:var(--e5);
  padding-top:var(--e4); border-top:1px solid var(--bd-sutil); }
.g-activo { display:flex; align-items:center; gap:var(--e2); margin-top:var(--e4);
  text-transform:none; letter-spacing:0; font-size:var(--t-base); font-weight:400; color:var(--tx-1); }
.g-activo input { width:auto; }
.g-activo .hint { display:inline; }

/* Barra de acciones de la sección de gastos. */
.g-barra { display:flex; align-items:center; justify-content:space-between; gap:var(--e3);
  flex-wrap:wrap; margin:var(--e4) 0 var(--e3); }
.g-ver-inactivos { display:flex; align-items:center; gap:var(--e2); margin:0;
  text-transform:none; letter-spacing:0; font-size:var(--t-chico); color:var(--tx-2); font-weight:400; }
.g-ver-inactivos input { width:auto; }
.g-acciones { display:flex; gap:var(--e2); align-items:center; }
/* Borrar es irreversible y afecta a las cotizaciones de todos: se distingue. */
button.danger { background:transparent; color:var(--err-texto); border-color:var(--bd-sutil); }
button.danger:hover { background:var(--err-bg); border-color:var(--err-texto); }

/* Cuando el producto llegó sin foto se dice, en vez de dejar un hueco: un vacío
   se lee como "la pantalla está rota" y manda a buscar el problema acá. */
.sin-fotos { font-size:var(--t-chico); color:var(--tx-3); padding:var(--e3) 0; }

/* Visible solo para lectores de pantalla. El <h1> del header se oculta —la
   marca la dicen los logos— pero no se borra: sin un encabezado, quien navega
   con lector entra a la página sin saber qué es, y dos imágenes no se lo dicen. */
.solo-lectores { position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
