/* ============================================================================
   AFB COSTOS — hoja de estilo
   ----------------------------------------------------------------------------
   Layout de tres zonas: barra fija arriba, lista a la izquierda, detalle a la
   derecha. En pantallas chicas la lista y el detalle se apilan.

   Tema claro y oscuro: el sistema decide por omisión y el botón de la barra lo
   fuerza escribiendo data-tema en <html>, que gana sobre la media query.
   ========================================================================== */

:root {
  --fondo: #f6f7f9;
  --superficie: #ffffff;
  --superficie-2: #f0f2f5;
  --borde: #dfe3e8;
  --texto: #16202c;
  --texto-2: #5b6b7c;
  /* Azul acero: el mismo azul, con la saturación bajada. Un primario muy
     saturado compite con los colores de estado; bajándolo, el verde de
     «cerrado» y el ámbar de «en proceso» se leen sin pelear con él. */
  --acento: #2563a5;
  --acento-vivo: #1f5490;      /* hover y pulsado */
  --acento-suave: #e8f0f8;
  /* ── Dorado de títulos ──
     El acento caliente de la identidad. Los títulos van aquí y los subtítulos en
     el azul: dos jerarquías que se distinguen por color y no sólo por tamaño.

     Está ELEGIDO CONTRA `--alerta`, no junto a ella. El ámbar de estado también
     se usa como texto —el semáforo «medio», los avisos de base dudosa— así que un
     dorado del mismo tono le quitaría fuerza justo al color que existe para que
     algo se mire. Medido: este dorado va en tono 41° y la alerta en 26°, y en
     oscuro la separación la carga la SATURACIÓN (58% contra 96%), que es lo que
     hace que uno se lea como latón y el otro como alarma.

     Contraste sobre los tres fondos claros: 5.27 · 4.92 · 4.70. */
  --dorado: #8c6510;
  --ok: #0f7b4f;
  --alerta: #b45309;
  --error: #b91c1c;
  /* Fondos tenues de estado: el color plano sobre una fila entera compite con
     el texto. Se usan como relleno de pastilla y como realce de fila. */
  --ok-suave: #e6f4ec;
  --alerta-suave: #fdf1e3;
  --sombra: 0 1px 2px rgba(16, 32, 44, .06), 0 4px 12px rgba(16, 32, 44, .06);
  --r: 10px;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
  /* La cinta creció al pasar sus botones a dos renglones, y esa altura se paga
     apretando la barra: el área de trabajo no pierde un pixel y la cinta gana
     no tener que desplazarse. 56+58 = 114 antes, 48+68 = 116 ahora. */
  --barra-alto: 48px;
  --cinta-alto: 68px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-tema="claro"]) {
    --fondo: #0d1219;
    --superficie: #151d27;
    --superficie-2: #1c2734;
    --borde: #27343f;
    --texto: #e7edf3;
    --texto-2: #94a5b8;
    /* En oscuro el acero se aclara para conservar contraste sobre el fondo. */
    --acento: #7fb0e0;
    --acento-vivo: #9cc4ea;
    --acento-suave: #17293a;
    /* Latón, no amarillo: 36° y 58% de saturación contra los 43° y 96% de
       `--alerta`. Contraste 7.19 · 7.96 · 6.40 sobre los fondos oscuros. */
    --dorado: #d2a054;
    --ok: #4ade80;
    --alerta: #fbbf24;
    --error: #f87171;
    --ok-suave: #14291d;
    --alerta-suave: #2b2314;
    --sombra: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 14px rgba(0, 0, 0, .3);
  }
}

:root[data-tema="oscuro"] {
  --fondo: #0d1219;
  --superficie: #151d27;
  --superficie-2: #1c2734;
  --borde: #27343f;
  --texto: #e7edf3;
  --texto-2: #94a5b8;
  --acento: #7fb0e0;
  --acento-vivo: #9cc4ea;
  --acento-suave: #17293a;
  --dorado: #d2a054;
  --ok: #4ade80;
  --alerta: #fbbf24;
  --error: #f87171;
  --ok-suave: #14291d;
  --alerta-suave: #2b2314;
  --sombra: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 14px rgba(0, 0, 0, .3);
}

* { box-sizing: border-box; }

/* ── Foco de teclado ──
   Una regla para todo lo pulsable, en lugar de recordarlo control por control.
   `:focus-visible` y no `:focus`: el anillo aparece al navegar con teclado y
   no al hacer clic, que es cuando estorba. Los campos de texto traen su propio
   tratamiento (borde en acento) y quedan fuera. */
button:focus-visible,
select:focus-visible,
[tabindex]:focus-visible,
.rama:focus-visible,
.item-rep:focus-visible,
.lista li:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 2px;
  border-radius: 6px;
}

html, body {
  margin: 0; height: 100%;
  background: var(--fondo); color: var(--texto);
  font: 15px/1.45 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

/* ── Barra superior ── */
.barra {
  position: sticky; top: 0; z-index: 40;
  height: var(--barra-alto);
  display: flex; align-items: center; gap: 18px;
  padding: 0 16px;
  background: var(--superficie);
  border-bottom: 1px solid var(--borde);
}

.marca { display: flex; align-items: center; gap: 8px; font-weight: 700; letter-spacing: .02em; }
/* El logo va antes del nombre, ajustado al alto de la barra. `object-fit` para
   que un logo de otra proporción no se deforme al sustituirlo. */
.logo-marca { height: 26px; width: auto; max-width: 40px; object-fit: contain; display: block; }
.logo-carga { display: block; margin: 0 auto 10px; height: auto; }
/* Los dos logos nacen `hidden` en el HTML y `montarLogo` los descubre al
   ponerles el `src`, «para que no quede un hueco de imagen rota si algo falla»
   —lo dice su propio comentario—. Sin estas dos reglas esa intención no se
   cumplía: el `display: block` de arriba gana sobre el `display: none` que el
   atributo `hidden` trae del navegador, y el hueco salía igual. */
.logo-marca[hidden], .logo-carga[hidden] { display: none; }
.titulo { font-size: 14px; color: var(--texto-2); letter-spacing: .1em; }
/* Discreta a propósito: sirve para saber qué versión se está usando al
   reportar algo, no para llamar la atención. */
.version {
  font-family: var(--mono); font-size: 10px; color: var(--texto-2);
  opacity: .55; letter-spacing: 0; font-weight: 400; align-self: center;
}

/* ── Qué base está montada ──
   Deliberadamente MÁS visible que la versión: la versión es para reportar un
   problema, y esto es para no cometerlo. Se lee de un golpe y se pulsa para
   cambiar de base, así que tiene cara de botón aunque viva en la marca.

   Se corta con puntos suspensivos en vez de empujar el marcador: los nombres
   de base son largos —«CONSTRUBASE Desarrollador julio 2026»— y el título
   completo queda en el `title`. */
.cintillo-base {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 260px; margin-left: 4px; padding: 3px 9px;
  font: inherit; font-size: 11.5px; font-weight: 600; letter-spacing: 0;
  color: var(--texto); background: var(--superficie-2);
  border: 1px solid var(--borde); border-radius: 999px;
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Igual que los logos: nace `hidden` y no se descubre hasta que hay una base
   que nombrar. Sin esta regla se veía una pastilla VACÍA en la barra durante
   toda la carga — y desde v0.9.8 la carga puede empezar mucho después, porque
   antes hay que elegir en la ventana de inicio. */
.cintillo-base[hidden] { display: none; }
.cintillo-base:hover { border-color: var(--acento); color: var(--acento); }
.cintillo-base .cb-et {
  font-size: 9.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--texto-2); opacity: .7;
}
.cintillo-base .cb-nom { overflow: hidden; text-overflow: ellipsis; }
/* Punto de advertencia cuando la base montada no trae todo lo que la interfaz
   ofrece —FASAR, mano de obra, maquinaria—. Es la misma señal que el aviso de
   arranque, pero permanente: el aviso se va a los 8 segundos. */
.cintillo-base.con-falta { border-color: var(--alerta); background: var(--alerta-suave); }
.cintillo-base.con-falta::after {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--alerta); flex: none;
}

/* Fila de la casilla en los diálogos: la casilla y su texto en la misma línea,
   alineadas por arriba para que un texto de dos renglones no la descuelgue. */
.campo-check {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 10px 0 2px; cursor: pointer; font-size: 13px;
}
.campo-check input { margin-top: 2px; flex: none; }

/* ── Cinta de apartados ──
   La navegación completa, como la de AFBdatos: grupos con nombre general
   (Catálogos · Consultas · Factores) y sus botones. Las pestañas que cambian
   de vista y los botones de documento comparten la misma cara; la activa se
   distingue con el acento. La fila se desplaza y las flechas sólo aparecen
   cuando de verdad hay algo fuera de vista. */
.cinta {
  display: flex; align-items: center; gap: 2px;
  height: var(--cinta-alto); padding: 0 8px;
  border-bottom: 1px solid var(--borde); background: var(--superficie);
}
.cinta-fila {
  display: flex; overflow-x: auto; scroll-behavior: smooth;
  scrollbar-width: none;           /* la barra estorba dentro de la cinta */
  flex: 1; min-width: 0;
}
.cinta-fila::-webkit-scrollbar { display: none; }
/* Cuando hay algo fuera de vista, el último botón se cortaba a media palabra
   —«FASA»— y eso se lee como interfaz rota, no como «hay más a la derecha». El
   degradado del borde dice lo segundo. Se aplica sólo del lado donde de verdad
   queda contenido, aprovechando que el JS ya oculta la flecha que no hace falta. */
.cinta:has(#tab-der:not([hidden])) .cinta-fila {
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 34px), transparent 100%);
}
.cinta:has(#tab-izq:not([hidden])) .cinta-fila {
  mask-image: linear-gradient(to right, transparent 0, #000 34px, #000 100%);
}
.cinta:has(#tab-izq:not([hidden])):has(#tab-der:not([hidden])) .cinta-fila {
  mask-image: linear-gradient(to right, transparent 0, #000 34px,
    #000 calc(100% - 34px), transparent 100%);
}
.cinta-grupo {
  display: flex; flex-direction: column; gap: 2px;
  padding: 5px 10px 3px; border-right: 1px solid var(--borde);
}
.cinta-grupo:last-child { border-right: 0; }

/* ── Los botones de un grupo van en DOS RENGLONES ──
   En una sola fila, los 16 botones de la cinta no caben en pantallas normales:
   había que desplazarla con flechas, y lo que uno busca casi siempre estaba
   fuera de vista. Apilados en dos, cada grupo mide la mitad de ancho y **la
   cinta entera cabe** — sin recortar ni abreviar una sola etiqueta, que era la
   otra salida y la mala.

   Se llena por RENGLONES (`grid-auto-flow: row`), no por columnas: en columnas,
   leer de izquierda a derecha daría 1, 3, 5 — el orden en que nadie lee un menú.
   `data-cols` fija cuántas columnas tiene el grupo; sin él, los grupos chicos
   quedarían de un renglón y la cinta saldría dispareja. */
.cinta-botones {
  display: grid; gap: 2px 3px;
  grid-auto-flow: row;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, max-content));
  align-content: start;
}
.cinta-botones[data-cols="1"] { --cols: 1; }
.cinta-botones[data-cols="2"] { --cols: 2; }
.cinta-botones[data-cols="3"] { --cols: 3; }
/* Cuatro y cinco columnas las pide sólo «Archivo». Tras v0.9.9 lleva diez
   botones: los cinco de importar y exportar, los dos de respaldar y restaurar la
   obra, y los tres de elegir con qué se trabaja. A cuatro columnas se iría a un
   tercer renglón y desnivelaría la cinta entera; la alternativa era abreviar
   etiquetas, y ésa es la mala.

   Y van con `max-content` en vez del `minmax(0, …)` de los demás: a partir de
   cuatro columnas el grupo ya no cabe a lo ancho, y `minmax(0, …)` deja que cada
   columna encoja POR DEBAJO de su texto. Como los botones son `nowrap`, el
   texto no se parte: se monta encima del de al lado, y se leía «Importar
   catálogo de conceptActualizar precios». Sin encogimiento, el grupo mide lo
   que mide y la cinta se desplaza, que es justo para lo que tiene flechas. */
