/* =============================================================================
   IDENTIDAD VISUAL — MÓDULO COMEX (Comercio Exterior)
   =============================================================================
   Manual: docs/identidad-visual.md. Plan del módulo: docs/RUNBOOK-COMEX.md.
   Hoja de referencia: facturas-ui.css (cabecera lite) y abm-ui.css (tarjetas,
   tablas, chips y §MOVIMIENTO).

   TODO va scopeado bajo `.cx-ui` y con prefijo `cx-`. El resto de GS sigue en
   Tailwind con su paleta: una regla suelta llamada `.card` o `.stat` rompería
   los nueve módulos sin migrar (manual §6).

   ── ESTE MÓDULO NACE EN IDENTIDAD NUEVA ──────────────────────────────────────
   No hay nada que migrar: 0 Tailwind y 0 `confirm/alert` desde la primera
   línea. Los diálogos, cuando lleguen, nacen con `core/dialogos.js`.

   ── DÓNDE ESTÁ EL FILETE NAVY DE 3 px ────────────────────────────────────────
   El runbook pide «cabecera lite: filete navy de 3 px, título navy». En el
   mockup ese filete corona la cabecera propia del módulo — que en la app NO
   existe: se fue a la barra superior del armazón (ver core/shell.js), igual
   que en Facturación, Remitos y el Tarifario.

   Y no se puede recolocar debajo de esa barra: con `shell-full` el wrapper
   tiene `padding: 0`, así que `.cx-shell` queda pegado al `#app-bar`, que ya
   trae su propio filete de 1 px más una sombra. Un navy de 3 px ahí abajo
   serían dos líneas separando lo mismo.

   El filete sigue vivo donde SÍ le corresponde y el mockup también lo dibuja:
   la cabecera de los modales (`.m-h` allá, `.cx-modal .cx-m-h` acá). Esa regla
   llega con la etapa que traiga el primer diálogo — acá no se escribe CSS para
   un elemento que todavía no existe.

   El «título navy», en cambio, sí vive desde hoy: es el color de la mesa
   activa en la barra de mesas y el de los rótulos de tarjeta.
   ========================================================================== */

/* LA PALETA NO ESTÁ ACÁ. Vive en src/core/tokens.css, que se carga antes y la
   declara una sola vez para todos los módulos con identidad. ComEx no se
   aparta en nada: usa los tokens tal cual salen, y en particular NO inventa un
   acento propio — navy alcanza, que es la decisión del runbook §3. Si alguna
   vez hiciera falta un valor propio se redeclara en un bloque `.cx-ui` acá,
   misma especificidad, gana el último, y se escribe el porqué al lado.

   La trampa §7 del manual (`.hidden` de Tailwind, que con una sola clase de
   especificidad pierde contra cualquier `.cx-ui .cx-loquesea` que declare
   `display`) también se resuelve allá: `.cx-ui` está en las tres listas de
   tokens.css. El caso del ROOT de un modal —que lleva `.cx-ui` él mismo— se
   resuelve con una regla propia el día que exista un modal. */

.cx-ui .material-symbols-outlined { font-size: 18px; line-height: 1; vertical-align: -4px; }

/* Obligación §5.2: quien navega con Tab tiene que ver dónde está parado. */
.cx-ui :focus-visible { outline: 2px solid var(--navy-500); outline-offset: 2px; border-radius: 5px; }

/* ── §MOVIMIENTO ─────────────────────────────────────────────────────────────
   Vocabulario portado LITERAL de abm-ui.css §MOVIMIENTO (que a su vez lo tomó
   de rrhh-ui.css). No se inventa nada acá — el mockup dibuja jerarquía y
   contenido, nunca animación (memoria `feedback_mockups_no_definen_animaciones`):

     · una sola curva para todo lo que se desplaza — var(--curva);
     · .14s para color y fondo, .18s para transformaciones;
     · nada se mueve más de 2 px: el gesto confirma que apuntaste algo,
       no lo festeja;
     · el ícono sube 2 px, el contenedor 1 px, y `:active` vuelve a cero —
       eso último es lo que da la sensación de que el botón se hundió.

   `prefers-reduced-motion` apaga el movimiento sin perder información: todo lo
   que este archivo anima es redundante con un color o un peso tipográfico.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .cx-ui * { transition: none !important; animation: none !important; }
}

/* =============================================================================
   ARMAZÓN
   ========================================================================== */
/* SIN ESPACIO entre las dos clases: el div es `class="cx-ui cx-shell"`, UN
   elemento con las dos. Escrito `.cx-ui .cx-shell` (descendiente) este bloque
   no matchearía NADA y el módulo se quedaría sin `display:flex` y sin
   `height:100%`, creciendo con su contenido adentro de un contenedor
   `overflow:hidden` — o sea, sin scroll y con las filas de abajo tapadas.
   Es el bug que le costó seis etapas al ABM, y por eso hay un chequeo
   automático que lo mira (hub-2-publican.py §9).

   El armazón va en un <div> HIJO de `#page-comex`, como el ABM, Configuración,
   Logística y el Tarifario: así el `.page-content` queda limpio y el `.hidden`
   del router le pega sin pelear (trampa §8 del manual). */
.cx-ui.cx-shell {
    display: flex; flex-direction: column;
    height: 100%; min-height: 0;
    background: var(--canvas);
}

/* ── Las siete mesas — subrayado que crece desde el centro ─────────────────
   Un `border-bottom` no se puede animar (manual §7): va un ::after con scaleX.
   Portado literal de facturas-ui.css / tarifario-ui.css, no reinventado acá.

   `overflow-x: auto` y no `flex-wrap`: son SIETE, y en una pantalla angosta
   envolverlas partiría la fila de mesas en dos renglones — que se lee como dos
   niveles de navegación cuando hay uno solo. */
.cx-ui .cx-secnav {
    background: var(--surface); border-bottom: 1px solid var(--hair);
    display: flex; gap: 2px; padding: 0 14px; flex-shrink: 0; overflow-x: auto;
}
.cx-ui .cx-secnav button {
    position: relative; background: none; border: 0; font: inherit;
    font-size: 12.8px; font-weight: 600; color: var(--muted);
    padding: 12px 15px 13px; cursor: pointer; white-space: nowrap;
    display: inline-flex; align-items: center; gap: 7px;
    transition: color .14s var(--curva), background .14s var(--curva);
}
.cx-ui .cx-secnav button .material-symbols-outlined {
    font-size: 18px; transition: transform .18s var(--curva);
}
.cx-ui .cx-secnav button::after {
    content: ''; position: absolute; left: 10px; right: 10px; bottom: 0;
    height: 2.5px; background: var(--navy); border-radius: 2px 2px 0 0;
    transform: scaleX(0); transition: transform .18s var(--curva);
}
.cx-ui .cx-secnav button:hover, .cx-ui .cx-secnav button:focus-visible {
    color: var(--navy); background: var(--navy-050); outline: none;
}
.cx-ui .cx-secnav button:hover::after,
.cx-ui .cx-secnav button:focus-visible::after { transform: scaleX(.55); }
.cx-ui .cx-secnav button:hover .material-symbols-outlined { transform: scale(1.18); }
.cx-ui .cx-secnav button[aria-current="page"] { color: var(--navy); font-weight: 700; }
.cx-ui .cx-secnav button[aria-current="page"]::after { transform: scaleX(1); }

/* El contador de pendientes de una mesa. Es ÁMBAR porque significa «esto pide
   trabajo», nunca «esta mesa tiene cosas»: una mesa con 40 carpetas cerradas y
   nada que hacer no lleva número. Lo escribe la etapa de cada mesa; la 1 no
   dibuja ninguno, porque todavía no hay nada que contar. */
.cx-ui .cx-secnav button .cx-nb {
    display: inline-block; min-width: 16px; text-align: center;
    font-size: .62rem; font-weight: 800; font-variant-numeric: tabular-nums;
    background: var(--warn-050); color: var(--warn); border: 1px solid var(--warn-hair);
    border-radius: 99px; padding: 0 5px;
}

/* La cola de la barra: lo que acompaña a la navegación sin ser navegación.
   Hoy está vacía; existe para que la mesa que la necesite no tenga que
   inventarse una segunda barra debajo. */
.cx-ui .cx-secnav .cx-cola { margin-left: auto; display: flex; align-items: center; gap: 10px; padding: 6px 0; }

/* ── Área de trabajo ──────────────────────────────────────────────────────
   `min-height: 0` no es opcional: un `flex: 1` sin él estira en vez de
   scrollear, y lo que pasa del pliegue queda tapado sin barra en ningún lado.
   El scroll es de la VISTA y no del área: así cada mesa recuerda dónde estaba
   y ninguna arrastra el scroll de la anterior. */