.cinta-botones[data-cols="4"] { --cols: 4; grid-template-columns: repeat(4, max-content); }
.cinta-botones[data-cols="5"] { --cols: 5; grid-template-columns: repeat(5, max-content); }
.cinta-titulo {
  font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--texto-2); text-align: center;
}
.btn-cinta, .cinta .pestana {
  border: 1px solid transparent; background: transparent; color: var(--texto);
  padding: 3px 8px; border-radius: 6px; cursor: pointer; font: inherit;
  font-size: 12px; white-space: nowrap;
  /* A la izquierda: dos renglones de etiquetas centradas se leen como una nube
     de palabras; alineadas arrancan todas en el mismo punto y se barren en
     vertical, que es como se busca en un menú. */
  text-align: left; width: 100%;
}
.btn-cinta:hover, .cinta .pestana:hover { background: var(--superficie-2); border-color: var(--borde); }
/* NIVEL 2 · ACTIVO — qué vista estoy viendo. Sin relleno: el subrayado basta
   y deja el relleno reservado para la selección, que es otra cosa. */
.cinta .pestana.activa {
  color: var(--acento); font-weight: 600; background: transparent;
  border-color: transparent; box-shadow: inset 0 -2px 0 var(--acento);
}
.flecha-tab {
  border: 1px solid var(--borde); background: var(--superficie); color: var(--texto-2);
  width: 24px; height: 28px; border-radius: 6px; cursor: pointer;
  font-size: 16px; line-height: 1; flex: 0 0 auto; padding: 0;
}
.flecha-tab:hover { border-color: var(--acento); color: var(--acento); }
.flecha-tab[hidden] { display: none; }

/* El que cede ancho cuando no cabe todo es el MARCADOR, no los botones: un
   número recortado no se puede leer, pero tampoco sirve de nada — y un botón
   comprimido deja de poder pulsarse. Así que el marcador se encoge y, si llega a
   su mínimo, desaparece; los botones nunca. */
.barra-der { margin-left: auto; display: flex; align-items: center; gap: 8px; min-width: 0; }
.barra-der > .barra-tools { flex: 0 0 auto; }
.barra-der > .marcador { flex: 0 1 auto; min-width: 0; overflow: hidden; }

/* ── Marcador de totales ──
   Obra y partida, cada una con su costo directo y su venta sin IVA. Es una
   cuadrícula de dos por dos y se lee como tal: las etiquetas a la izquierda de
   su número, los números alineados en columna con cifras tabulares para poder
   compararlos de un vistazo. La venta va en negro pleno y el directo atenuado,
   porque el que se cobra es el que manda. */
.marcador { display: flex; align-items: stretch; gap: 5px; }
.mk-col {
  display: flex; flex-direction: column; gap: 0;
  padding: 2px 8px 3px; border: 1px solid var(--borde); border-radius: 8px;
  background: var(--superficie);
}
.mk-tit {
  font-size: 8.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--texto-2); opacity: .8;
}
.mk { display: flex; align-items: baseline; gap: 8px; line-height: 1.15; }
/* «C. TOTAL SIN IVA» es la etiqueta más larga y ella fija el ancho: si cada
   renglón midiera lo suyo, los importes de las dos columnas no alinearían. */
.mk-et {
  font-size: 9px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--texto-2); min-width: 84px; white-space: nowrap;
}
.mk-v {
  font-family: var(--mono); font-size: 11.5px;
  font-variant-numeric: tabular-nums; color: var(--texto-2);
  margin-left: auto;
}
.mk-fuerte { font-weight: 600; font-size: 12px; color: var(--texto); }
@media (max-width: 1240px) { .marcador { display: none; } }

/* ── Herramientas de la barra ──
   Factores es la de uso diario y lleva rótulo; actualizar y depurar son de
   mantenimiento y van como iconos. Las reglas separan los tres oficios para que
   no se lean como una sola fila de seis botones iguales. */
.barra-tools { display: flex; align-items: center; gap: 6px; }
.barra-tools > * { flex: 0 0 auto; }
.tools-sep { width: 1px; align-self: stretch; background: var(--borde); margin: 2px 2px; }

/* ── Mantenimiento del presupuesto, junto al marcador ──
   Actualizar y depurar no cambian ningún porcentaje: sirven al NÚMERO. Por eso
   viven pegados al marcador y no dentro del panel de Factores, donde estaban
   escondidos detrás de un botón que se abre para otra cosa.

   Van más discretos que Factores —sin relleno, borde sólo al pasar el cursor—
   porque son de uso ocasional: Factores es lo que se toca a diario. */
.btn-mant {
  display: inline-flex; align-items: center; gap: 5px;
  border: 1px solid transparent; background: transparent; color: var(--texto-2);
  padding: 5px 8px; border-radius: 8px; cursor: pointer; font: inherit;
  font-size: 12px; white-space: nowrap;
}
.btn-mant:hover { border-color: var(--borde); background: var(--superficie-2); color: var(--texto); }

.btn-factores {
  display: flex; align-items: center; gap: 8px;
  border: 1px solid var(--borde); background: var(--superficie);
  color: var(--texto); padding: 6px 11px; border-radius: 8px;
  cursor: pointer; font: inherit; font-size: 13px;
}
.btn-factores:hover { border-color: var(--acento); }
.chip {
  background: var(--acento-suave); color: var(--acento);
  padding: 1px 7px; border-radius: 20px;
  font-family: var(--mono); font-size: 12px; font-weight: 600;
}
.btn-icono {
  border: 1px solid var(--borde); background: var(--superficie); color: var(--texto);
  width: 34px; height: 34px; border-radius: 8px; cursor: pointer; font-size: 15px;
  /* Sin esto flexbox lo encogía por debajo de su contenido —medido: 32 px de
     caja para 62 px de contenido— y la barra entera empujaba 13 px fuera de la
     ventana, que es de dónde salía la barra de desplazamiento horizontal del
     documento. Un botón de icono no cede ancho: cede el marcador. */
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
}
.btn-icono:hover { border-color: var(--acento); }

/* ── Panel de factores ── */
.panel-factores {
  position: sticky; top: calc(var(--barra-alto) + var(--cinta-alto)); z-index: 35;
  background: var(--superficie); border-bottom: 1px solid var(--borde);
  padding: 14px 16px; box-shadow: var(--sombra);
}
.panel-factores[hidden] { display: none; }
.campos { display: flex; flex-wrap: wrap; gap: 12px; }
.campos label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--texto-2); font-weight: 500;
}
.campos .u { color: var(--acento); font-family: var(--mono); }
.campos input {
  width: 116px; padding: 6px 9px;
  border: 1px solid var(--borde); border-radius: 7px;
  background: var(--fondo); color: var(--texto);
  font: 14px var(--mono);
}
.campos input:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }
.nota { margin: 10px 0 0; font-size: 12.5px; color: var(--texto-2); max-width: 70ch; }

/* ── Iconos ──
   Un solo sprite SVG (js/ui/iconos.js). Heredan `currentColor`, así que el
   estado del botón —hover, deshabilitado, seleccionado— lo lleva el color del
   texto y el icono lo sigue solo, sin variantes de archivo.

   `stroke-width` va aquí y no en el sprite para que un icono grande no salga
   con el trazo engordado: el vector escala, el grosor se mantiene. */
.ico {
  width: 16px; height: 16px; flex: 0 0 auto;
  fill: none; stroke: currentColor;
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
  vertical-align: -.18em; pointer-events: none;
}
.ico-sm { width: 13px; height: 13px; stroke-width: 2; }
.ico-lg { width: 18px; height: 18px; stroke-width: 1.6; }
#sprite-iconos { display: none; }

/* ── Estructura ──
   Se usa position:absolute en las vistas para que sólo la activa participe del
   layout sin recalcular el grid en cada cambio de pestaña. */
main { height: calc(100vh - var(--barra-alto) - var(--cinta-alto)); position: relative; }
.vista {
  display: none; position: absolute; inset: 0;
  /* El ancho del lateral es ajustable: el divisor escribe la variable. */
  grid-template-columns: var(--ancho-lateral, 340px) 6px 1fr;
}
.vista.activa { display: grid; }
.vista:has(.lateral-ancha) { --ancho-lateral: 380px; }
.vista.sin-lateral { grid-template-columns: 0 14px 1fr; }
.vista.sin-lateral .lateral { overflow: hidden; border-right: 0; }

/* ── Divisor de paneles ── */
.divisor {
  cursor: col-resize; background: transparent; position: relative; z-index: 4;
  /* Zona de agarre más ancha que la línea visible: 6px exactos son esquivos. */
  margin: 0 -3px; padding: 0 3px; background-clip: content-box;
}
.divisor:hover, body.arrastrando-panel .divisor { background-color: var(--acento); background-clip: content-box; }
body.arrastrando-panel { cursor: col-resize; user-select: none; }
.vista.sin-lateral .divisor { background-color: var(--superficie-2); background-clip: content-box; }