.cx-ui .cx-work { flex: 1; min-height: 0; min-width: 0; position: relative; }
.cx-ui .cx-view { height: 100%; overflow-y: auto; overscroll-behavior: contain; padding: 14px 0 24px; }

/* El canal lateral, UNA sola medida (var(--gutter), de tokens.css). Lo que va
   de borde a borde no lo lleva: se lo aplica a su contenido. */
.cx-ui .cx-pad { padding-left: var(--gutter); padding-right: var(--gutter); }

/* =============================================================================
   TARJETAS DE PENDIENTE (el Panel)
   =============================================================================
   Portadas de `.abm-stat`. SIN NÚMEROS GIGANTES — preferencia explícita de
   Hernán (04/08/2026, runbook §3): la cifra va al tamaño del ABM (1.34rem) y
   la jerarquía la hacen el peso, el espacio y el color de estado. Una cifra
   display de 3rem grita el número aunque el número sea cero.

   Son BOTONES, no tarjetas decorativas: cada una abre su mesa con el filtro
   puesto. Si una tarjeta no lleva a ningún lado, no va en el Panel.

   El color es del ESTADO y de nada más (manual §1.1): rojo = vencido, ámbar =
   pide atención, neutro = informativo. Nunca «divisas es azul». */
.cx-ui .cx-stats {
    display: flex; gap: 10px; flex-wrap: wrap;
    padding: 0 var(--gutter);
}
/* COLUMNA CON ARRANQUE ARRIBA, y esto no es decoración. Un <button> centra
   verticalmente su contenido: como las seis descripciones ocupan dos o tres
   líneas según el texto, los seis rótulos quedaban a alturas distintas aunque
   las seis cajas midan exactamente lo mismo (medido: top 59, alto 113 las
   seis). Una tira de KPIs cuyos rótulos no comparten línea de base se lee como
   un error de armado. `flex-direction: column` + `justify-content: flex-start`
   los pega arriba; la caja sigue estirando parejo por el `stretch` del padre.
   Lo mostró la foto — leyendo el CSS no se ve. */
.cx-ui .cx-stat {
    flex: 1; min-width: 168px; text-align: left; font: inherit; cursor: pointer;
    display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start;
    background: var(--surface); border-radius: 12px; padding: 10px 13px;
    border: 1px solid rgba(16, 32, 64, .05); border-left: 3px solid var(--hair-strong);
    box-shadow: var(--e1);
    transition: box-shadow .18s var(--curva), transform .18s var(--curva);
}
.cx-ui .cx-stat:hover { transform: translateY(-2px); box-shadow: var(--e2); }
.cx-ui .cx-stat:active { transform: translateY(0); box-shadow: var(--e1); }
.cx-ui .cx-stat .k {
    display: block; font-size: .58rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: .1em; color: var(--faint);
}
.cx-ui .cx-stat .v {
    display: block; font-size: 1.34rem; font-weight: 800; line-height: 1.2;
    margin-top: 2px; font-variant-numeric: tabular-nums; color: var(--ink);
}
.cx-ui .cx-stat .d { display: block; font-size: .68rem; font-weight: 600; color: var(--faint); }

/* Los tres estados. El teñido del fondo es sólo para el ámbar y arranca en el
   6 % del alto: una tarjeta entera de color compite con la tabla de al lado. */
.cx-ui .cx-stat.ok  { border-left-color: var(--ok); }
.cx-ui .cx-stat.ok .v { color: var(--ok); }
.cx-ui .cx-stat.wrn { border-left-color: var(--warn); background: linear-gradient(180deg, var(--warn-050), var(--surface) 62%); }
.cx-ui .cx-stat.wrn .v { color: var(--warn); }
.cx-ui .cx-stat.neg { border-left-color: var(--crit); }
.cx-ui .cx-stat.neg .v { color: var(--crit); }

/* UNA CIFRA QUE NADIE CALCULÓ NO SE ESCRIBE COMO CIFRA. Mientras la mesa que
   alimenta la tarjeta no exista, el valor es una raya y va en gris, aunque el
   borde de estado ya esté puesto: pintar «0» ahí sería afirmar que se contó y
   no había nada, que es distinto de no haber contado.
   (Memorias `feedback_campo_que_se_guarda_y_nadie_lee` y
   `feedback_estado_que_se_lee_y_nadie_escribe`.) */
.cx-ui .cx-stat.sindato { border-left-color: var(--hair-strong); background: var(--surface); }
.cx-ui .cx-stat.sindato .v { color: var(--faint); font-weight: 700; }

/* =============================================================================
   AVISO CONTEXTUAL
   =============================================================================
   La franja de 3 px del margen izquierdo carga el estado; el resto del bloque
   se mantiene sobre `--surface` para no encender media pantalla. */
.cx-ui .cx-risk {
    margin: 12px var(--gutter) 0; padding: 9px 13px; border-radius: 10px;
    border: 1px solid var(--hair-strong); border-left: 3px solid var(--navy-500);
    background: var(--surface); box-shadow: var(--e1);
    font-size: .76rem; color: var(--ink); line-height: 1.55;
}
.cx-ui .cx-risk b { font-weight: 700; }
.cx-ui .cx-risk.alerta { border-left-color: var(--warn); border-color: var(--warn-hair); background: var(--warn-050); }
.cx-ui .cx-risk.critico { border-left-color: var(--crit); border-color: var(--crit-hair); background: var(--crit-050); }
/* `info` NO es un cuarto nivel de gravedad: es la ausencia de gravedad. Lo usa
   el dato que está bien y hay que tener a la vista —el permiso de embarque ya
   cargado— y por eso va en navy, que en este sistema no significa estado sino
   «esto es del documento». Pintarlo verde diría «salió bien algo que podía
   salir mal», y un permiso cargado no es un logro: es un dato. */
.cx-ui .cx-risk.info { border-left-color: var(--navy); border-color: var(--hair-strong); background: var(--navy-050); }
.cx-ui .cx-risk .material-symbols-outlined { flex: 0 0 auto; margin-top: 1px; color: var(--faint); }
.cx-ui .cx-risk.alerta .material-symbols-outlined { color: var(--warn); }
.cx-ui .cx-risk.critico .material-symbols-outlined { color: var(--crit); }
.cx-ui .cx-risk.info .material-symbols-outlined { color: var(--navy); }

/* =============================================================================
   TARJETA CONTENEDORA (una mesa adentro)
   ========================================================================== */