.btn-panel {
  position: absolute; top: 8px; z-index: 5;
  width: 20px; height: 20px; border-radius: 50%;
  border: 1px solid var(--borde); background: var(--superficie); color: var(--texto-2);
  cursor: pointer; font-size: 11px; line-height: 1; padding: 0;
  display: grid; place-items: center; opacity: .55;
}
.btn-panel:hover { opacity: 1; background: var(--acento); border-color: var(--acento); color: #fff; }
.btn-panel-izq { right: 6px; }
/* El botón del panel derecho se ancla a la vista, no al detalle: el detalle
   tiene scroll y el botón se iría con él. Sigue al divisor, esté donde esté. */
.btn-panel-der { left: calc(var(--ancho-lateral, 340px) + 12px); }
.vista.sin-lateral .btn-panel-der { left: 20px; }
.lateral { position: relative; }

/* ── Selector de árbol Base / Obra ── */
/* ── Selector de catálogos ──
   El Maestro y las obras en la misma fila, porque son lo mismo: catálogos que
   se abren y se editan. La fila se desplaza cuando hay muchas obras. */
.sel-arbol {
  display: flex; padding: 8px 8px 0; gap: 4px;
  border-bottom: 1px solid var(--borde);
  overflow-x: auto; scrollbar-width: none;
}
.sel-arbol::-webkit-scrollbar { display: none; }
.sub {
  display: flex; align-items: center; gap: 5px;
  border: 0; background: transparent; color: var(--texto-2);
  padding: 8px 8px; cursor: pointer; font: inherit; font-weight: 600; font-size: 13px;
  border-bottom: 2px solid transparent; border-radius: 6px 6px 0 0;
  white-space: nowrap; flex: 0 0 auto; max-width: 190px;
}
.sub:hover { background: var(--superficie-2); color: var(--texto); }
.sub.activa { color: var(--acento); border-bottom-color: var(--acento); }
.sub .nom { overflow: hidden; text-overflow: ellipsis; }
/* Encabezado de panel: dice de qué es lo que se está viendo. «Propios» lo usa
   para dejar claro que esos conceptos los armó el usuario y no vienen del
   catálogo — es la diferencia que importa al mirarlos. */
.enc-panel {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; border-bottom: 1px solid var(--borde);
  font-size: 12px;
}

/* La estrella dice cuál es el catálogo ACTIVO: donde se captura y a qué
   apuntan los reportes. Es una forma distinta del subrayado —que dice cuál
   estoy VIENDO— porque son dos cosas independientes: puedo estar viendo el
   Maestro mientras capturo en OBRA_1. */
.estrella {
  border: 0; background: transparent; padding: 0; cursor: pointer;
  color: var(--texto-2); opacity: .45; display: grid; place-items: center;
  flex: 0 0 auto; border-radius: 4px;
}
.estrella:hover { opacity: 1; color: var(--acento); }
.estrella.es-activo { opacity: 1; color: var(--acento); }
.estrella.es-activo .ico { fill: currentColor; }

.panel-arbol { display: none; flex-direction: column; min-height: 0; flex: 1; }
.panel-arbol.activo { display: flex; }
/* El árbol se lleva el sobrante y es lo único que se desplaza; el resto
   —buscador, selector, acciones, conteo, ayuda y pie— conserva su alto. Sin
   esto el panel entero sacaba barra y el pie de acciones quedaba fuera de
   vista justo cuando hacía falta. */
.panel-arbol > *:not(.arbol) { flex: 0 0 auto; }

/* ── Árboles ── */
.arbol { overflow-y: auto; flex: 1; min-height: 0; padding-bottom: 20px; }
.rama {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 10px 5px 0; cursor: pointer;
  border-bottom: 1px solid transparent; font-size: 13px;
}
.rama:hover { background: var(--superficie-2); }
/* NIVEL 1 · SELECCIÓN — sobre qué estoy operando. Barra izquierda y fondo:
   es el único tratamiento que lleva relleno, y sólo hay uno seleccionado. */
.rama.sel { background: var(--acento-suave); box-shadow: inset 3px 0 0 var(--acento); }
.flecha {
  width: 15px; flex: 0 0 15px; text-align: center;
  color: var(--texto-2); font-size: 10px; user-select: none;
}
.rama .wbs {
  font-family: var(--mono); font-size: 11px; color: var(--acento);
  font-weight: 600; flex: 0 0 auto;
}
/* `flex: 1` a secas NO basta: en una fila flex el `min-width` implícito es
   `auto`, así que el texto se niega a bajar de su ancho de contenido y empuja la
   rama entera fuera del panel — medido en Chrome, 26 px de desborde con sólo dos
   raíces, y el árbol salía con barra horizontal desde el primer renglón. Con
   `min-width: 0` el recorte con puntos suspensivos sí ocurre. */
.rama .txt {
  flex: 1 1 0; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rama .der {
  font-family: var(--mono); font-size: 11px; color: var(--texto-2);
  font-variant-numeric: tabular-nums; flex: 0 0 auto;
}
.rama.hoja .txt { color: var(--texto); }
.rama.hoja .wbs { color: var(--texto-2); }
.rama.partida { font-weight: 600; }
.rama-mas {
  padding: 5px 10px; font-size: 12px; color: var(--acento);
  cursor: pointer; font-weight: 600;
}
.rama-mas:hover { background: var(--superficie-2); }

/* ── Acciones dentro de una rama ──
   Ocultas hasta pasar el cursor: con cuatro botones visibles en cada renglón el
   árbol se vuelve ilegible. Se muestran también al enfocar con teclado, que si
   no quedarían inalcanzables sin ratón. */
/* Barra de acciones al pie del árbol. Las de la rama (al pasar el cursor) son
   más rápidas cuando ya sabes dónde vas; ésta es la que se encuentra sola. */
/* Arriba del árbol: el borde va abajo, no arriba, o quedan dos líneas juntas
   contra lo que tenga encima. */
.barra-arbol { border-top: 0; border-bottom: 1px solid var(--borde); }

.pie-arbol {
  display: flex; align-items: center; gap: 2px; flex: 0 0 auto;
  padding: 6px 8px; border-top: 1px solid var(--borde); background: var(--superficie-2);
}
.btn-pie {
  border: 1px solid transparent; background: transparent; color: var(--texto-2);
  width: 26px; height: 24px; border-radius: 5px; cursor: pointer;
  font-size: 12px; line-height: 1; padding: 0; display: grid; place-items: center;
}
.btn-pie:hover:not(:disabled) { background: var(--acento); border-color: var(--acento); color: #fff; }
.btn-pie:disabled { opacity: .32; cursor: default; }
.sep-pie { width: 1px; height: 16px; background: var(--borde); margin: 0 4px; }

.acciones-rama {
  display: flex; gap: 1px; flex: 0 0 auto;
  opacity: 0; transition: opacity .12s ease;
}
.rama:hover .acciones-rama,
.rama:focus-within .acciones-rama { opacity: 1; }
.acc {
  border: 0; background: transparent; color: var(--texto-2);
  width: 20px; height: 20px; border-radius: 4px; cursor: pointer;
  font-size: 12px; line-height: 1; padding: 0;
  display: grid; place-items: center;
}
.acc:hover { background: var(--acento); color: #fff; }
.acc[data-accion^="borrar"]:hover { background: var(--error); color: #fff; }
.acc:focus-visible { outline: 2px solid var(--acento); outline-offset: 1px; }

/* ── Catálogo completo ── */
.tabla-vista { grid-column: 1 / -1; display: flex; flex-direction: column; min-height: 0; }
.tabla-barra {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 14px; border-bottom: 1px solid var(--borde); background: var(--superficie);
}
.conteo-inline { font-size: 12.5px; color: var(--texto-2); font-variant-numeric: tabular-nums; }
.tabla-scroll { flex: 1; overflow: auto; min-height: 0; }
.tabla-pie {
  display: flex; align-items: center; gap: 12px; justify-content: center;
  padding: 8px 14px; border-top: 1px solid var(--borde); background: var(--superficie);
}
.rejilla { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
.rejilla thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--superficie-2); border-bottom: 1px solid var(--borde);
  padding: 6px 8px; white-space: nowrap; cursor: pointer; user-select: none;
}
.rejilla thead tr.filtros th { top: 30px; padding: 4px 6px; cursor: default; }
.rejilla thead input {
  width: 100%; min-width: 70px; padding: 3px 6px;
  border: 1px solid var(--borde); border-radius: 5px;
  background: var(--fondo); color: var(--texto); font: 11.5px var(--mono);
}
.rejilla thead input:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }
.rejilla tbody td { padding: 5px 8px; border-bottom: 1px solid var(--borde); }
.rejilla tbody tr { cursor: pointer; }
.rejilla tbody tr:hover td { background: var(--superficie-2); }
.rejilla .orden { color: var(--acento); font-size: 10px; margin-left: 3px; }
.rejilla td.ds { max-width: 420px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rejilla td.c, .rejilla th.c { text-align: center; width: 1%; white-space: nowrap; }
.rejilla td.c input[type=checkbox] { cursor: pointer; }

/* ── El destino de captura ──
   A qué matriz se mandan los insumos que se marquen. Va SIEMPRE que se ve una
   rejilla de insumos, con destino o sin él: un botón «agregar» que no dice a
   dónde manda es una forma elegante de perder trabajo. */
.destino-captura {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 12px; margin-bottom: 12px;
  border: 1px solid var(--acento); border-radius: var(--r);
  background: var(--acento-suave); font-size: 13px; color: var(--texto);
}
.destino-captura .cl { font-family: var(--mono); }
.destino-captura button { margin-left: auto; }
/* Sin destino no es un aviso de error: es el siguiente paso. Va en gris, no en
   ámbar — nada está mal, sólo falta abrir una matriz. */
.destino-captura.sin-destino {
  border-color: var(--borde); background: var(--superficie); color: var(--texto-2);
}
.rejilla.con-captura tr.marcada td { background: var(--acento-suave); }
.rejilla.con-captura tr.marcada:hover td { background: var(--acento-suave); }

/* ── El alta en el primer renglón de Propios ── */
.rejilla tr.fila-alta td { background: var(--superficie-2); border-bottom: 2px solid var(--borde); }
.rejilla tr.fila-alta input {
  width: 100%; padding: 4px 7px; border: 1px solid var(--borde); border-radius: 5px;
  background: var(--fondo); color: var(--texto); font-size: 12.5px;
}
.rejilla tr.fila-alta input.alta-cl { font-family: var(--mono); min-width: 110px; }
.rejilla tr.fila-alta input.alta-un { min-width: 60px; }
.rejilla tr.fila-alta input:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }
/* Un propio sin matriz es un hueco que hay que ver antes de entregar, no un
   error: se marca como dato pendiente, con el ámbar de «esto lo tocaste tú y
   falta terminarlo», no en rojo. */
.rejilla tr.sin-matriz td:first-child { box-shadow: inset 3px 0 0 var(--alerta); }

/* ── Botón de agregar a la obra, en el análisis ── */
/* Barra de acciones de la tarjeta. A la izquierda lo que se lee —acciones con
   nombre—, a la derecha las herramientas de trabajo sobre la matriz y el
   semáforo. `align-items: flex-start` para que al envolverse en pantalla
   angosta los dos grupos no se estiren a la misma altura. */
.acciones-detalle {
  display: flex; gap: 12px; margin: 0 0 18px;
  flex-wrap: wrap; align-items: flex-start; justify-content: space-between;
}
.acc-izq, .acc-der { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.acc-der { margin-left: auto; gap: 4px; }
.acc-sep { width: 1px; align-self: stretch; background: var(--borde); margin: 0 4px; }
.acc-der .btn-mini { padding: 5px 7px; }
.acc-der .btn-mini[disabled] { opacity: .3; cursor: default; }
.acc-der .btn-mini[disabled]:hover { background: none; color: inherit; }

/* ── Semáforo de confiabilidad ──
   Vertical, como un semáforo de verdad: las tres luces apiladas se leen de un
   golpe y ocupan el alto que la barra ya tiene, sin robarle ancho a los
   botones. Apagadas quedan casi transparentes para que sólo cante la
   encendida — si las tres se vieran fuertes, ninguna diría nada. */
.semaforo {
  display: flex; flex-direction: column; gap: 2px;
  border: 1px solid var(--borde); border-radius: 6px; padding: 3px;
  background: var(--superficie-2);
}
.sem-luz {
  display: flex; align-items: center; gap: 6px;
  border: 0; background: none; cursor: pointer;
  padding: 2px 7px 2px 4px; border-radius: 4px;
  font: inherit; font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--texto-2); opacity: .45; transition: opacity .12s ease;
}
.sem-luz::before {
  content: ''; width: 9px; height: 9px; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
.sem-alta { color: var(--ok); }
.sem-media { color: var(--alerta); }
.sem-baja { color: var(--error); }
/* La cuarta luz: «sin revisar». Va en blanco con borde, porque un círculo
   blanco sin contorno sobre fondo blanco no existe. */
.sem- { color: var(--texto-2); }
.sem-luz.sem-::before { background: var(--fondo); box-shadow: inset 0 0 0 1px var(--borde); }
.sem-luz.sem-.encendida::before { box-shadow: inset 0 0 0 1px var(--texto-2), 0 0 0 3px color-mix(in srgb, currentColor 20%, transparent); }
.sem-luz:hover { opacity: .8; }

/* ── Carga del logo, en la configuración de la obra ──
   La vista previa a la izquierda y las acciones a la derecha: se ve lo que se
   va a imprimir antes de aceptar, que es el punto de tenerla. */
.cf-logo { display: flex; gap: 14px; align-items: flex-start; }
.cf-logo-vista {
  width: 120px; height: auto; max-height: 100px; object-fit: contain;
  border: 1px solid var(--borde); border-radius: 8px; padding: 6px;
  background: var(--superficie);
}
.cf-logo-acc { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.cf-logo-acc .btn { cursor: pointer; }
.cf-logo-acc p { margin: 0; font-size: 12px; }

/* ── El punto del semáforo en el listado ──
   La misma información que las luces de la tarjeta, del tamaño que cabe en una
   fila. Sin marcar va en blanco con borde: es el estado normal de lo recién
   traído del catálogo, no una alarma. */
.punto-sem {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  background: var(--fondo); box-shadow: inset 0 0 0 1px var(--borde);
  vertical-align: middle;
}
.punto-alta { background: var(--ok); box-shadow: none; }
.punto-media { background: var(--alerta); box-shadow: none; }
.punto-baja { background: var(--error); box-shadow: none; }
.sem-luz.encendida { opacity: 1; font-weight: 600; }
.sem-luz.encendida::before { box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 25%, transparent); }
@media (prefers-reduced-motion: reduce) { .sem-luz { transition: none; } }

/* ── Acciones dentro de la matriz ──
   Ocultas hasta que el cursor entra al renglón: tres botones fijos por fila
   vuelven la matriz ilegible, que es justo lo que se aprendió en el árbol. */
td.acc-mat, th.acc-mat { width: 1%; white-space: nowrap; text-align: right; }
td.acc-mat .btn-mini { opacity: 0; transition: opacity .12s ease; }
tr:hover td.acc-mat .btn-mini,
td.acc-mat .btn-mini:focus-visible { opacity: 1; }
@media (prefers-reduced-motion: reduce) { td.acc-mat .btn-mini { transition: none; } }

.mat-pie { margin: 8px 0 0; }
.btn-mini-txt { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; padding: 5px 10px; }

/* La cantidad rechazada parpadea en rojo: se devuelve al valor anterior y hay
   que decir que NO se guardó, o el usuario cree que sí. */
input.cant.mal { border-color: var(--error); background: color-mix(in srgb, var(--error) 12%, transparent); }

/* Buscador de insumos para agregar un renglón a la matriz. */
.mat-result { max-height: 240px; overflow-y: auto; border: 1px solid var(--borde); border-radius: 6px; margin: 8px 0; }
.mat-op-ins {
  display: grid; grid-template-columns: 130px 1fr 24px 60px 90px; gap: 8px; align-items: center;
  width: 100%; text-align: left; border: 0; border-bottom: 1px solid var(--borde);
  background: none; color: inherit; font: inherit; font-size: 12px; padding: 6px 9px; cursor: pointer;
}
.mat-op-ins:last-child { border-bottom: 0; }
.mat-op-ins:hover { background: var(--superficie-2); }
.mat-op-ins.elegida { background: color-mix(in srgb, var(--acento) 18%, transparent); font-weight: 600; }
.mat-op-ins .cl { font-family: ui-monospace, monospace; }
.mat-op-ins .un, .mat-op-ins .pr { text-align: right; color: var(--texto-2); }

/* ── El tipo de insumo, en su columna ──
   El NÚMERO es el dato —es lo que el motor honra y lo que se teclea al filtrar—
   así que va en un disco de color, legible aunque la columna se angoste. El
   nombre lo acompaña y se retira solo en pantallas estrechas: quien filtra por
   «2» ya sabe qué es 2, y quien no, tiene el globo.

   Los colores distinguen sin semaforizar: ninguno es «bueno» ni «malo». Se
   toman del acento para que no compitan con el rojo de los negativos ni con el
   verde del semáforo de confiabilidad, que sí significan algo. */
.tipo-ins {
  display: inline-grid; place-items: center;
  width: 17px; height: 17px; border-radius: 50%;
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  color: #fff; flex: 0 0 auto;
}
.tipo-1 { background: #6b7f96; }   /* material          */
.tipo-2 { background: #2563a5; }   /* mano de obra      */
.tipo-3 { background: #7a5ea8; }   /* equipo            */
.tipo-4 { background: #3f7f79; }   /* básico            */
.tipo-5 { background: #96703f; }   /* subcontrato       */
.tipo-nom { font-size: 11.5px; color: var(--texto-2); }
@media (max-width: 1400px) { .tipo-nom { display: none; } }

.aj-tipos { display: flex; gap: 14px; flex-wrap: wrap; }
.aj-tipo { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }

/* ── Panel derecho con banner de tarjetas ── */
.panel-derecho { display: flex; flex-direction: column; min-height: 0; }
.panel-derecho .detalle { flex: 1; }

.banner-tarjetas {
  display: flex; align-items: stretch; gap: 2px;
  padding: 6px 10px 0; background: var(--superficie-2);
  border-bottom: 1px solid var(--borde);
  overflow-x: auto; scrollbar-width: none; flex: 0 0 auto;
}
.banner-tarjetas::-webkit-scrollbar { display: none; }
.banner-tarjetas[hidden] { display: none; }
.tarjeta-tab {
  display: flex; align-items: center; gap: 7px;
  border: 1px solid var(--borde); border-bottom: 0;
  background: var(--fondo); color: var(--texto-2);
  padding: 6px 10px; border-radius: 7px 7px 0 0;
  cursor: pointer; font: inherit; font-size: 12.5px;
  white-space: nowrap; flex: 0 0 auto; max-width: 220px;
}
.tarjeta-tab:hover { color: var(--texto); }
.tarjeta-tab.activa {
  background: var(--superficie); color: var(--acento); font-weight: 600;
  border-color: var(--borde);
  /* Tapa la línea de abajo: la pestaña activa se ve unida a su contenido. */
  margin-bottom: -1px; padding-bottom: 7px;
}
/* El icono de la pestaña: identifica el tipo de un vistazo. Se atenúa cuando
   la pestaña no está activa para que no compita con el texto. */
.tarjeta-tab > .ico { flex: 0 0 auto; opacity: .55; }
.tarjeta-tab.activa > .ico { opacity: 1; }
.tarjeta-tab:hover > .ico { opacity: .85; }

.tt-txt { overflow: hidden; text-overflow: ellipsis; font-family: var(--mono); }
.tt-cerrar {
  width: 15px; height: 15px; border-radius: 3px; flex: 0 0 auto;
  display: grid; place-items: center; font-size: 13px; line-height: 1;
}
.tt-cerrar:hover { background: var(--error); color: #fff; }
.tarjeta-cerrar-todas {
  border: 0; background: transparent; color: var(--texto-2);
  cursor: pointer; font: inherit; font-size: 12px;
  padding: 0 8px; margin-left: auto; flex: 0 0 auto;
}
.tarjeta-cerrar-todas:hover { color: var(--error); }

/* ── Listado de conceptos de una partida ── */
.barra-carrito {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 9px 12px; margin-bottom: 14px;
  border: 1px solid var(--borde); border-radius: var(--r);
  background: var(--superficie); font-size: 13px;
}
.barra-carrito.activa { border-color: var(--acento); background: var(--acento-suave); }
.marca-todos { display: flex; align-items: center; gap: 6px; cursor: pointer; color: var(--texto-2); }
.cuenta-carrito { font-weight: 600; color: var(--acento); }

table.listado td.c, table.listado th.c { text-align: center; width: 1%; white-space: nowrap; }
table.listado td.c input[type=checkbox] { cursor: pointer; }
table.listado tr.marcada td { background: var(--acento-suave); }
table.listado tbody tr:hover td { background: var(--superficie-2); }
table.listado tr.marcada:hover td { background: var(--acento-suave); }
table.listado input.cant, table.listado input.campo-rgl {
  width: 92px; padding: 3px 6px; border: 1px solid var(--borde); border-radius: 5px;
  background: var(--fondo); color: var(--texto); font: 12px var(--mono); text-align: right;
}
table.listado input.campo-rgl { width: 62px; }
table.listado input.cant:focus, table.listado input.campo-rgl:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }
table.listado .btn-mini { font-size: 13px; padding: 2px 5px; }
table.listado .btn-mini:hover { background: var(--acento); color: #fff; }
/* La columna Descripción se ensancha arrastrando su borde. El ancho vive en
   una variable del contenedor, así que moverlo no toca ninguna celda: con
   cientos de filas, escribir el ancho en cada `<td>` sería recorrerlas todas
   en cada movimiento del ratón. */
table.listado th.col-ds, table.listado td.col-ds {
  width: var(--ancho-ds, 340px);
  max-width: var(--ancho-ds, 340px);
  overflow-wrap: anywhere;
}
/* Todo encabezado del listado ancla a su tirador de ancho: el de Descripción y
   los demás. Va aquí y no en el JS porque es presentación, y porque consultarlo
   desde el código ataba el módulo a `getComputedStyle`, que el arnés de pruebas
   no tiene.

   La REJILLA no entra aquí a propósito: sus encabezados son `sticky` para que se
   queden a la vista al desplazar 42 mil renglones, y `sticky` ya es una posición
   —el tirador ancla igual—. Escribirles `relative` los desclavaría, y con la
   misma especificidad que `.rejilla thead th` ganaría esta regla por ir después. */
table.listado th { position: relative; }
.tirador-col {
  position: absolute; top: 0; right: -3px; width: 7px; height: 100%;
  cursor: col-resize; z-index: 3;
}
.tirador-col::after {
  content: ''; position: absolute; top: 20%; left: 3px;
  width: 1px; height: 60%; background: var(--borde);
}
.tirador-col:hover::after { background: var(--acento); width: 2px; }

/* ── Descripción completa del concepto ──
   Del ancho de la tabla y justo encima de ella: es el texto que va al
   presupuesto, y con hasta 934 caracteres no cabe en un título ni en una celda
   sin ensanchar la columna. Aquí se lee entero de un vistazo.

   Medida de lectura holgada pero no infinita — un párrafo que cruza toda una
   pantalla ancha se pierde al saltar de línea. */
.concepto-completo {
  border: 1px solid var(--borde); border-left: 3px solid var(--acento);
  border-radius: 0 var(--r) var(--r) 0;
  background: var(--superficie);
  padding: 10px 14px; margin-bottom: 14px;
}
.concepto-completo .cc-et {
  display: block; font-size: 10px; letter-spacing: .07em;
  text-transform: uppercase; color: var(--texto-2); margin-bottom: 3px;
}
.concepto-completo p {
  margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--texto);
  max-width: 100ch;
}

/* ── Controles dentro de la matriz ──
   El operador se elige de una lista y no se teclea: `*`, `/` y `%` hacen
   aritmética distinta, y confundirlos cambia el costo directo en silencio. */
.op-matriz, .base-pct {
  padding: 2px 4px; border: 1px solid var(--borde); border-radius: 5px;
  background: var(--fondo); color: var(--texto); font: inherit; font-size: 11.5px;
  max-width: 100%;
}
.op-matriz { min-width: 84px; }
/* La base del % va bajo el nombre del insumo, que es donde se lee la frase
   completa: «HERRAMIENTA MENOR — de la mano de obra». */
.base-pct { display: block; margin-top: 3px; color: var(--alerta); }
.op-matriz:focus, .base-pct:focus {
  outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent;
}
table input.cant[data-cant-matriz] { width: 92px; }

/* ── Tabla de mano de obra ──
   Catorce columnas y 46 renglones: cabe porque la descripción cede ancho y la
   envoltura se desplaza a lo ancho, nunca la página. */
.tabla-mo { font-size: 12.5px; }
.tabla-mo th { white-space: nowrap; }
.tabla-mo .ds { min-width: 180px; max-width: 320px; }
.tabla-mo td.fuerte { font-weight: 600; color: var(--acento); font-variant-numeric: tabular-nums; }
.tabla-mo tr.mo-tocada td:first-child { box-shadow: inset 3px 0 0 var(--acento); }

.celda-mo {
  width: 92px; text-align: right; font-family: var(--mono); font-size: 12px;
  padding: 3px 5px; border: 1px solid transparent; border-radius: 5px;
  background: transparent; color: var(--texto);
}
.celda-mo:hover { border-color: var(--borde); background: var(--fondo); }
.celda-mo:focus { outline: none; border-color: var(--acento); background: var(--superficie); }
.celda-mo[data-tocado] { color: var(--acento); font-weight: 600; }
.celda-mo.fsr { width: 104px; }
select.celda-mo.tipo-fasar {
  width: auto; min-width: 150px; text-align: left; font-family: inherit;
  border-color: var(--borde);
}

/* Parámetros globales del FASAR, agrupados: las referencias del año por un
   lado y los cargos que cambian de estado a estado por otro. */
.grupo-param {
  display: flex; flex-direction: column; gap: 6px;
  padding: 8px 0; border-bottom: 1px solid var(--borde);
}
.grupo-param:last-of-type { border-bottom: 0; }
.et-grupo {
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--texto-2); font-weight: 600;
}

/* Precio tecleable dentro de la rejilla del catálogo. Discreto hasta que se
   usa: una columna de 60 cajas con borde grita más que la lista que contiene.
   El que se cambió sí se marca — hay que poder ver de un vistazo qué se tocó. */
.precio-cat {
  width: 108px; text-align: right; font-family: var(--mono); font-size: 12.5px;
  padding: 3px 6px; border: 1px solid transparent; border-radius: 5px;
  background: transparent; color: var(--texto);
}
.precio-cat:hover { border-color: var(--borde); background: var(--fondo); }
.precio-cat:focus { outline: none; border-color: var(--acento); background: var(--superficie); }
.precio-cat.fijado {
  color: var(--acento); font-weight: 600;
  box-shadow: inset 2px 0 0 var(--acento);
}

/* Parámetros editables de un insumo o de un costo horario. Los CALCULADOS se
   atenúan: no se pueden tocar y hay que verlo antes de intentarlo, no después. */
.par-maq {
  width: 130px; text-align: right; font-family: var(--mono);
  padding: 4px 7px; border: 1px solid var(--borde); border-radius: 6px;
  background: var(--fondo); color: var(--texto); font-size: 12.5px;
}
.par-maq:focus { outline: none; border-color: var(--acento); background: var(--superficie); }
tr.par-calculado td { color: var(--texto-2); }
tr.par-calculado td:last-child { font-weight: 400; }

/* El recuadro de la descripción, cuando se puede corregir ahí mismo. El borde
   punteado dice «esto se escribe» sin gritarlo como un campo de formulario. */
.concepto-completo.editable .cc-texto {
  border: 1px dashed transparent; border-radius: 6px;
  margin: 0 -6px; padding: 2px 6px; cursor: text;
}
.concepto-completo.editable .cc-texto:hover { border-color: var(--borde); }
.concepto-completo.editable .cc-texto:focus {
  outline: none; border: 1px solid var(--acento);
  background: var(--superficie);
}
.cc-pista { font-weight: 400; text-transform: none; letter-spacing: 0; opacity: .7; }

/* Aviso de lo que se pierde al borrar: en rojo porque es lo único del diálogo
   que hay que leer antes de confirmar. */
.aviso-borrado {
  background: color-mix(in srgb, var(--error) 10%, transparent);
  border-left: 3px solid var(--error);
  padding: 8px 10px; border-radius: 0 6px 6px 0; margin: 10px 0 0;
  font-size: 13px;
}

/* Nombre de partida editable en el propio árbol. Doble clic y se escribe:
   abrir un diálogo para cambiar una palabra costaba más que el cambio. */
.rama .txt[contenteditable] {
  outline: 2px solid var(--acento); outline-offset: 1px;
  background: var(--superficie); border-radius: 4px; padding: 0 3px;
  cursor: text; white-space: normal;
}

/* ── Celda editable ──
   Se ve como texto hasta que el cursor se acerca: una tabla con cientos de
   campos dibujados como campos es ilegible. El subrayado punteado al pasar
   dice que se puede corregir sin gritarlo. */
.celda-edit {
  display: block; min-height: 1.2em; border-radius: 4px;
  padding: 1px 3px; margin: -1px -3px;
  border-bottom: 1px dashed transparent; cursor: text;
}
.celda-edit:hover { border-bottom-color: var(--texto-2); }
.celda-edit:focus {
  outline: 2px solid var(--acento); outline-offset: 0;
  background: var(--superficie); border-bottom-color: transparent;
}

table.listado thead tr.filtros th { padding: 4px 6px; }
table.listado thead tr.filtros input {
  width: 100%; min-width: 52px; box-sizing: border-box; padding: 3px 6px;
  border: 1px solid var(--borde); border-radius: 5px;
  background: var(--fondo); color: var(--texto); font: 12px var(--mono);
}
table.listado thead tr.filtros input:focus {
  outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent;
}
table.listado tr.actual td { box-shadow: inset 0 0 0 1px var(--acento); }
.pie-listado {
  margin: -8px 0 18px; font-size: 12px; color: var(--texto-2);
  font-variant-numeric: tabular-nums;
}

/* ── Reportes ── */
/* ── Panel de reportes ──
   Cuatro zonas de alto fijo —obra, controles, conteo, pie— y la lista al
   medio con el sobrante. Así la lista es lo único que se desplaza: antes, con
   todo apilado en una columna que crecía, el panel entero sacaba barra y el
   pie quedaba fuera de vista justo cuando se necesitaba. */
#vista-reportes .lateral { display: flex; flex-direction: column; min-height: 0; }
#vista-reportes .fuente-rep,
#vista-reportes .obra-reporte,
#vista-reportes .conteo,
#vista-reportes .pie-reportes { flex: 0 0 auto; }
#vista-reportes #lista-reportes { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* Qué obra reportan: fijo arriba, porque es lo primero que hay que saber
   antes de imprimir cuando hay varios catálogos abiertos. */
.obra-reporte {
  display: flex; flex-direction: column; gap: 5px;
  padding: 10px 12px; border-bottom: 1px solid var(--borde);
  background: var(--superficie);
}
.obra-reporte-nom {
  display: flex; align-items: center; gap: 6px;
  font-weight: 600; font-size: 13.5px; color: var(--texto);
}
.obra-reporte-nom .ico { color: var(--acento); fill: currentColor; }
.obra-reporte .sutil { font-size: 11.5px; }
.obra-reporte .pastilla { align-self: flex-start; }

.pie-reportes { gap: 6px; }
.pie-reportes .btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 12.5px; }

.fuente-rep {
  padding: 12px; border-bottom: 1px solid var(--borde);
  display: flex; flex-direction: column; gap: 10px;
}
.fuente-rep label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--texto-2); font-weight: 600;
}
.fuente-rep label[hidden] { display: none; }
.fuente-rep select, .fuente-rep input {
  padding: 7px 9px; border: 1px solid var(--borde); border-radius: 7px;
  background: var(--fondo); color: var(--texto); font: inherit; font-size: 13px;
}
.fuente-rep select:focus, .fuente-rep input:focus {
  outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent;
}
.fuente-rep .ayuda { font-weight: 400; }

.grupo-rep {
  padding: 9px 12px 4px; font-size: 11px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--texto-2);
}
.item-rep {
  padding: 8px 12px; cursor: pointer; font-size: 13px;
  border-bottom: 1px solid var(--borde);
  display: flex; flex-direction: column; gap: 2px;
}
/* La flecha del árbol es UN chevron que gira: dos glifos distintos para
   abierto y cerrado saltaban de tamaño al plegar. Rotando, el movimiento
   explica el plegado en vez de sólo indicarlo. */
.flecha .ico { transition: transform .15s ease; }
@media (prefers-reduced-motion: reduce) { .flecha .ico { transition: none; } }
.flecha.abierta .ico { transform: rotate(90deg); }

.item-rep:hover { background: var(--superficie-2); }
/* Apagado, no escondido: que se vea que existe y por qué no aplica ahora.
   Se le quita el cursor de mano además de la opacidad — un elemento que se ve
   pulsable y no responde es peor que uno que se ve apagado. */
.item-rep.apagado { opacity: .42; cursor: default; }
.item-rep.apagado:hover { background: transparent; }
.item-rep.sel { background: var(--acento-suave); box-shadow: inset 3px 0 0 var(--acento); }
.item-rep .maq { font-size: 11px; color: var(--texto-2); font-family: var(--mono); }

.lateral {
  border-right: 1px solid var(--borde); background: var(--superficie);
  display: flex; flex-direction: column; min-height: 0;
}
.buscador { padding: 12px; border-bottom: 1px solid var(--borde); }
.buscador input {
  width: 100%; padding: 9px 12px;
  border: 1px solid var(--borde); border-radius: 8px;
  background: var(--fondo); color: var(--texto); font: inherit;
}
.buscador input:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }

.filtro-partida, .params-fasar {
  padding: 10px 12px; border-bottom: 1px solid var(--borde);
  display: flex; flex-direction: column; gap: 6px;
}
.params-fasar { flex-direction: row; flex-wrap: wrap; gap: 10px; }
.filtro-partida label, .params-fasar label {
  font-size: 12px; color: var(--texto-2); font-weight: 500;
  display: flex; flex-direction: column; gap: 4px;
}
.filtro-partida select, .params-fasar select, .params-fasar input {
  padding: 7px 9px; border: 1px solid var(--borde); border-radius: 7px;
  background: var(--fondo); color: var(--texto); font: inherit; font-size: 13px;
}
.params-fasar input, .params-fasar select { width: 104px; font-family: var(--mono); }
.acciones-fasar { display: flex; align-items: flex-end; gap: 6px; flex-wrap: wrap; }
#fasar-quitar { color: var(--error); }
.fsr-manual {
  /* Los renglones de la lista son columnas: el campo va bajo el meta. */
  width: 84px; padding: 3px 6px; margin-top: 2px; align-self: flex-start;
  border: 1px solid var(--borde); border-radius: 5px;
  background: var(--fondo); color: var(--texto); font: 12px var(--mono); text-align: right;
}
.fsr-manual:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }
/* NIVEL 3 · ESTADO DEL DATO — no compite con la selección: se distingue por
   FORMA (un punto) además de por color, porque el color solo no basta para
   quien no lo distingue. Puede haber muchos a la vez; selección, sólo una. */
.marca-estado-dato { position: relative; }
.marca-estado-dato::before {
  content: ''; position: absolute; left: 4px; top: 50%;
  width: 6px; height: 6px; margin-top: -3px; border-radius: 50%;
  background: var(--alerta);
}
#lista-fasar li.con-manual { padding-left: 18px; position: relative; }
#lista-fasar li.con-manual::before {
  content: ''; position: absolute; left: 6px; top: 14px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--alerta);
}
.rejilla tr.con-manual td { background: var(--alerta-suave); }
.rejilla tr.con-manual td:first-child { box-shadow: inset 3px 0 0 var(--alerta); }

/* ── Captura de avance ── */
.est-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 12px; }
.est-tab {
  border: 1px solid var(--borde); background: var(--superficie); color: var(--texto-2);
  padding: 5px 12px; border-radius: 7px; cursor: pointer; font: inherit; font-size: 13px;
}
.est-tab:hover { border-color: var(--acento); color: var(--texto); }
.est-tab.activa {
  border-color: var(--acento); color: var(--acento); font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--acento);
}
.est-tab .ico { margin-left: 4px; }
.est-tab.cerrada .ico { color: var(--ok); }

.est-periodo {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 14px;
  border: 1px solid var(--borde); border-radius: var(--r);
  background: var(--superficie); font-size: 13px;
}
.est-periodo label { display: flex; align-items: center; gap: 6px; color: var(--texto-2); }
.est-periodo input[type=date] {
  padding: 4px 7px; border: 1px solid var(--borde); border-radius: 6px;
  background: var(--fondo); color: var(--texto); font: inherit; font-size: 12.5px;
}
.est-periodo input:disabled { opacity: .6; }

/* El renglón con avance en el periodo se distingue: es lo que se está cobrando. */
/* Con avance en el periodo: es lo que se está cobrando, y conviene que salte. */
.rep-tabla tr.con-avance td { background: var(--ok-suave); }
.rep-tabla tr.con-avance td:first-child { box-shadow: inset 3px 0 0 var(--ok); }