.cx-ui .cx-card {
    margin: 13px var(--gutter) 0; background: var(--surface); border-radius: var(--r-card);
    border: 1px solid rgba(16, 32, 64, .05); box-shadow: var(--shadow); overflow: hidden;
}
.cx-ui .cx-card-h {
    padding: 9px var(--gutter); border-bottom: 1px solid var(--hair); background: #fafbfd;
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.cx-ui .cx-card-h h5 {
    margin: 0; font-size: .64rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
}
.cx-ui .cx-card-h .hint { margin-left: auto; font-size: .7rem; font-weight: 600; color: var(--faint); }

/* =============================================================================
   LA MESA QUE TODAVÍA NO SE CONSTRUYÓ
   =============================================================================
   Seis de las siete mesas no existen en la etapa 1, y el cartel que las ocupa
   tiene que decir TRES cosas o no sirve de nada: qué va a haber ahí, en qué
   etapa llega, y dónde está escrito eso. Un «Próximamente» solo es una pared.

   En gris, no en ámbar: que una etapa futura no esté hecha no es una anomalía
   del sistema — el ámbar se reserva para lo que le pide algo al usuario. */
.cx-ui .cx-obra {
    margin: 13px var(--gutter) 0; padding: 30px 26px;
    background: var(--surface); border-radius: var(--r-card);
    border: 1px dashed var(--hair-strong); box-shadow: var(--e1);
    text-align: center; color: var(--muted);
}
.cx-ui .cx-obra .material-symbols-outlined {
    font-size: 30px; color: var(--hair-strong); vertical-align: middle;
}
.cx-ui .cx-obra h4 {
    margin: 8px 0 0; font-size: .95rem; font-weight: 700; color: var(--ink);
}
/* El párrafo va ALINEADO A LA IZQUIERDA aunque el cartel esté centrado: son
   cuatro o cinco renglones, y centrados obligan a buscar dónde empieza cada
   uno. Se centra el BLOQUE (margin auto), no el texto. El título y el renglón
   de etapa sí van centrados: son una línea cada uno. */
.cx-ui .cx-obra p {
    margin: 8px auto 0; font-size: .78rem; max-width: 58ch;
    line-height: 1.6; text-align: left;
}
.cx-ui .cx-obra p.et {
    margin-top: 14px; font-size: .68rem; font-weight: 700; color: var(--faint);
    text-transform: uppercase; letter-spacing: .07em; text-align: center;
}

/* =============================================================================
   ETAPA 2 — CONTROLES, TABLAS, MODAL Y PANTALLA DE DOCUMENTO
   =============================================================================
   Todo lo de acá abajo está portado de abm-ui.css con UN solo cambio
   sistemático: donde el ABM usa `--azure` (su acento), ComEx usa `--navy`.
   No es una preferencia — es la decisión del runbook §3: «Sin acento propio:
   navy alcanza, no se inventa un segundo azul». Un módulo nuevo con su propio
   celeste sería la sexta paleta del sistema.

   El MOVIMIENTO no se reinventa acá: sale del §MOVIMIENTO de arriba, que ya lo
   portó literal. Una sola curva, .14s color / .18s transformación, nada se
   mueve más de 2 px y `:active` vuelve a cero.
   ========================================================================== */

/* ── Botones ─────────────────────────────────────────────────────────────── */
.cx-ui .cx-btn {
    display: inline-flex; align-items: center; gap: 6px;
    font: inherit; font-size: .79rem; font-weight: 700; white-space: nowrap;
    background: var(--navy); color: #fff; border: 1px solid var(--navy);
    border-radius: 8px; padding: 7px 14px; cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 43, 107, .22);
    transition: background .14s var(--curva), border-color .14s var(--curva),
                transform .18s var(--curva), box-shadow .18s var(--curva);
}
.cx-ui .cx-btn .material-symbols-outlined { font-size: 17px; transition: transform .18s var(--curva); }
.cx-ui .cx-btn:hover {
    background: var(--navy-700); border-color: var(--navy-700);
    transform: translateY(-1px); box-shadow: 0 4px 14px rgba(0, 43, 107, .26);
}
.cx-ui .cx-btn:hover .material-symbols-outlined { transform: translateY(-2px); }
.cx-ui .cx-btn:active { transform: translateY(0); box-shadow: 0 2px 8px rgba(0, 43, 107, .22); }
.cx-ui .cx-btn:disabled { opacity: .45; cursor: default; transform: none; box-shadow: none; }
.cx-ui .cx-btn.sec {
    background: var(--surface); color: var(--muted); border-color: var(--hair-strong); box-shadow: none;
}
.cx-ui .cx-btn.sec:hover { background: var(--navy-050); border-color: var(--navy-300); color: var(--navy); box-shadow: none; }
.cx-ui .cx-btn.danger { background: var(--crit); border-color: var(--crit); box-shadow: 0 2px 8px rgba(198, 40, 40, .24); }
.cx-ui .cx-btn.danger:hover { background: #a71f1f; border-color: #a71f1f; }
.cx-ui .cx-btn.ln {
    background: none; border-color: transparent; color: var(--navy); box-shadow: none; padding: 6px 10px;
}
.cx-ui .cx-btn.ln:hover { background: var(--navy-050); box-shadow: none; }

/* Íconos de acción de fila: apagados en reposo, suben al apuntarlos. */
.cx-ui .cx-x {
    background: none; border: 1px solid transparent; border-radius: 7px; padding: 5px 6px;
    cursor: pointer; color: var(--faint); line-height: 1;
    transition: background .14s var(--curva), color .14s var(--curva), border-color .14s var(--curva);
}
.cx-ui .cx-x .material-symbols-outlined { display: block; transition: transform .18s var(--curva); }
.cx-ui .cx-x:hover { background: var(--navy-050); color: var(--navy); border-color: rgba(0, 43, 107, .18); }
.cx-ui .cx-x:hover .material-symbols-outlined { transform: translateY(-2px); }
.cx-ui .cx-x:active .material-symbols-outlined { transform: translateY(0); }
.cx-ui .cx-x.del:hover { background: var(--crit-050); color: var(--crit); border-color: var(--crit-hair); }
.cx-ui .cx-x:disabled { opacity: .4; cursor: default; }

/* ── Campos ──────────────────────────────────────────────────────────────── */
.cx-ui .cx-in {
    width: 100%; border: 1px solid var(--hair-strong); border-radius: 8px; padding: 7px 11px;
    font: inherit; font-size: .82rem; color: var(--ink); background: var(--surface); outline: none;
    transition: border-color .14s var(--curva), box-shadow .18s var(--curva);
}
.cx-ui .cx-in:focus { border-color: var(--navy-500); box-shadow: 0 0 0 3px rgba(21, 74, 148, .14); }
.cx-ui .cx-in:disabled { background: #f5f7fa; color: var(--muted); cursor: default; }
.cx-ui .cx-in.n { text-align: right; font-variant-numeric: tabular-nums; }
.cx-ui textarea.cx-in, .cx-ui .cx-txt { min-height: 66px; resize: vertical; }
/* `select.cx-in` nace llenando su columna, al revés que en el ABM: en ComEx su
   caso principal es el formulario, no la barra de filtros. La barra le da su
   ancho a mano cuando hace falta. */
.cx-ui select.cx-in { cursor: pointer; }
.cx-ui .cx-bar select.cx-in { width: auto; min-width: 150px; }

.cx-ui .cx-lbl {
    display: block; font-size: .62rem; text-transform: uppercase; letter-spacing: .08em;
    font-weight: 800; color: var(--muted); margin-bottom: 4px;
}
.cx-ui .cx-lbl .req { color: var(--crit); }
.cx-ui .cx-ayuda { display: block; margin-top: 4px; font-size: .69rem; color: var(--faint); }
/* El eco del maestro: cuando dice un dato de verdad —y no la promesa de que va
   a decirlo— sube de peso y de contraste. Es el mismo texto cambiando de
   estado, no dos textos distintos. */
.cx-ui .cx-ayuda.fuerte { color: var(--navy-500); font-weight: 700; }
/* Un botón que se lee como enlace, adentro de una línea de ayuda: «+ Nueva
   aduana» al lado del selector (4f). Sin caja: es texto que hace algo. */
.cx-ui .cx-link { background: none; border: 0; padding: 0; font: inherit; font-weight: 700; color: var(--navy-500); cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.cx-ui .cx-link:hover { color: var(--navy); }
.cx-ui .cx-err { display: block; margin-top: 12px; font-size: .755rem; font-weight: 700; color: var(--crit); }

.cx-ui .cx-ck {
    display: inline-flex; align-items: center; gap: 7px; font-size: .78rem;
    font-weight: 600; color: var(--muted); cursor: pointer; user-select: none;
}
.cx-ui .cx-ck input { width: 16px; height: 16px; accent-color: var(--navy); cursor: pointer; }

.cx-ui .cx-switch {
    display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px;
    border: 1px solid var(--hair-strong); border-radius: 9px; background: var(--surface);
    cursor: pointer; user-select: none; transition: border-color .14s var(--curva);
}
.cx-ui .cx-switch:hover { border-color: var(--navy-300); }
.cx-ui .cx-switch input { width: 17px; height: 17px; margin-top: 2px; accent-color: var(--navy); cursor: pointer; flex: 0 0 auto; }
.cx-ui .cx-switch b { display: block; font-size: .79rem; font-weight: 700; color: var(--ink); }
.cx-ui .cx-switch span span { display: block; font-size: .72rem; color: var(--muted); }

/* Un campo con un botón pegado (el selector de cliente y su «+ Nuevo»). El
   botón no se encoge: el que se estira es el campo. */
.cx-ui .cx-conboton { display: flex; gap: 8px; align-items: stretch; }
.cx-ui .cx-conboton .cx-in { flex: 1; min-width: 0; }
.cx-ui .cx-conboton .cx-btn { flex: 0 0 auto; }

/* ── Barra de filtros ────────────────────────────────────────────────────── */
.cx-ui .cx-bar {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 11px var(--gutter); border-bottom: 1px solid var(--hair);
}
.cx-ui .cx-busca { position: relative; flex: 1; min-width: 210px; max-width: 420px; }
.cx-ui .cx-busca .material-symbols-outlined {
    position: absolute; left: 10px; top: 8px; color: var(--faint);
    transition: color .14s var(--curva); pointer-events: none;
}
.cx-ui .cx-busca:focus-within .material-symbols-outlined { color: var(--navy); }
.cx-ui .cx-busca .cx-in { padding-left: 33px; }

/* ── Tabla ───────────────────────────────────────────────────────────────── */
.cx-ui .cx-tw { overflow-x: auto; }
.cx-ui table.cx-g { width: 100%; border-collapse: collapse; background: var(--surface); }
.cx-ui table.cx-g th {
    position: sticky; top: 0; z-index: 1;
    background: var(--surface); color: var(--muted);
    font-size: .6rem; text-transform: uppercase; letter-spacing: .1em; font-weight: 800;
    text-align: left; padding: 10px 12px; white-space: nowrap;
    border-bottom: 2px solid var(--ink);   /* regla gruesa, como un informe impreso */
}
.cx-ui table.cx-g td {
    padding: 10px 12px; border-bottom: 1px solid var(--hair);
    white-space: nowrap; vertical-align: middle; font-size: .82rem;
}
/* nowrap es el default: un número partido en dos renglones es ilegible. Se pide
   envolver a mano, y sólo la columna que de verdad lo necesita. */
.cx-ui table.cx-g td.w, .cx-ui table.cx-g th.w { white-space: normal; min-width: 190px; }
.cx-ui table.cx-g th.n, .cx-ui table.cx-g td.n { text-align: right; }
.cx-ui table.cx-g th.c, .cx-ui table.cx-g td.c { text-align: center; }
.cx-ui table.cx-g td:first-child { border-left: 3px solid transparent; padding-left: calc(var(--gutter) - 3px); }
.cx-ui table.cx-g th:first-child { padding-left: var(--gutter); }
.cx-ui table.cx-g td:last-child, .cx-ui table.cx-g th:last-child { padding-right: var(--gutter); text-align: right; }
.cx-ui table.cx-g tbody tr { transition: background .14s var(--curva); }
.cx-ui table.cx-g tbody tr:nth-child(even) { background: #fafbfd; }
.cx-ui table.cx-g tbody tr:hover { background: var(--navy-050); }
.cx-ui table.cx-g tbody tr:last-child td { border-bottom: 0; }

/* Estado de fila: franja de 3 px a la izquierda. Libera la columna de estado
   para que diga QUÉ pasa en vez de repetir el color. */
.cx-ui table.cx-g tr.st-ok  td:first-child { border-left-color: var(--ok-hair); }
.cx-ui table.cx-g tr.st-wrn td:first-child { border-left-color: var(--warn); }
.cx-ui table.cx-g tr.st-neg td:first-child { border-left-color: var(--crit); }
/* Fila apagada: baja de peso sin perder contraste — nada de opacity global,
   que además apaga el foco del teclado. */
.cx-ui table.cx-g tr.apagada td { color: var(--muted); }

/* La fila entera abre el expediente (el mockup: «clic en fila → expediente»).
   El número además es un BOTÓN de verdad: un <tr> no se puede enfocar con el
   teclado, así que sin él el expediente existiría sólo para el mouse. */
.cx-ui table.cx-g tbody tr.cx-clic { cursor: pointer; }
.cx-ui .cx-lk {
    font: inherit; font-weight: 700; color: var(--navy-500); background: none;
    border: 1px solid transparent; border-radius: 6px; padding: 1px 5px; margin-left: -5px;
    cursor: pointer; text-align: left;
    transition: background .14s var(--curva), color .14s var(--curva);
}
.cx-ui .cx-lk:hover { background: var(--navy-050); color: var(--navy); }

.cx-ui .cx-nom { font-weight: 700; }
.cx-ui .cx-nom small, .cx-ui table.cx-g td small {
    display: block; font-weight: 600; font-size: .69rem; color: var(--faint); margin-top: 1px;
}
.cx-ui .dim { color: var(--faint); font-weight: 600; }

.cx-ui .cx-b {
    display: inline-block; font-size: .62rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .04em; padding: 2.5px 8px; border-radius: 99px;
    background: var(--canvas); color: var(--muted); border: 1px solid var(--hair-strong);
}
.cx-ui .cx-b.ok  { background: var(--ok-050);   color: var(--ok);   border-color: var(--ok-hair); }
.cx-ui .cx-b.wrn { background: var(--warn-050); color: var(--warn); border-color: var(--warn-hair); }
.cx-ui .cx-b.neg { background: var(--crit-050); color: var(--crit); border-color: var(--crit-hair); }

.cx-ui .cx-mark {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: .69rem; font-weight: 700; color: var(--muted); margin-top: 3px;
}
.cx-ui .cx-mark .material-symbols-outlined { font-size: 14px; vertical-align: -2px; }
.cx-ui .cx-mark.wrn { color: var(--warn); }
.cx-ui .cx-mark.neg { color: var(--crit); }

/* Pie de tarjeta: el contador y —en esta etapa— la nota que explica por qué
   todas las carpetas dicen lo mismo en la columna «Etapa». */
.cx-ui .cx-card-f {
    padding: 10px var(--gutter); background: #fafbfd; border-top: 1px solid var(--hair);
    display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
    font-size: .72rem; font-weight: 700; color: var(--muted);
}
.cx-ui .cx-card-f .nota {
    flex: 1; min-width: 260px; font-weight: 600; color: var(--faint); line-height: 1.5;
}
.cx-ui .cx-card-f .nota b { color: var(--muted); font-weight: 700; }

/* ── Vacío y espera ──────────────────────────────────────────────────────── */
.cx-ui .cx-ph { padding: 40px 20px; text-align: center; color: var(--muted); }
/* El vacío casi siempre cae dentro de un <td colspan>, que hereda el nowrap de
   la tabla. Sin esto, el texto de ayuda sale en una sola línea infinita. */
.cx-ui table.cx-g td .cx-ph { white-space: normal; }
.cx-ui .cx-ph .material-symbols-outlined { font-size: 36px; color: var(--hair-strong); display: block; margin: 0 auto 8px; }
.cx-ui .cx-ph b { display: block; font-size: .88rem; color: var(--ink); margin-bottom: 3px; }
.cx-ui .cx-ph span { font-size: .77rem; }
/* ── EL SPINNER PROPIO DE COMEX MURIÓ, y acá no quedó nada ───────────────────
   Acá vivía `.cx-spin`: quince píxeles de anillo con su propio `@keyframes`, y
   `.cx-ph .cx-spin` para pararlo adentro de un vacío. Era la copia número
   catorce del mismo dibujo, y el 04/08/2026 el sistema de espera de
   `docs/identidad-visual.md` §5 lo reemplazó por una pieza única (`.gs-spin`
   en `core/tokens.css`) con dos helpers en `core/ui.js`.

   Borrarlo no es prolijidad: es lo que impide que la próxima diferencia entre
   dos anillos de GS sea un descuido en vez de una decisión — que es exactamente
   lo que le pasó a `--faint` antes de que existiera `tokens.css`.

   Y NO QUEDÓ NI UNA REGLA DE POSICIÓN. La primera versión de este bloque dejaba
   un `.cx-ui .cx-ph .gs-spin { display:block }` «para pararlo adentro de la
   tarjeta», y el banco de la espera lo marcó rojo con razón: una hoja de módulo
   que toca la pieza del sistema es el primer paso de las trece copias, aunque
   sólo la corra de lugar. Además ya no hacía falta — el anillo lo dibuja
   `gsZonaCargando`, que trae su propio centrado. */

/* =============================================================================
   EL ÍNDICE DE DEFINICIONES
   =============================================================================
   Cuatro tarjetas: una viva y tres anunciadas. La viva se marca con el filete
   navy y la sombra levantada; las otras quedan con el borde gris del `.sindato`
   de las tarjetas del Panel — la misma señal, por el mismo motivo: lo que
   todavía no está no se pinta como si estuviera.

   NO son botones y por eso no tienen `:hover` de elevación: la sección viva se
   administra en la tabla de abajo, en esta misma pantalla. Una tarjeta que se
   levanta al pasarle por encima promete que se puede tocar. */
.cx-ui .cx-idx { display: flex; gap: 10px; flex-wrap: wrap; padding: 0 var(--gutter); }
.cx-ui .cx-idx-it {
    flex: 1; min-width: 190px;
    display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start;
    background: var(--surface); border-radius: 12px; padding: 10px 13px;
    border: 1px solid rgba(16, 32, 64, .05); border-left: 3px solid var(--hair-strong);
    box-shadow: var(--e1);
}
.cx-ui .cx-idx-it.viva { border-left-color: var(--navy); box-shadow: var(--e2); }
.cx-ui .cx-idx-it .k {
    font-size: .55rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .1em; color: var(--faint);
}
.cx-ui .cx-idx-it .v { font-size: .88rem; font-weight: 800; color: var(--ink); line-height: 1.3; margin-top: 1px; }
.cx-ui .cx-idx-it.viva .v { color: var(--navy); }
.cx-ui .cx-idx-it .d { font-size: .68rem; font-weight: 600; color: var(--faint); line-height: 1.45; margin-top: 2px; }
.cx-ui .cx-idx-it .et {
    margin-top: auto; padding-top: 7px;
    font-size: .58rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .07em; color: var(--faint);
}
.cx-ui .cx-idx-it.viva .et { color: var(--navy-500); }

/* =============================================================================
   EL MODAL DE FORMULARIO — y el filete navy de 3 px
   =============================================================================
   ACÁ ESTÁ EL FILETE. El runbook §3 pide «cabecera lite: filete navy de 3 px»,
   y la etapa 1 explicó por qué no lo puso arriba de la mesa: con `shell-full`
   el módulo queda pegado al `#app-bar`, que ya trae su hairline y su sombra, y
   serían dos líneas separando lo mismo. Quedó reservado para la cabecera de los
   modales, que es donde el mockup también lo dibuja. Éste es el primer modal.

   OJO: la raíz lleva `.cx-ui` ELLA MISMA, y por eso el selector es
   `.cx-ui.cx-modal` SIN espacio. El modal se cuelga de <body>, o sea fuera de
   `#page-comex`: si el scope dependiera del padre, saldría sin un solo estilo.
   Escrito con espacio (`.cx-ui .cx-modal`) este bloque no matchearía NADA — es
   la misma trampa del armazón, que ya costó seis etapas en el ABM.

   Y el `.hidden` del error interno: adentro de un modal la regla de tokens.css
   (`.cx-ui .hidden`) sí matchea, porque el `<span>` es descendiente de la raíz
   que lleva la clase. */
.cx-ui.cx-modal {
    position: fixed; inset: 0; z-index: 200;
    background: rgba(10, 20, 42, .5); backdrop-filter: blur(2px);
    display: flex; align-items: center; justify-content: center; padding: 22px;
    animation: cxFade .16s ease;
}
@keyframes cxFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes cxRise { from { opacity: 0; transform: translateY(10px) scale(.985); } to { opacity: 1; transform: none; } }

.cx-ui .cx-panel {
    background: var(--surface); border-radius: 14px; box-shadow: var(--e3);
    width: 100%; max-width: 580px; max-height: 88vh;
    display: flex; flex-direction: column; overflow: hidden;
    animation: cxRise .2s var(--curva);
}
.cx-ui .cx-panel.ancho { max-width: 880px; }
.cx-ui .cx-m-h {
    padding: 14px 22px; display: flex; align-items: center; gap: 10px; flex-shrink: 0;
    border-top: 3px solid var(--navy);       /* ← el filete */
    border-bottom: 1px solid var(--hair);
}
.cx-ui .cx-m-h h3 { margin: 0; font-size: .95rem; font-weight: 800; color: var(--navy); }
.cx-ui .cx-m-h .s { margin-top: 2px; font-size: .71rem; font-weight: 600; color: var(--faint); }
.cx-ui .cx-m-h .cx-x { margin-left: auto; flex: 0 0 auto; }
.cx-ui .cx-m-b { padding: 18px 22px; overflow-y: auto; flex: 1; min-height: 0; }
.cx-ui .cx-m-f {
    padding: 12px 22px; border-top: 1px solid var(--hair); background: #f7f9fc;
    display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; flex-shrink: 0;
}

.cx-ui .cx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 13px; }
.cx-ui .cx-grid.tres { grid-template-columns: repeat(3, 1fr); }
.cx-ui .cx-grid .full { grid-column: 1 / -1; }

/* Bloque agrupado dentro de un formulario. En el maestro de clientes NO es
   decoración: separa lo que IDENTIFICA al cliente de lo que se COPIA a la
   carpeta cuando se lo elige, que son dos clases de dato distintas. El rótulo
   lo dice con palabras. */
.cx-ui .cx-fold {
    border: 1px solid var(--hair); border-radius: 10px; margin-top: 16px;
    overflow: hidden; box-shadow: var(--e1);
    transition: border-color .14s var(--curva), box-shadow .18s var(--curva);
}
.cx-ui .cx-fold:focus-within { border-color: var(--navy-300); box-shadow: var(--e2); }
.cx-ui .cx-fold > .t {
    background: #f7f9fc; padding: 9px 13px; font-size: .64rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: .08em; color: var(--muted);
    border-bottom: 1px solid var(--hair);
}
.cx-ui .cx-fold > .t .lib { font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--faint); }
.cx-ui .cx-fold > .c { padding: 14px 13px; }

/* =============================================================================
   LA PANTALLA DE DOCUMENTO (el alta hoy, el expediente en la etapa 4)
   =============================================================================
   Una carpeta es un DOCUMENTO, no un registro de ABM: nace, avanza por hitos y
   se cierra. Por eso va en pantalla y no en modal — corrección de Hernán del
   04/08/2026 al elegir el alta, y el molde de GS para un pedido
   (`renderNewOrderForm()` escribe una pantalla, no un cartel).

   El ancho está TOPEADO. Un formulario que se estira hasta los 1900 px de un
   monitor ancho deja el rótulo de un campo a medio metro de su valor, y la
   tabla de renglones queda con seis columnas y un desierto en el medio. */
.cx-ui .cx-volver-barra { padding: 0 var(--gutter); }
.cx-ui .cx-doc {
    max-width: 1020px; margin: 10px var(--gutter) 0;
    background: var(--surface); border-radius: var(--r-card);
    border: 1px solid rgba(16, 32, 64, .05); box-shadow: var(--e2); overflow: hidden;
}
.cx-ui .cx-doc-h {
    padding: 15px var(--gutter); border-bottom: 1px solid var(--hair); background: #fafbfd;
    border-top: 3px solid var(--navy);
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.cx-ui .cx-doc-h .k {
    display: block; font-size: .58rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .1em; color: var(--faint);
}
.cx-ui .cx-doc-h h4 { margin: 2px 0 0; font-size: 1.05rem; font-weight: 800; color: var(--navy); }
.cx-ui .cx-doc-h .cx-b { margin-left: auto; }

.cx-ui .cx-doc-s { padding: 18px var(--gutter); border-bottom: 1px solid var(--hair); }
.cx-ui .cx-doc-s:last-of-type { border-bottom: 0; }
.cx-ui .cx-doc-s > h5 {
    margin: 0 0 13px; font-size: .64rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .08em; color: var(--muted);
}
.cx-ui .cx-doc-s > h5 .lib { font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--faint); }
.cx-ui .cx-doc-s .cx-risk { margin: 0 0 13px; }
.cx-ui .cx-doc-acts { margin-top: 10px; }

.cx-ui .cx-doc-f {
    padding: 13px var(--gutter); background: #f7f9fc; border-top: 1px solid var(--hair);
    display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap;
}
.cx-ui .cx-doc-f .nota { margin-right: auto; font-size: .72rem; font-weight: 600; color: var(--faint); }

/* ── La tabla de renglones ───────────────────────────────────────────────────
   Es una tabla EDITABLE: cada celda tiene un control adentro. El padding de la
   celda baja porque el control ya trae el suyo — si no, cada fila mediría 50 px
   y cuatro renglones ocuparían la pantalla entera.

   `overflow: visible` en el contenedor: un `<select>` abierto adentro de un
   `overflow: auto` se recorta contra el borde, y el z-index no salva de un
   recorte (memoria `feedback_zindex_no_salva_del_recorte`). El scroll
   horizontal lo sigue dando la tabla si hace falta, por el ancho mínimo de sus
   columnas. */
.cx-ui table.cx-ren { border-top: 1px solid var(--hair); }
.cx-ui table.cx-ren td { padding: 6px 8px; }
.cx-ui table.cx-ren td:first-child { padding-left: 0; border-left: 0; }
.cx-ui table.cx-ren th:first-child { padding-left: 0; }
.cx-ui table.cx-ren td:last-child, .cx-ui table.cx-ren th:last-child { padding-right: 0; }
.cx-ui table.cx-ren tbody tr:nth-child(even) { background: transparent; }
.cx-ui table.cx-ren tbody tr:hover { background: transparent; }
.cx-ui table.cx-ren td[data-c="fob"] { font-weight: 700; color: var(--ink); }

/* ── El pie de totales ───────────────────────────────────────────────────────
   TRES cifras y no una. Una carpeta de varios renglones no tiene «un precio»:
   tiene kilos, tiene un valor FOB y tiene un cociente entre los dos. Mostrar
   sólo el último, o llamarlo «precio», es la cifra con todo adentro que esconde
   de qué está hecha (memoria `feedback_una_cifra_con_todo_adentro_esconde_el_costo`).

   Y sin números gigantes: 1.34rem, el mismo cuerpo que las tarjetas del Panel
   y que el ABM. La jerarquía la hacen el peso, el espacio y el color. */
.cx-ui .cx-tot {
    display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px;
    padding-top: 14px; border-top: 1px solid var(--hair);
}
.cx-ui .cx-tot .t {
    flex: 1; min-width: 168px;
    display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start;
    background: var(--canvas); border-radius: 10px; padding: 9px 12px;
    border-left: 3px solid var(--hair-strong);
}
.cx-ui .cx-tot .t .k {
    font-size: .56rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .1em; color: var(--faint);
}
.cx-ui .cx-tot .t .v {
    font-size: 1.34rem; font-weight: 800; line-height: 1.2; margin-top: 2px;
    font-variant-numeric: tabular-nums; color: var(--ink);
}
.cx-ui .cx-tot .t .d { font-size: .67rem; font-weight: 600; color: var(--faint); line-height: 1.4; }

/* =============================================================================
   EL EXPEDIENTE (etapa 3: la cabecera, los KPI y la línea de tiempo)
   =============================================================================
   Portado del mockup (bloque «expediente» de la lámina f021055a): cabecera con
   KPI, línea de tiempo con un punto por hito, y adentro del hito de imputación
   el medidor de cobertura y la tabla de facturas.

   El movimiento NO se inventa: es el mismo de abm-ui.css §MOVIMIENTO — .14s en
   color, .18s var(--curva) en transform, nada se corre más de 2 px y `:active`
   vuelve a cero. Lo único que se agrega es el giro del chevron del `<details>`,
   que es el mismo .18s var(--curva). */
.cx-ui .cx-doc-h .cx-chapas { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }
.cx-ui .cx-doc-h .cx-chapas .cx-b { margin-left: 0; }
.cx-ui .cx-sub {
    padding: 10px var(--gutter); border-bottom: 1px solid var(--hair);
    font-size: .74rem; font-weight: 600; color: var(--faint);
}

/* ── Los KPI del expediente ──────────────────────────────────────────────────
   Separados por un filete y no por tarjetas: son cinco caras del MISMO
   documento, y cinco cajas con sombra las convertirían en cinco cosas.
   Sin números gigantes (1.02rem): la jerarquía la hacen el peso y el color. */
.cx-ui .cx-kpis {
    display: flex; flex-wrap: wrap; gap: 0;
    padding: 13px var(--gutter); border-bottom: 1px solid var(--hair);
}
.cx-ui .cx-kpi { flex: 1; min-width: 132px; padding: 0 14px; border-left: 3px solid var(--hair); }
.cx-ui .cx-kpi:first-child { padding-left: 0; border-left: 0; }
.cx-ui .cx-kpi .k {
    display: block; font-size: .56rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .1em; color: var(--faint);
}
.cx-ui .cx-kpi .v {
    display: block; font-size: 1.02rem; font-weight: 800; line-height: 1.3;
    font-variant-numeric: tabular-nums; color: var(--ink);
}
.cx-ui .cx-kpi .d { display: block; font-size: .66rem; font-weight: 600; color: var(--faint); line-height: 1.4; }
.cx-ui .cx-kpi.ok  { border-left-color: var(--ok-hair); }
.cx-ui .cx-kpi.ok  .v { color: var(--ok); }
.cx-ui .cx-kpi.wrn { border-left-color: var(--warn); }
.cx-ui .cx-kpi.wrn .v { color: var(--warn); }

/* ── La línea de tiempo ──────────────────────────────────────────────────────
   El riel vertical y un punto por hito. El punto lleva el estado: verde lo
   alcanzado, ámbar hueco lo que está en juego, gris lo que todavía no llegó.
   El color es del ESTADO y nunca del frente. */
.cx-ui .cx-tl { position: relative; padding: 14px var(--gutter) 18px calc(var(--gutter) + 20px); }
.cx-ui .cx-tl::before {
    content: ''; position: absolute; left: calc(var(--gutter) + 6px); top: 26px; bottom: 30px;
    width: 2px; background: var(--hair-strong);
}
.cx-ui .cx-hito { position: relative; margin-bottom: 8px; }
.cx-ui .cx-hito:last-child { margin-bottom: 0; }
.cx-ui .cx-hito::before {
    content: ''; position: absolute; left: -19px; top: 13px; width: 11px; height: 11px;
    border-radius: 50%; background: var(--surface); border: 2.5px solid var(--hair-strong); z-index: 1;
}
.cx-ui .cx-hito.done::before  { border-color: var(--ok); background: var(--ok); }
.cx-ui .cx-hito.curr::before  { border-color: var(--warn); background: var(--surface); }
.cx-ui .cx-hito.alert::before { border-color: var(--crit); background: var(--crit); }

.cx-ui .cx-hito details {
    background: var(--surface); border-radius: 11px; border: 1px solid rgba(16, 32, 64, .05);
    box-shadow: var(--e1); overflow: hidden; transition: box-shadow .18s var(--curva);
}
.cx-ui .cx-hito details[open] { box-shadow: var(--e2); }
.cx-ui .cx-hito summary {
    list-style: none; display: flex; align-items: center; gap: 9px; padding: 9px 13px;
    cursor: pointer; transition: background .14s var(--curva);
}
.cx-ui .cx-hito summary::-webkit-details-marker { display: none; }
.cx-ui .cx-hito summary:hover { background: #fafbfd; }
.cx-ui .cx-hito summary b { font-size: .8rem; font-weight: 800; color: var(--ink); }
.cx-ui .cx-hito summary .fecha { font-size: .7rem; font-weight: 600; color: var(--faint); }
.cx-ui .cx-hito summary .cx-b { margin-left: auto; }
.cx-ui .cx-hito summary .care { color: var(--faint); transition: transform .18s var(--curva); }
.cx-ui .cx-hito details[open] summary .care { transform: rotate(180deg); }
.cx-ui .cx-hito .cuerpo { padding: 4px 13px 13px; border-top: 1px solid var(--hair); font-size: .78rem; }
.cx-ui .cx-hito-acts { display: flex; gap: 8px; margin-top: 11px; flex-wrap: wrap; }

.cx-ui .cx-fila { display: flex; gap: 10px; padding: 6px 0; border-bottom: 1px dashed var(--hair); }
.cx-ui .cx-fila:last-child { border-bottom: 0; }
.cx-ui .cx-fila .et {
    flex: 0 0 118px; font-size: .62rem; text-transform: uppercase; letter-spacing: .07em;
    font-weight: 800; color: var(--faint); padding-top: 2px;
}
.cx-ui .cx-fila b { font-weight: 700; }

/* ── El medidor de cobertura ─────────────────────────────────────────────────
   UN medidor contra el `kgTotal` de la carpeta, no uno por renglón: la
   cobertura es sobre el total (runbook §1.2, cerrado por Hernán el 04/08/2026).

   La barra pinta VERDE sólo cuando cerró exacta. Una barra verde al 73 % diría
   «vas bien» sobre una carpeta cuyo recupero está bloqueado. */
.cx-ui .cx-cov { margin: 9px 0 4px; }
.cx-ui .cx-cov .head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.cx-ui .cx-cov .big { font-size: 1rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.cx-ui .cx-cov .big.ok  { color: var(--ok); }
.cx-ui .cx-cov .big.wrn { color: var(--warn); }
.cx-ui .cx-cov .x { font-size: .7rem; font-weight: 600; color: var(--faint); }
.cx-ui .cx-cov .track {
    position: relative; height: 8px; border-radius: 99px; background: var(--canvas);
    border: 1px solid var(--hair); margin-top: 6px; overflow: hidden;
}
.cx-ui .cx-cov .fill {
    position: absolute; inset: 0 auto 0 0; border-radius: 99px; background: var(--ok);
    transition: width .18s var(--curva);
}
.cx-ui .cx-cov .fill.wrn { background: var(--warn); }
.cx-ui .cx-cov .scale {
    display: flex; justify-content: space-between; font-size: .64rem; font-weight: 600;
    color: var(--faint); margin-top: 3px;
}

/* ── La tabla de facturas imputadas ──────────────────────────────────────────
   Vive ADENTRO de un hito, así que no es `table.cx-g`: no lleva el gutter de la
   página ni el rayado alterno, que acá pelearían con el fondo de la tarjeta. */
.cx-ui table.cx-mini { width: 100%; border-collapse: collapse; margin: 8px 0 2px; font-size: .76rem; }
.cx-ui table.cx-mini th {
    text-align: left; font-size: .56rem; text-transform: uppercase; letter-spacing: .08em;
    color: var(--muted); font-weight: 800; padding: 5px 8px;
    border-bottom: 2px solid var(--ink); white-space: nowrap;
}
.cx-ui table.cx-mini td { padding: 6px 8px; border-bottom: 1px solid var(--hair); white-space: nowrap; }
.cx-ui table.cx-mini th.n, .cx-ui table.cx-mini td.n { text-align: right; }
.cx-ui table.cx-mini th.c, .cx-ui table.cx-mini td.c { text-align: center; }
/* La celda que SÍ parte el renglón. `table.cx-mini td` es `nowrap` porque casi
   todo lo que lleva son números y comprobantes, que partidos no se leen; pero
   un camión con dos artículos y cuatro lotes en una sola línea empuja la tabla
   a un scroll horizontal de dos pantallas. Mismo `.w` que `table.cx-g`, misma
   razón, escrito por segunda vez porque las dos tablas no comparten regla. */
.cx-ui table.cx-mini th.w, .cx-ui table.cx-mini td.w { white-space: normal; min-width: 150px; }
.cx-ui table.cx-mini tfoot td { font-weight: 800; border-bottom: 0; border-top: 2px solid var(--hair-strong); }
.cx-ui table.cx-mini tbody tr { transition: background .14s var(--curva); }
.cx-ui table.cx-mini tbody tr:hover { background: var(--navy-050); }

/* =============================================================================
   EL SELECTOR DE FACTURAS (adentro del modal)
   =============================================================================
   Una fila por factura, con el checkbox a la izquierda y las cifras a la
   derecha. Las que NO se pueden elegir se muestran igual, apagadas y diciendo
   por qué: una factura que desaparece de la lista se busca veinte minutos antes
   de que a alguien se le ocurra que ya está imputada en otra carpeta. */
.cx-ui .cx-pick {
    display: flex; align-items: center; gap: 11px; padding: 9px 11px;
    border: 1px solid var(--hair-strong); border-radius: 9px; margin-bottom: 8px;
    cursor: pointer; background: var(--surface);
    transition: border-color .14s var(--curva), background .14s var(--curva);
}
.cx-ui .cx-pick:hover { border-color: var(--navy-500); background: var(--navy-050); }
.cx-ui .cx-pick.on { border-color: var(--navy-500); background: var(--navy-050); box-shadow: inset 3px 0 0 var(--navy-500); }
.cx-ui .cx-pick input { width: 16px; height: 16px; accent-color: var(--navy); flex: 0 0 auto; cursor: pointer; }
/* HIJO DIRECTO, y esto no es prolijidad: `.cx-pick .d b` también matchea el
   <b> que va ADENTRO de la explicación, y un `display:block` ahí parte la frase
   en tres renglones con la palabra resaltada sola en el medio
   (memoria `feedback_flex_rompe_la_frase`, misma clase de error). */
.cx-ui .cx-pick .d { min-width: 0; flex: 1; }
.cx-ui .cx-pick .d > b { display: block; font-size: .78rem; font-weight: 700; color: var(--ink); }
.cx-ui .cx-pick .d small { display: block; font-size: .69rem; font-weight: 600; color: var(--faint); }
.cx-ui .cx-pick .d small.por { margin-top: 3px; color: var(--muted); white-space: normal; line-height: 1.45; }
.cx-ui .cx-pick .d small b { font-weight: 700; color: var(--muted); }
.cx-ui .cx-pick .q { flex: 0 0 auto; text-align: right; }
.cx-ui .cx-pick .q > b { display: block; font-size: .78rem; font-weight: 700; color: var(--ink); }
.cx-ui .cx-pick .q small { font-size: .67rem; font-weight: 600; color: var(--faint); }
/* EL SELECTOR DE LOTES ES EL MISMO `.cx-pick`, pero su columna derecha no MUESTRA
   una cifra: la PIDE. Un ancho fijo y no `auto`, y no es capricho — con `auto` la
   caja mide lo que mide su contenido, así que el campo se ensancha al tipear y
   toda la fila se mueve mientras alguien escribe los kilos. Ocho lotes haciendo
   eso a la vez es una lista que tiembla.
   El `click` del campo no puede burbujear al `<label>`: si lo hiciera, tocar el
   número destildaría el lote que se está por cargar. */
.cx-ui .cx-pick .q .cx-in { width: 108px; padding: 5px 8px; font-size: .78rem; }
.cx-ui .cx-pick .q .cx-in:disabled { background: #f5f7fa; }

.cx-ui .cx-pick.off {
    cursor: default; background: var(--canvas); border-style: dashed; border-color: var(--hair-strong);
    align-items: flex-start;
}
.cx-ui .cx-pick.off:hover { border-color: var(--hair-strong); background: var(--canvas); }
.cx-ui .cx-pick.off .material-symbols-outlined { color: var(--faint); flex: 0 0 auto; margin-top: 2px; }
.cx-ui .cx-pick.off .d b, .cx-ui .cx-pick.off .q b { color: var(--muted); }

.cx-ui .cx-sep {
    margin: 16px 0 9px; font-size: .6rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .09em; color: var(--faint);
    border-top: 1px solid var(--hair); padding-top: 11px;
}
.cx-ui .cx-nota { margin-top: 14px; font-size: .69rem; font-weight: 600; color: var(--faint); line-height: 1.55; }

/* ── El resumen vivo de la selección ─────────────────────────────────────────
   Es donde se ve la regla funcionando: dice cuánto se eligió, cómo quedaría la
   cobertura y —cuando el botón está apagado— por qué. Un botón apagado sin
   motivo al lado se lee como una pantalla rota; con el motivo, se lee como una
   regla. */
.cx-ui .cx-sum {
    border-radius: 10px; padding: 11px 13px; margin: 0 0 13px;
    border: 1px solid var(--hair-strong); border-left: 3px solid var(--hair-strong);
    background: var(--canvas);
}
.cx-ui .cx-sum.ok  { border-left-color: var(--ok);   border-color: var(--ok-hair);   background: var(--ok-050); }
.cx-ui .cx-sum.wrn { border-left-color: var(--warn); border-color: var(--warn-hair); background: var(--warn-050); }
.cx-ui .cx-sum .l { display: flex; align-items: baseline; gap: 10px; }
.cx-ui .cx-sum .l .k {
    flex: 0 0 auto; font-size: .58rem; font-weight: 800; text-transform: uppercase;
    letter-spacing: .09em; color: var(--faint);
}
.cx-ui .cx-sum .l .v { margin-left: auto; font-size: .84rem; font-weight: 800; color: var(--ink); }
.cx-ui .cx-sum .m { margin-top: 7px; font-size: .72rem; font-weight: 600; color: var(--muted); line-height: 1.5; }
.cx-ui .cx-sum.ok  .m { color: var(--ok); font-weight: 700; }
.cx-ui .cx-sum.wrn .m { color: var(--warn); font-weight: 700; }

/* =============================================================================
   EL LEGAJO — el clip de adjuntos (etapa 4d)
   =============================================================================
   Vive ADENTRO del cuerpo de un hito y adentro del bloque «Otra documentación»,
   y en los dos lados tiene que leerse como algo que CUELGA de lo de arriba y no
   como una tarjeta más. De ahí el borde punteado y el fondo del lienzo: es la
   misma gramática que .cx-pick.off usa para lo que no es una acción principal.

   El clip NO usa color de estado. Un legajo sin el permiso escaneado no es un
   error —el papel puede estar en la carpeta física— así que pintarlo de warn
   sería inventar una alarma que nadie puede apagar. El único amarillo que
   aparece es el de «hay dos y debería haber uno», que sí es algo raro. */
.cx-ui .cx-clip {
    margin-top: 11px; padding: 9px 11px 4px;
    border: 1px dashed var(--hair-strong); border-radius: 10px; background: var(--canvas);
}
.cx-ui .cx-clip.suelto { margin-top: 0; margin-bottom: 11px; background: var(--surface); }
.cx-ui .cx-clip .h { display: flex; align-items: center; gap: 8px; }
.cx-ui .cx-clip .h > .material-symbols-outlined { color: var(--faint); flex: 0 0 auto; }
.cx-ui .cx-clip .h b { font-size: .74rem; font-weight: 800; color: var(--ink); }
.cx-ui .cx-clip .h .n {
    font-size: .63rem; font-weight: 700; color: var(--faint);
    text-transform: uppercase; letter-spacing: .06em;
}
.cx-ui .cx-clip .h .cx-btn { margin-left: auto; flex: 0 0 auto; }
.cx-ui .cx-clip .vacio { margin: 5px 0 6px; font-size: .7rem; font-weight: 600; color: var(--faint); line-height: 1.5; }
.cx-ui .cx-clip .aviso {
    margin: 7px 0 3px; padding: 6px 9px; border-radius: 7px;
    background: var(--warn-050); border: 1px solid var(--warn-hair);
    font-size: .7rem; font-weight: 600; color: var(--warn); line-height: 1.5;
}

/* Una ficha por archivo. El nombre es un link de verdad —se abre en otra
   pestaña— porque el gesto que la persona hace noventa veces de cada cien es
   ABRIR el papel, no borrarlo. */
.cx-ui .cx-clip .fs { margin: 6px 0 4px; }
.cx-ui .cx-clip .f {
    display: flex; align-items: center; gap: 9px; padding: 6px 0;
    border-top: 1px dashed var(--hair);
}
.cx-ui .cx-clip .f:first-child { border-top: 0; }
.cx-ui .cx-clip .f > .material-symbols-outlined { color: var(--faint); flex: 0 0 auto; }
.cx-ui .cx-clip .f .d { min-width: 0; flex: 1; }
.cx-ui .cx-clip .f .d a {
    display: block; font-size: .75rem; font-weight: 700; color: var(--navy);
    text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cx-ui .cx-clip .f .d a:hover { text-decoration: underline; }
.cx-ui .cx-clip .f .d small {
    display: block; margin-top: 1px; font-size: .66rem; font-weight: 600; color: var(--faint);
}
.cx-ui .cx-clip .f .cx-x { flex: 0 0 auto; }

/* =============================================================================
   LA LISTA DE EMPAQUE — el bloque de un renglón adentro del diálogo (etapa 4e)
   =============================================================================
   Un bloque por renglón del embarque, y adentro de cada uno lo único que esta
   pantalla pregunta: la descripción, los bultos y el bruto.

   EL PESO NETO ESTÁ DIBUJADO COMO DATO Y NO COMO CAMPO, y eso es la mitad del
   diseño: no se tipea porque es el del embarque —el mismo que las facturas de
   compra cubren exacto— y un `<input disabled>` con el número adentro invitaría
   a intentar cambiarlo todas las veces. Va arriba, en la cabecera del bloque,
   con la tipografía de un dato.

   El bloque NO usa color de estado. Lo único que se pinta es el diferencial de
   embalaje: verde cuando cierra, rojo cuando el bruto quedó por debajo del neto
   —que no es una alarma del sistema sino un dígito de menos al tipear. */
.cx-ui .cx-plr {
    margin-bottom: 13px; padding: 11px 13px 12px;
    border: 1px solid var(--hair-strong); border-radius: 11px; background: var(--canvas);
}
.cx-ui .cx-plr:last-of-type { margin-bottom: 4px; }
.cx-ui .cx-plr .cab {
    display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
    padding-bottom: 9px; margin-bottom: 10px; border-bottom: 1px dashed var(--hair-strong);
}
.cx-ui .cx-plr .cab > b { font-size: .8rem; font-weight: 800; color: var(--ink); }
.cx-ui .cx-plr .cab .fmt { font-size: .69rem; font-weight: 600; color: var(--faint); }
/* El neto a la derecha: es el ancla del bloque y el número contra el que se lee
   todo lo demás. Sin números gigantes (runbook §3) — la jerarquía la hace el
   peso, no el cuerpo. */
.cx-ui .cx-plr .cab .neto {
    margin-left: auto; font-size: .69rem; font-weight: 700; color: var(--faint);
    text-transform: uppercase; letter-spacing: .06em;
}
.cx-ui .cx-plr .cab .neto b {
    margin-left: 5px; font-size: .84rem; font-weight: 800; color: var(--ink);
    text-transform: none; letter-spacing: 0; font-variant-numeric: tabular-nums;
}
.cx-ui .cx-plr textarea.cx-in { resize: vertical; min-height: 46px; line-height: 1.5; }

/* El diferencial vivo, debajo del bruto. Es el número por el que existe esta
   hoja, así que se dice mientras se tipea y no al guardar. */
.cx-ui .cx-ayuda.dif { min-height: 2.2em; }
.cx-ui .cx-ayuda.dif.ok  { color: var(--ok);   font-weight: 700; }
.cx-ui .cx-ayuda.dif.neg { color: var(--crit); font-weight: 700; }

/* ── El ayudante, plegado ────────────────────────────────────────────────────
   Es el «estimado si es posible» de Hernán: PROPONE, no decide. Va cerrado
   porque el que ya tiene el remito de balanza en la mano no lo necesita, y
   abrirlo de entrada le pondría tres campos más en la cara para escribir un
   número que ya sabe.

   No es un `.cx-hito details`: aquél es una tarjeta con sombra y éste es un
   renglón que se despliega adentro de un bloque. Misma curva y mismo giro del
   chevron, que es lo que hace que se lean como la misma casa (§MOVIMIENTO). */
.cx-ui details.cx-ayud { margin-top: 11px; border-top: 1px dashed var(--hair-strong); }
.cx-ui details.cx-ayud > summary {
    list-style: none; display: flex; align-items: center; gap: 7px; cursor: pointer;
    padding: 8px 0 2px; font-size: .7rem; font-weight: 700; color: var(--navy);
    transition: color .14s var(--curva);
}
.cx-ui details.cx-ayud > summary::-webkit-details-marker { display: none; }
.cx-ui details.cx-ayud > summary:hover { color: var(--navy-700); }
.cx-ui details.cx-ayud > summary .material-symbols-outlined { font-size: 17px; color: var(--faint); }
.cx-ui details.cx-ayud > .cuerpo { padding: 6px 0 2px; }
.cx-ui details.cx-ayud .res {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 11px;
    font-size: .75rem; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums;
}
.cx-ui details.cx-ayud .res .cx-btn { margin-left: auto; }
.cx-ui details.cx-ayud .res .cx-btn:disabled { opacity: .45; cursor: default; }
.cx-ui details.cx-ayud .por {
    margin: 9px 0 0; font-size: .67rem; font-weight: 600; color: var(--faint); line-height: 1.55;
}
.cx-ui details.cx-ayud .por b { font-weight: 700; color: var(--muted); }

/* =============================================================================
   LOS TRES CAJONES DEL INGRESO DE DIVISAS (etapa 5)
   =============================================================================
   Ganó la B de la mini-ronda del 12/08/2026: aplicaciones del BCRA, cobros
   (que son sólo señal) y reclamos, cada uno en su cajón. La separación no es
   decorativa — es la regla §1.4 hecha estructura: una señal no puede mover el
   medidor porque ni siquiera vive en la misma lista.

   El cajón se parece al `.cx-clip` del legajo y NO es el mismo: el clip cuelga
   con borde punteado porque es un anexo, y esto es contenido del hito. Borde
   entero, fondo de superficie, y el título con su rótulo chico al lado diciendo
   qué hace cada lista («lo único que mueve el medidor», «no cumplen nada»).

   TAMPOCO USA COLOR DE ESTADO. El color del ingreso ya está en la chapa del hito
   y en el medidor; pintar además los tres cajones sería decir tres veces lo
   mismo con tres tonos distintos. El único amarillo es el `.aviso` de «hay cobro
   y el BCRA todavía no aplicó», que es el pendiente concreto. */
.cx-ui .cx-caja {
    margin-top: 11px; padding: 9px 11px 8px;
    border: 1px solid var(--hair-strong); border-radius: 10px; background: var(--surface);
}
.cx-ui .cx-caja .h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cx-ui .cx-caja .h > .material-symbols-outlined { color: var(--faint); flex: 0 0 auto; font-size: 18px; }
.cx-ui .cx-caja .h b { font-size: .74rem; font-weight: 800; color: var(--ink); }
.cx-ui .cx-caja .h .n {
    font-size: .63rem; font-weight: 700; color: var(--faint);
    text-transform: uppercase; letter-spacing: .06em;
}
.cx-ui .cx-caja .h .cx-btn { margin-left: auto; flex: 0 0 auto; }
.cx-ui .cx-caja .c { margin-top: 4px; }
.cx-ui .cx-caja .vacio {
    margin: 4px 0 2px; font-size: .7rem; font-weight: 600; color: var(--faint); line-height: 1.55;
}
.cx-ui .cx-caja .aviso {
    margin: 8px 0 2px; padding: 6px 9px; border-radius: 7px;
    background: var(--warn-050); border: 1px solid var(--warn-hair);
    font-size: .7rem; font-weight: 600; color: var(--warn); line-height: 1.5;
}

/* UN RECLAMO — con su seguimiento adentro, que es lo que la propuesta B compró.
   El filete a la izquierda lo ata visualmente a lo que cuelga de él; cerrado,
   baja a hairline y el bloque se apaga: la historia queda, el pendiente no. */
.cx-ui .cx-caja .cx-rec {
    margin: 7px 0 0; padding: 7px 0 7px 11px;
    border-left: 3px solid var(--warn); background: transparent;
}
.cx-ui .cx-caja .cx-rec + .cx-rec { border-top: 1px dashed var(--hair); margin-top: 9px; }
.cx-ui .cx-caja .cx-rec.cerrado { border-left-color: var(--hair-strong); opacity: .72; }
.cx-ui .cx-caja .cx-rec .t { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cx-ui .cx-caja .cx-rec .t b { font-size: .75rem; font-variant-numeric: tabular-nums; }
.cx-ui .cx-caja .cx-rec .t .q { font-size: .66rem; font-weight: 600; color: var(--faint); }
.cx-ui .cx-caja .cx-rec .nota {
    margin: 3px 0 0; font-size: .75rem; font-weight: 600; color: var(--ink); line-height: 1.5;
}
/* El seguimiento va sin cabecera: tres columnas de fecha, qué pasó y quién no
   necesitan que se las nombre, y un <thead> acá partiría la lectura del
   reclamo en dos tablas. */
.cx-ui .cx-caja .cx-rec .cx-mini.seg { margin-top: 5px; }
.cx-ui .cx-caja .cx-rec .cx-mini.seg td { font-size: .72rem; }
.cx-ui .cx-caja .cx-rec .cx-hito-acts { margin-top: 7px; }