/* Programado: tiene fecha, pero eso no es un logro — es sólo un dato puesto.
   Marca discreta, sin fondo, para que destaque lo que FALTA por programar. */
.rep-tabla tr.programado td:first-child { box-shadow: inset 3px 0 0 var(--acento); }
td.n.completo { color: var(--ok); font-weight: 600; }
input[type=date] {
  padding: 3px 6px; border: 1px solid var(--borde); border-radius: 5px;
  background: var(--fondo); color: var(--texto); font: 12px var(--mono);
}
input[type=date]:focus, .est-periodo input:focus {
  outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent;
}

.conteo {
  padding: 8px 12px; font-size: 12px; color: var(--texto-2);
  border-bottom: 1px solid var(--borde); background: var(--superficie-2);
  font-variant-numeric: tabular-nums;
}

.lista { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; min-height: 0; }
.lista li {
  padding: 9px 12px; border-bottom: 1px solid var(--borde);
  cursor: pointer; display: flex; flex-direction: column; gap: 2px;
}
.lista li:hover { background: var(--superficie-2); }
.lista li.sel { background: var(--acento-suave); box-shadow: inset 3px 0 0 var(--acento); }
.lista .cl { font-family: var(--mono); font-size: 12px; color: var(--acento); font-weight: 600; }
.lista .ds {
  font-size: 13px; color: var(--texto);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.lista .meta { font-size: 11.5px; color: var(--texto-2); font-variant-numeric: tabular-nums; }

/* ── Detalle ── */
.detalle { overflow-y: auto; padding: 22px 26px 60px; min-height: 0; }
.vacio { max-width: 46ch; margin: 12vh auto 0; text-align: center; color: var(--texto-2); }
.vacio h2 { color: var(--dorado); font-size: 19px; margin: 0 0 8px; }
.vacio p { margin: 0; font-size: 14px; }

.enc-detalle { margin-bottom: 20px; }
.enc-detalle .cl {
  font-family: var(--mono); color: var(--acento); font-weight: 700; font-size: 14px;
}
/* El título del panel es el dorado; la clave de arriba, el azul. Dos jerarquías
   que se leen por color, no sólo por tamaño. */
.enc-detalle h1 {
  font-size: 19px; margin: 4px 0 8px; line-height: 1.3; font-weight: 600;
  color: var(--dorado);
}
.etiquetas { display: flex; flex-wrap: wrap; gap: 6px; }
.etiqueta {
  font-size: 11.5px; padding: 2px 9px; border-radius: 20px;
  background: var(--superficie-2); color: var(--texto-2); border: 1px solid var(--borde);
}

/* ── Tablas ── */
.tabla-envoltura { overflow-x: auto; margin-bottom: 18px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: left; font-weight: 600; font-size: 11.5px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--texto-2);
  padding: 7px 9px; border-bottom: 1px solid var(--borde); white-space: nowrap;
}
td { padding: 6px 9px; border-bottom: 1px solid var(--borde); }
td.n, th.n { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); font-size: 12.5px; }
td.cl { font-family: var(--mono); font-size: 12px; color: var(--acento); white-space: nowrap; }
tr.seccion td {
  background: var(--superficie-2); font-weight: 700; font-size: 11.5px;
  letter-spacing: .05em; color: var(--texto-2); padding: 7px 9px;
}
tr.subtotal td { font-weight: 600; border-bottom: 2px solid var(--borde); }
tr.pct td { color: var(--texto-2); font-style: italic; }
tr.total td { font-weight: 700; font-size: 14px; border-bottom: 0; padding-top: 10px; }

/* ── Encabezado y firmas de reporte ── */
/* ── Membrete del reporte ──
   Rejilla de dos columnas: el logo a la izquierda, cruzando los dos renglones,
   y a la derecha el nombre de la obra con sus datos. Es la disposición de
   cualquier papel membretado, y la que esperan las dependencias. */
.rep-encabezado {
  border-bottom: 2px solid var(--acento);
  margin-bottom: 16px; padding: 10px 12px 8px;
  background: var(--superficie); border-radius: var(--r) var(--r) 0 0;
  display: grid; grid-template-columns: auto 1fr; gap: 2px 14px; align-items: center;
}
/* Se ajusta por ALTO y no por ancho: el logo cruza los dos renglones del
   membrete, así que lo que tiene que cuadrar es su altura. Con un ancho fijo,
   un logo apaisado se salía y uno vertical dejaba un hueco. `object-fit` para
   que el de la obra —de cualquier proporción— no se deforme al sustituirlo.

   La REGLA vertical a su derecha es lo que lo ancla: sin ella el logo flotaba
   junto al texto sin pertenecer a nada. Es la separación de cualquier papel
   membretado, y de paso reserva el hueco para que el nombre de la obra no se
   le pegue. */
.rep-logo {
  grid-row: 1 / span 2; align-self: center;
  height: 52px; width: auto; max-width: 150px; object-fit: contain;
  padding-right: 14px; border-right: 1px solid var(--borde);
}
/* Sin logo, el texto ocupa las dos columnas y no queda una sangría huérfana. */
.rep-encabezado > .rep-obra:first-child { grid-column: 1 / -1; }
.rep-encabezado > .rep-obra:first-child ~ .rep-datos { grid-column: 1 / -1; }
.rep-obra {
  font-size: 16px; font-weight: 700; color: var(--acento);
  letter-spacing: .01em; align-self: end;
}
.rep-datos {
  display: flex; flex-wrap: wrap; gap: 3px 18px;
  font-size: 12.5px; color: var(--texto-2); margin-top: 5px;
}
/* La tabla del reporte se lee de corrido: encabezado fijo al desplazar,
   renglones alternos para no perder la fila, y la columna de importe marcada
   —es la que se sigue con el dedo. */
.rep-tabla thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--superficie-2); border-bottom: 2px solid var(--borde);
}
.rep-tabla tbody tr:nth-child(even) td { background: var(--superficie); }
.rep-tabla tbody tr:hover td { background: var(--acento-suave); }
.rep-tabla tr.seccion td { position: sticky; top: 30px; z-index: 1; }
.rep-tabla tbody td:last-child { font-weight: 500; }

/* ── Análisis de precios unitarios ──
   Tres niveles dentro de la misma tabla y hay que distinguirlos de un vistazo:
   el CONCEPTO abre el bloque, sus SECCIONES (materiales, mano de obra…) agrupan
   dentro, y el pie integra del costo directo al precio. Si los tres se vieran
   igual, el documento sería una lista plana de cientos de renglones. */
.rep-tabla tr.grupo td {
  background: var(--acento); color: #fff; font-weight: 600;
  position: sticky; top: 30px; z-index: 2;
}
.rep-tabla tr.seccion td {
  background: var(--acento-suave); color: var(--acento);
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  font-weight: 600; position: static;
}
.rep-tabla tr.subtotal td {
  background: var(--superficie-2); font-weight: 600;
  border-top: 1px solid var(--borde);
}
.rep-tabla tr.cargo-grupo td { background: var(--superficie-2); color: var(--texto-2); }
.rep-tabla tr.cierre-grupo td {
  background: var(--acento-suave); color: var(--acento);
  font-weight: 700; border-bottom: 2px solid var(--acento);
}
.rep-tabla tr.cargo-grupo:hover td, .rep-tabla tr.cierre-grupo:hover td,
.rep-tabla tr.grupo:hover td { background: inherit; }

.firmas { display: flex; gap: 40px; margin: 52px 0 20px; flex-wrap: wrap; }
.firma { flex: 1; min-width: 160px; max-width: 260px; text-align: center; }
.firma-linea { border-bottom: 1px solid var(--texto); height: 30px; margin-bottom: 6px; }
.firma-nombre { font-size: 13px; font-weight: 600; }
.firma-rol {
  font-size: 11px; color: var(--texto-2);
  text-transform: uppercase; letter-spacing: .06em;
}

/* ── Cascada de cargos ── */
.cascada {
  background: var(--superficie); border: 1px solid var(--borde);
  border-radius: var(--r); padding: 14px 16px; max-width: 460px; box-shadow: var(--sombra);
}
.cascada .fila {
  display: flex; justify-content: space-between; gap: 20px;
  padding: 5px 0; font-size: 13.5px;
}
.cascada .fila .v { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.cascada .fila.destacada {
  border-top: 1px solid var(--borde); margin-top: 6px; padding-top: 10px;
  font-weight: 700; font-size: 16px;
}
.cascada .fila.destacada .v { color: var(--acento); }
.cascada .lbl-cargo { color: var(--texto-2); }

/* Rótulo de sección: azul, un escalón por debajo del título dorado. */
h3.sec {
  font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--acento); margin: 22px 0 8px; font-weight: 700;
}

/* ── Cortina de carga ── */
.cargando {
  position: fixed; inset: 0; z-index: 100;
  background: var(--fondo);
  display: grid; place-items: center;
  transition: opacity .35s ease;
}
.cargando.fuera { opacity: 0; pointer-events: none; }
.caja-carga { text-align: center; width: min(380px, 84vw); }
.logo-grande {
  font-size: 27px; font-weight: 800; letter-spacing: .04em;
  color: var(--acento); margin-bottom: 22px;
}
.logo-grande span { color: var(--texto-2); font-weight: 500; margin-left: 8px; letter-spacing: .16em; }
.barra-progreso {
  height: 5px; background: var(--superficie-2);
  border-radius: 3px; overflow: hidden;
}
.progreso {
  height: 100%; width: 0%; background: var(--acento);
  border-radius: 3px; transition: width .25s ease;
}
.estado {
  margin: 12px 0 0; font-size: 13px; color: var(--texto-2);
  font-variant-numeric: tabular-nums; min-height: 1.4em;
}
.pie-carga { margin: 26px 0 0; font-size: 12px; color: var(--texto-2); opacity: .75; }

/* ── El rescate del arranque ──
   Sólo se ve cuando la carga falló. La caja se ensancha por la misma razón que
   con `sinbase-tit`: aquí hay que leer un mensaje de error y elegir, y eso no se
   lee centrado en 380 px. */
.cargando .caja-carga:has(.rescate-carga:not([hidden])) { width: min(560px, 90vw); }
.estado.estado-error { color: var(--peligro, #d9534f); font-weight: 600; }
.rescate-carga { margin: 18px 0 0; text-align: left; }
.rescate-detalle {
  margin: 0 0 14px; padding: 10px 12px; font-size: 12.5px; line-height: 1.5;
  color: var(--texto-2); background: var(--fondo-2, rgba(127, 127, 127, .10));
  border-left: 3px solid var(--peligro, #d9534f); border-radius: 4px;
  /* El error puede ser largo y traer rutas: se envuelve en vez de desbordar. */
  overflow-wrap: anywhere;
}
.rescate-botones { display: flex; flex-wrap: wrap; gap: 8px; }
/* `hidden` tiene que ganar: un `display` nuestro se impone al del navegador y
   dejaría el bloque de rescate a la vista en un arranque normal. */
.rescate-carga[hidden], .rescate-botones[hidden] { display: none; }
.rescate-ayuda {
  margin: 16px 0 0; font-size: 12px; line-height: 1.5; color: var(--texto-2); opacity: .85;
}

/* ── Primer arranque, sin base cargada ──
   La caja de carga es angosta porque sólo lleva una barra de avance; aquí lleva
   instrucciones, así que se ensancha y el texto se alinea a la izquierda: tres
   pasos centrados se leen peor que tres pasos en columna. */
.cargando .caja-carga:has(.sinbase-tit) { width: min(560px, 90vw); }
.sinbase-tit { font-size: 19px; font-weight: 600; margin: 22px 0 10px; color: var(--dorado); }
.sinbase-txt {
  font-size: 14px; line-height: 1.55; color: var(--texto-2);
  text-align: left; margin: 0 0 20px;
}
.sinbase-pasos { display: flex; flex-direction: column; gap: 12px; text-align: left; }
.sinbase-paso {
  display: flex; gap: 12px; align-items: flex-start;
  font-size: 13px; line-height: 1.5;
}
/* El número dice que son pasos EN ORDEN, no una lista de opciones: importar
   antes de validar, y validar antes de copiar. */
.sinbase-n {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--acento); color: #fff; font-size: 12px; font-weight: 600;
}
.sinbase-paso code {
  background: var(--superficie-2); border: 1px solid var(--borde);
  border-radius: 4px; padding: 1px 5px; font-size: 12px;
}

/* ── Aviso ── */
.aviso {
  position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%);
  background: var(--superficie); border: 1px solid var(--error); color: var(--error);
  padding: 10px 16px; border-radius: 8px; box-shadow: var(--sombra);
  /* Encima de TODO, y del modal incluido: es donde se dicen los errores, y el
     más importante de todos —«ese archivo no es una base»— se da mientras el
     diálogo está abierto. Estaba en 90, debajo de la cortina de carga, así que
     durante el arranque los avisos se escribían donde nadie los veía: ni el
     «Leyendo archivo…» ni el motivo de que algo fallara. */
  font-size: 13.5px; z-index: 150; max-width: min(560px, 90vw);
}
.aviso[hidden] { display: none; }

.sutil { color: var(--texto-2); }
.mono { font-family: var(--mono); }

/* ── Presupuesto ── */
.obra-selector {
  padding: 10px 12px; border-bottom: 1px solid var(--borde);
  display: flex; align-items: center; gap: 4px;
}
.obra-selector select {
  flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--borde);
  border-radius: 7px; background: var(--fondo); color: var(--texto);
  font: inherit; font-size: 13px; cursor: pointer;
}
.obra-selector select:focus { outline: 2px solid var(--acento); outline-offset: -1px; }

/* Nombre y cliente en UNA fila: apilados se comían 40 px del alto que le
   toca al árbol, y el resto de los datos generales ya vive en el ⚙. */
.obra-datos {
  padding: 8px 12px; border-bottom: 1px solid var(--borde);
  display: flex; gap: 8px;
}
/* Los dos campos se reparten el ancho. Sin `flex` en el cliente, el nombre se
   llevaba su parte y el resto quedaba como un hueco muerto a la derecha. */
.obra-datos input { min-width: 0; flex: 1; }
.obra-datos input {
  width: 100%; padding: 8px 10px; border: 1px solid var(--borde); border-radius: 7px;
  background: var(--fondo); color: var(--texto); font: inherit; font-size: 13px;
}
.obra-datos .obra-nombre { font-weight: 600; font-size: 13px; flex: 1.4; }
.obra-datos input:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }

.acciones { padding: 10px 12px; border-bottom: 1px solid var(--borde); display: flex; gap: 8px; }
.btn {
  border: 1px solid var(--borde); background: var(--superficie); color: var(--texto);
  padding: 7px 12px; border-radius: 7px; cursor: pointer; font: inherit; font-size: 13px;
}
.btn:hover { border-color: var(--acento); color: var(--acento); }
.btn-primario { background: var(--acento); border-color: var(--acento); color: #fff; font-weight: 600; }
.btn-primario:hover { filter: brightness(1.08); color: #fff; }
.btn-mini {
  border: 0; background: transparent; color: var(--texto-2);
  cursor: pointer; font: inherit; font-size: 15px; line-height: 1; padding: 2px 6px; border-radius: 5px;
}
.btn-mini:hover { background: var(--superficie-2); color: var(--error); }

#arbol-obra { padding: 4px 0; }
.propio {
  font-size: 10px; padding: 1px 5px; border-radius: 4px;
  background: var(--acento-suave); color: var(--acento); font-weight: 700;
}

/* ── Ayuda al pasar el cursor ──
   Propia y no la del navegador. El `title` nativo tarda cerca de un segundo,
   se dibuja con la tipografía del sistema operativo —así que en Windows se ve
   como un globo de Windows dentro de una app que no lo es— y no se puede
   estilar. Éste aparece en 150 ms, con la tipografía de la app.

   Es CSS puro: sin JavaScript que escuche el ratón. El texto va en
   `data-ayuda`, y el elemento conserva su `title` para lectores de pantalla y
   para el caso en que el CSS no cargue. */
/* ── RETIRADO: se queda el globo del NAVEGADOR ──
   Reportado: «se superponen 2 etiquetas para cada botón, la del navegador y la
   de la plantilla, deja la del navegador».

   Y es cierto: cada elemento lleva las dos —`title` y `data-ayuda`— con el mismo
   texto, así que al pasar el cursor salían ambas, una encima de otra. Se
   comprobó antes de quitarlo: los 62 elementos con `data-ayuda` tienen TAMBIÉN
   `title`, así que no se pierde una sola ayuda.

   Los atributos `data-ayuda` se conservan en el marcado: no estorban, y volver
   a encender este globo es descomentar el bloque. Las razones por las que se
   hizo propio siguen siendo ciertas —el nativo tarda ~1 s y usa la tipografía
   del sistema— pero dos globos a la vez es peor que uno lento. */
[data-ayuda] { position: relative; }
[data-ayuda].globo-propio::after {
  content: attr(data-ayuda);
  position: absolute; bottom: calc(100% + 7px); left: 50%;
  transform: translateX(-50%);
  background: var(--texto); color: var(--fondo);
  font: 500 11.5px/1.35 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  letter-spacing: .01em;
  border-radius: 6px;
  white-space: normal; width: max-content;
  text-align: center; pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity .12s ease .15s, visibility 0s linear .27s;
  z-index: 60; box-shadow: var(--sombra);

  /* ── Por qué el globo mide CERO mientras está oculto ──
     `opacity: 0` y `visibility: hidden` lo vuelven invisible, pero la caja
     sigue existiendo y MIDIENDO: un pseudo-elemento absoluto cuenta para el
     área desplazable de su contenedor. Medido en Chrome: el globo de
     «Cambiar tema» se extendía 90 px más allá del botón, que está pegado al
     borde derecho de la barra, y de ahí salía la barra de desplazamiento
     horizontal del documento —13 px que no se explicaban con ningún elemento
     visible—. En el árbol, los globos de las acciones de cada rama hacían lo
     mismo: 46 px, con una barra horizontal desde el primer renglón.

     Con ancho máximo cero y `overflow: hidden` no aporta nada al desbordamiento,
     y al pasar el cursor recupera su tamaño. La caja sigue ahí, así que la
     transición de opacidad se conserva. */
  max-width: 0; overflow: hidden; padding: 0;
}
[data-ayuda].globo-propio:hover::after,
[data-ayuda].globo-propio:focus-visible::after {
  opacity: 1; visibility: visible;
  max-width: 230px; overflow: visible; padding: 5px 9px;
  transition: opacity .12s ease .15s, visibility 0s;
}
/* Cerca del borde superior el globo se saldría de la pantalla: se pone abajo. */
[data-ayuda].globo-propio[data-ayuda-abajo]::after { bottom: auto; top: calc(100% + 7px); }
@media (prefers-reduced-motion: reduce) {
  [data-ayuda].globo-propio::after { transition: none; }
}
/* En táctil no hay «pasar el cursor»: el globo se quedaría pegado tras tocar. */
@media (hover: none) { [data-ayuda].globo-propio::after { display: none; } }

/* ── Barra de ayuda contextual ──
   Al pie del panel, dice qué es lo que está seleccionado y qué se puede hacer
   con ello. Es la diferencia entre descubrir la app y adivinarla. */
.ayuda-pie {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 7px 12px; border-top: 1px solid var(--borde);
  background: var(--superficie-2); color: var(--texto-2);
  font-size: 11.5px; line-height: 1.35;
}
/* El texto se recorta a tres líneas CON puntos suspensivos, no con una tijera.
   Antes era `max-height: 3.1em; overflow: hidden`, que cortaba la tercera línea
   a media altura: en pantalla se leía «…o busca por clave o» y ahí se acababa,
   sin ninguna señal de que faltara algo. Medido en Chrome: el texto de la vista
   de catálogo necesita tres líneas en los 339 px del panel y sólo tenía dos.
   `line-clamp` corta por renglón completo y pone la elipsis, así que se ve que
   hay más; el `title` lo lleva entero para quien lo necesite. */
.ayuda-pie > .ayuda-txt {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
}
.ayuda-pie .ico { margin-top: 1px; }
.ayuda-pie .ico { color: var(--acento); opacity: .8; }
.ayuda-pie b { color: var(--texto); font-weight: 600; }
.ayuda-pie .tecla {
  font-family: var(--mono); font-size: 10.5px;
  border: 1px solid var(--borde); border-bottom-width: 2px;
  border-radius: 4px; padding: 0 4px; background: var(--superficie);
  color: var(--texto-2);
}

/* Lo editado del Maestro. Un punto, no un fondo: pueden estar marcadas muchas
   ramas a la vez y un relleno por cada una haría ilegible el árbol. Ámbar,
   igual que el dato manual del FASAR — es la misma idea: esto lo tocaste tú. */
.punto-editado {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--alerta); vertical-align: middle; margin-left: 2px;
  flex: 0 0 auto;
}

/* ── Pastillas de estado ──
   Para el estado de un DOCUMENTO —abierta, cerrada, en proceso—, que se lee
   de un vistazo y nombra lo que pasa. Lleva punto además de color: el color
   solo no basta para quien no lo distingue, y la forma sí se ve siempre. */
.pastilla {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; padding: 2px 9px 2px 7px;
  border-radius: 20px; white-space: nowrap; letter-spacing: .01em;
  background: var(--superficie-2); color: var(--texto-2);
}
.pastilla::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
.pastilla-ok { background: var(--ok-suave); color: var(--ok); }
.pastilla-proceso { background: var(--alerta-suave); color: var(--alerta); }
.pastilla-acento { background: var(--acento-suave); color: var(--acento); }

td input.cant {
  width: 110px; padding: 4px 7px; border: 1px solid var(--borde); border-radius: 6px;
  background: var(--fondo); color: var(--texto); font: 12.5px var(--mono); text-align: right;
}
td input.cant:focus { outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent; }

/* ── Modal ──
   ── Por qué va por ENCIMA de la cortina y de la ventana de inicio ──

   Estaba en 80, debajo de la cortina de carga (100) y de la ventana de inicio
   (120). En una copia recién entregada eso hacía IMPOSIBLE cargar una base:

     · sin `data/` la app se queda en «Falta cargar tu base» y la cortina SIGUE
       PUESTA a propósito —la interfaz no se montó—;
     · se pulsa «Importar base…», el selector de archivos abre (es del sistema,
       va por encima de todo), el archivo se lee bien…
     · …y el diálogo que pide confirmar sale DETRÁS de la cortina. Invisible.

   El usuario ve que no pasa nada, y no pasa nada: nadie puede pulsar «Importar»
   en un diálogo que no se ve, así que la base nunca se aplica. Sin un error en
   consola, porque no hay error — hay una capa encima.

   Es el mismo defecto que ya se documentó con `hidden`: algo funcionando
   perfectamente detrás de otra cosa que lo tapa. El diálogo tiene que estar
   siempre encima de todo lo que puede abrirlo, y las dos pantallas que lo abren
   antes de que exista la interfaz son la cortina y el inicio. */
.modal {
  position: fixed; inset: 0; z-index: 140;
  background: rgba(10, 16, 22, .55);
  display: grid; place-items: center; padding: 20px;
}
.modal[hidden] { display: none; }
/* ── El tamaño, y por qué se puede cambiar ──
   Con 760 px el diálogo de importar salía apretado: dos opciones de destino con
   su explicación completa, el nombre, la casilla y la nota, todo en una columna
   angosta que obligaba a desplazar para comparar dos opciones que hay que leer
   JUNTAS para elegir.

   Por omisión ahora es más ancho y más alto —cabe lo que hay que comparar— y
   además el usuario lo agranda con la esquina y lo mueve arrastrando su barra de
   título. Lo que ajuste se recuerda: ver `recordarCaja` en presupuesto.js. */
.modal-caja {
  background: var(--superficie); border: 1px solid var(--borde); border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
  width: min(940px, 96vw); max-height: 92vh;
  min-width: 320px; min-height: 200px;
  max-width: 98vw;
  display: flex; flex-direction: column;
  /* `resize` pide que el desbordamiento no sea `visible`. El cuerpo tiene su
     propio desplazamiento, así que ocultar aquí no esconde nada. */
  resize: both; overflow: hidden;
}
/* Cuando el usuario lo mueve, deja de centrarlo la rejilla del `.modal`. */
.modal-caja.movida { position: fixed; margin: 0; }
.modal-enc {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--borde);
  /* Se arrastra de aquí, como cualquier ventana. `flex: none` para que la barra
     no se encoja cuando el cuerpo crece. */
  cursor: move; user-select: none; flex: none;
}
.modal-enc button { cursor: pointer; }
.modal-enc h2 { margin: 0; font-size: 16px; font-weight: 600; color: var(--dorado); }
.modal-cuerpo { padding: 18px; overflow-y: auto; }
.modal-pie {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 18px; border-top: 1px solid var(--borde);
}
.modal-msg { flex: 1; font-size: 12.5px; color: var(--error); }
.campo { display: flex; flex-direction: column; gap: 5px; margin-bottom: 14px; }
.campo label { font-size: 12px; color: var(--texto-2); font-weight: 600; }
.campo input, .campo select, .campo textarea {
  padding: 8px 10px; border: 1px solid var(--borde); border-radius: 7px;
  background: var(--fondo); color: var(--texto); font: inherit; font-size: 13.5px; width: 100%;
}
.campo textarea { font-family: var(--mono); font-size: 12.5px; min-height: 150px; resize: vertical; }
.campo input:focus, .campo select:focus, .campo textarea:focus {
  outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent;
}
.campo .ayuda { font-size: 11.5px; color: var(--texto-2); font-weight: 400; }
.fila-campos { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* Lectura del importador de matrices */
.lectura { margin-top: 12px; border: 1px solid var(--borde); border-radius: 8px; overflow: hidden; }
.lectura-enc {
  padding: 8px 12px; background: var(--superficie-2); font-size: 12px;
  display: flex; gap: 14px; flex-wrap: wrap;
}
.lectura table { font-size: 12px; }
.lectura td, .lectura th { padding: 5px 9px; }
.lectura .mal { color: var(--error); }
.lectura .duda { color: var(--alerta); }
.lectura .bien { color: var(--ok); }
.lectura-cuerpo { max-height: 300px; overflow-y: auto; }
.marca-estado { font-weight: 700; }

/* ── Pegar una matriz ──
   El ejemplo va AL LADO del cuadro, no dentro: un `placeholder` desaparece
   justo cuando se querría comparar contra él. */
.pegar-zona { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; }
.pegar-zona textarea { width: 100%; min-height: 108px; }
.pegar-ayuda {
  font-size: 12px; color: var(--texto-2); line-height: 1.45;
  border: 1px dashed var(--borde); border-radius: 8px; padding: 8px 10px;
  background: var(--superficie-2);
}
.pegar-ayuda strong { color: var(--texto); }
.pegar-ayuda p { margin: 6px 0; }
.pegar-ayuda pre {
  font-family: var(--mono); font-size: 11px; margin: 6px 0;
  white-space: pre; overflow-x: auto; color: var(--texto);
}
/* El tabulador es invisible y es lo que separa las columnas: se dibuja. */
.pegar-ayuda .tab { color: var(--acento); opacity: .7; }
@media (max-width: 720px) { .pegar-zona { grid-template-columns: 1fr; } }

/* Leído: el cuadro de texto se retira. Con los dos a la vista habría dos
   fuentes de verdad y ninguna forma de saber cuál gana. */
.pegar-hecho {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--texto-2);
}

/* ── La tabla de lectura, ya editable ── */
.tabla-lectura select.op-lectura,
.tabla-lectura input.cant-lectura {
  border: 1px solid var(--borde); border-radius: 5px; background: var(--fondo);
  color: var(--texto); font: 12px var(--mono); padding: 2px 5px;
}
.tabla-lectura input.cant-lectura { width: 94px; text-align: right; }
.tabla-lectura select.op-lectura { font-family: inherit; }
.tabla-lectura input:focus, .tabla-lectura select:focus {
  outline: 2px solid var(--acento); outline-offset: -1px; border-color: transparent;
}
.tabla-lectura td.ds { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* El renglón que no resuelve se ve, pero no como una alarma: es trabajo
   pendiente, no una falla del programa. */
.tabla-lectura tr.fila-huerfana td { background: var(--alerta-suave); }
.tabla-lectura tr.fila-arreglo td {
  font-size: 11.5px; padding-top: 0; padding-bottom: 7px;
  border-bottom: 1px solid var(--borde);
}
.tabla-lectura .btn-mini.pick, .tabla-lectura .btn-mini.equiv {
  font-family: var(--mono); font-size: 11px; margin-left: 5px;
  border: 1px solid var(--borde); border-radius: 5px; padding: 2px 7px;
}
.tabla-lectura .btn-mini.equiv { font-family: inherit; max-width: 320px; text-align: left; }
.tabla-lectura .btn-mini.pick.elegido { border-color: var(--acento); color: var(--acento); font-weight: 600; }
.tabla-lectura input.buscar-equiv {
  border: 1px solid var(--borde); border-radius: 5px; background: var(--fondo);
  color: var(--texto); font: 11.5px inherit; padding: 3px 7px; min-width: 220px; margin-left: 4px;
}
.tabla-lectura .equiv-res { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-left: 6px; }

/* ── Impresión ──
   El mismo documento que se ve, en papel: fuera la navegación y los botones,
   la tabla a todo lo ancho, encabezados de columna repetidos en cada hoja y
   los renglones sin partirse a la mitad. Es también la vía al PDF, porque el
   navegador ya trae «Guardar como PDF» en su diálogo de impresión. */
@media print {
  .barra, .cinta, .lateral, .divisor, .btn-panel, .banner-tarjetas,
  .panel-factores, .no-imprimir, .acciones-detalle, #aviso,
  /* Herramientas de captura: en papel no se marca nada ni se agrega a ninguna
     matriz, y el aviso de destino ocuparía el ancho de la hoja diciendo algo
     que sólo tiene sentido en pantalla. */
  .destino-captura, .barra-carrito { display: none !important; }

  main { height: auto; position: static; }
  .vista { position: static; display: none; }
  .vista.activa { display: block; }
  .detalle { overflow: visible; padding: 0; }

  body { background: #fff; color: #000; }
  /* El membrete se imprime en AZUL, no en negro: es la misma escala de tinta de
     la pantalla y del Excel, y una regla de color identifica la hoja de un
     vistazo en un legajo de cincuenta. Las CIFRAS siguen en negro. */
  .rep-encabezado { background: none; border-bottom: 2pt solid #123a63; }
  .rep-obra { color: #123a63; }
  /* El dorado es de la PANTALLA. En papel la escala de tinta es la del membrete
     —azul profundo y cifras en negro—, la misma del Excel, y un título dorado en
     una hoja que se entrega al cliente rompería esa unidad. Además el dorado
     sobre blanco impreso pierde la mitad de su contraste. */
  .enc-detalle h1, .vacio h2, .modal-enc h2, .sinbase-tit { color: #123a63; }
  h3.sec { color: #123a63; }
  /* El logo se imprime. Sin esto el navegador puede omitir fondos e imágenes
     decorativas, y el membrete saldría sin él justo en el papel que se entrega. */
  .rep-logo {
    display: block !important; height: 42pt; max-height: 42pt; width: auto;
    padding-right: 10pt; border-right: .5pt solid #123a63;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }

  table { font-size: 9pt; }
  thead { display: table-header-group; }   /* el encabezado se repite por hoja */
  tr, .firma { break-inside: avoid; }
  .tabla-envoltura { overflow: visible; }
  .firmas { break-inside: avoid; margin-top: 40pt; }

  /* ── El pie, repetido en cada hoja ──
     `position: fixed` es lo que Chrome repite en todas las páginas impresas: es
     la única vía, porque las cajas de margen de `@page` —donde iría un
     `content: counter(page)`— no están implementadas en Chrome. El número de
     hoja lo pone el propio diálogo de impresión con «Encabezados y pies de
     página»; aquí va lo que el navegador no sabe: de qué obra es la hoja y
     quién la elaboró. */
  .rep-pie-hoja {
    display: block !important;
    position: fixed; bottom: 0; left: 0; right: 0;
    border-top: .5pt solid #123a63;
    padding-top: 3pt; font-size: 7.5pt; color: #444;
    display: flex; justify-content: space-between; gap: 12pt;
  }
  /* El contenido no debe montarse encima del pie fijo. */
  .detalle { padding-bottom: 24pt; }

  /* Una tabla de veinte columnas en vertical no se lee. */
  @page { margin: 14mm 14mm 20mm; size: landscape; }
}

/* El pie de hoja SÓLO existe en papel: en pantalla el mismo dato ya está en el
   membrete de arriba, y repetirlo abajo sería ruido. */
.rep-pie-hoja { display: none; }

/* ── Pantallas chicas ── */
@media (max-width: 860px) {
  .barra { gap: 10px; padding: 0 10px; }
  .titulo { display: none; }
  /* En pantallas chicas la cinta conserva sus botones; los títulos de grupo
     se ocultan para ganar una fila. */
  .cinta { height: auto; padding: 2px 6px; }
  .cinta-titulo { display: none; }
  main { height: auto; }
  .vista.activa, .vista:has(.lateral-ancha), .vista.sin-lateral { grid-template-columns: 1fr; }
  .lateral { border-right: 0; border-bottom: 1px solid var(--borde); }
  /* En una columna no hay nada que dividir. */
  .divisor, .btn-panel { display: none; }
  .vista.sin-lateral .lateral { overflow: visible; }
  .lista { max-height: 44vh; }
  .detalle { padding: 16px 14px 40px; }
}

/* La clave de la partida, junto al WBS: es el prefijo de sus conceptos. */
.rama .clave-part {
  font-family: var(--mono); font-size: 11px; color: var(--texto-2);
  flex: 0 0 auto; opacity: .85;
}

/* ══ Ventana de inicio ════════════════════════════════════════════════════════
   La primera pantalla: qué hay guardado y con qué se trabaja hoy. Es el
   «Catálogo de obras general» de AFBdatos, y como allá, se ve ANTES que nada.

   Va por encima de la cortina de carga (z-index 100) porque se elige primero y
   se carga después: mientras esta ventana está abierta no hay ninguna descarga
   en marcha que la barra de avance pudiera estar contando.
   ========================================================================== */
.inicio {
  position: fixed; inset: 0; z-index: 120;
  background: var(--fondo);
  display: grid; place-items: center;
  padding: 24px 16px; overflow: auto;
}
/* Sin esto la ventana NO se cierra: un `display` de autor gana sobre el
   `display: none` que el atributo `hidden` trae de la hoja del navegador, y la
   app quedaba montada y funcionando detrás de una pantalla que la tapaba
   entera. Es la misma línea que ya llevan `.modal`, `.aviso` y el panel de
   factores, y por la misma razón. */
.inicio[hidden] { display: none; }
.inicio-caja {
  width: min(880px, 100%);
  background: var(--superficie);
  border: 1px solid var(--borde); border-radius: var(--r);
  box-shadow: var(--sombra);
  padding: 26px 26px 18px;
}

.ini-enc { display: flex; align-items: center; gap: 16px; margin-bottom: 20px; }
.ini-logo { flex: none; }
/* El logo grande trae 22px de margen inferior para la cortina de carga, donde
   va solo y centrado. Aquí va en fila con el subtítulo y ese hueco lo rompe. */
.ini-enc .logo-grande { margin-bottom: 4px; }
.ini-sub { margin: 0; font-size: 13.5px; color: var(--texto-2); }

/* ── «Seguir donde quedé» ──
   Ocupa el ancho entero y va antes que las listas porque es la respuesta
   correcta la mayoría de las veces: casi nadie cambia de base entre dos
   sesiones seguidas, y el que sí, tiene las dos columnas justo debajo. */
.ini-seguir {
  display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
  width: 100%; text-align: left; cursor: pointer;
  padding: 12px 16px; margin-bottom: 22px;
  border: 1px solid var(--acento); border-radius: var(--r);
  background: var(--acento-suave); color: var(--texto);
  font: inherit;
}
.ini-seguir:hover { border-color: var(--acento-vivo); }
.ini-seguir-et { font-size: 12px; font-weight: 600; color: var(--acento); letter-spacing: .02em; }
.ini-seguir-q { font-size: 14.5px; }
.ini-flecha { color: var(--texto-2); margin: 0 2px; }

.ini-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.ini-col > h3 { margin: 0 0 2px; font-size: 13px; letter-spacing: .03em; text-transform: uppercase; color: var(--acento); }
.ini-ayuda { margin: 0 0 10px; font-size: 12.5px; line-height: 1.45; color: var(--texto-2); }
.ini-vacio { margin: 0; font-size: 12.5px; color: var(--texto-2); opacity: .8; }

.ini-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.ini-fila {
  border: 1px solid var(--borde); border-radius: 8px;
  background: var(--superficie);
  display: flex; align-items: stretch;
}
.ini-fila:hover { border-color: var(--acento); }
.ini-fila.es-montada { border-color: var(--acento); background: var(--acento-suave); }

.ini-abrir {
  flex: 1; min-width: 0; text-align: left; cursor: pointer;
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 12px; border: 0; background: transparent; color: inherit; font: inherit;
  border-radius: 8px;
}
.ini-abrir[disabled] { cursor: default; opacity: .6; }
.ini-nom { font-size: 14px; font-weight: 600; }
/* Las cuentas y la fecha se cortan con puntos suspensivos en vez de envolver:
   una fila de dos renglones y otra de tres desalinean la lista entera. */
.ini-det, .ini-fecha {
  font-size: 11.5px; color: var(--texto-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ini-fecha { font-family: var(--mono); opacity: .75; }

/* El interruptor de consulta. Va pegado al borde derecho y en vertical para
   que no compita con el nombre: abrir es la acción, tener de consulta es una
   preferencia que se marca de paso. */
.ini-fondo {
  flex: none; display: flex; align-items: center; gap: 4px;
  padding: 0 10px; border-left: 1px solid var(--borde);
  font-size: 11px; color: var(--texto-2); cursor: pointer; user-select: none;
}
.ini-fondo:has(input:disabled) { opacity: .4; cursor: default; }
.ini-fondo input { margin: 0; }

/* Las dos acciones de la derecha, apiladas: tener de consulta y cambiar de
   columna. Van juntas y separadas del nombre por una línea, porque ninguna de
   las dos ABRE nada — y el clic grande de la fila sí. */
.ini-acciones {
  flex: none; display: flex; flex-direction: column; justify-content: center;
  gap: 3px; padding: 0 8px; border-left: 1px solid var(--borde);
}
.ini-mover {
  border: 1px solid var(--borde); border-radius: 6px; background: transparent;
  color: var(--texto-2); font: inherit; font-size: 10.5px;
  padding: 1px 6px; cursor: pointer; white-space: nowrap;
}
.ini-mover:hover { border-color: var(--acento); color: var(--acento); }
.ini-mover[disabled] { opacity: .5; cursor: default; }

/* Una base sin insumos: se marca en ámbar, no en rojo. No está rota — se puede
   abrir y funciona—; lo que pasa es que casi seguro no es lo que parece. */
.ini-fila.es-dudosa { border-color: var(--alerta); background: var(--alerta-suave); }
.ini-dudosa { font-size: 11px; color: var(--alerta); }
.ini-error { font-size: 11px; color: var(--error); }

.ini-pie {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--borde);
}
.ini-nota { flex: 1 1 100%; margin: 0; font-size: 11.5px; color: var(--texto-2); opacity: .8; }
.btn-sutil { color: var(--texto-2); }

@media (max-width: 720px) {
  .ini-cols { grid-template-columns: 1fr; gap: 18px; }
  .inicio-caja { padding: 18px 16px 14px; }
}

/* ── El destino de un archivo importado ──
   Las dos opciones se pintan como tarjetas y no como un `select` porque la
   diferencia entre ellas necesita una frase para entenderse, y una lista
   desplegable no tiene dónde ponerla. Es la elección que decide de dónde van a
   salir los precios: merece verse entera antes de marcar. */
/* Las dos opciones LADO A LADO cuando hay ancho. Son excluyentes y hay que
   compararlas para elegir: en una columna angosta obligaban a desplazar entre
   una y otra, que es justo lo que impide compararlas. Bajo 640 px se apilan. */
.imp-destinos { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.imp-opcion {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  padding: 13px 15px; border: 1px solid var(--borde); border-radius: 8px;
  font-size: 13.5px; line-height: 1.55;
}
.imp-opcion:hover { border-color: var(--acento); }
.imp-opcion:has(input:checked) { border-color: var(--acento); background: var(--acento-suave); }
.imp-opcion.desactivada { opacity: .55; cursor: default; }
.imp-opcion.desactivada:hover { border-color: var(--borde); }
.imp-opcion input { margin-top: 3px; flex: none; }

/* Listas de consecuencias dentro de un diálogo: qué se copia, qué se reusa y
   qué falta. Con viñeta, porque son cosas distintas y no pasos de un proceso. */
.lista-simple { margin: 10px 0; padding-left: 20px; font-size: 13px; line-height: 1.5; }
.lista-simple li + li { margin-top: 5px; }
.lista-simple .mal, .lista-simple li.mal { color: var(--error); }
