:root {
  --bg:        #0f1419;
  --bg-panel:  #1a212b;
  --bg-elev:   #222c38;
  --border:    #2d3a48;
  --text:      #e6edf3;
  --text-dim:  #93a1b0;
  --accent:    #4f9cf9;
  --accent-2:  #2d7ff0;
  --green:     #3fb950;
  --amber:     #d29922;
  --red:       #f85149;
  --violet:    #a371f7;
  /* 2px, no 9: Faena viene de la obra y el canto redondeado convierte cualquier caja en una
     tarjeta de aplicación. Es UN token para toda la interfaz — cajetines, botones, campos,
     diálogos y tarjetas—, así que no hay que ir cuadrando caja por caja ni queda nada desparejo. */
  /* Serie categorica de los graficos. NO son colores decorativos ni se reciclan: cada ranura
     pertenece a un concepto fijo (1 material, 2 planilla, 3 contratistas, 4 gastos) y el orden
     no cambia aunque uno valga cero, porque el color identifica, no clasifica por tamaño.
     Verde/ambar/rojo quedan RESERVADOS para estado —bien/ojo/mal— y nunca hacen de "serie 5".
     Los pasos estan medidos, no elegidos a ojo: banda de luminosidad, croma minimo, separacion
     bajo daltonismo (protan/deutan) y contraste contra el fondo del panel. */
  --c1: #3987e5;
  --c2: #d95926;
  --c3: #199e70;
  --c4: #9a67a6;
  --radius:    2px;
  --shadow:    0 4px 20px rgba(0,0,0,.35);
  --zebra:     rgba(127,140,155,.06);
  --zebra-strong: rgba(255,255,255,.035);
  color-scheme: dark;
  font-synthesis: none;
}

/* Alto contraste: negro/blanco puros (no grises intermedios), bordes bien marcados y colores
   más saturados — pensado para trabajar bajo luz fuerte o con dificultad visual. Fondo claro
   porque el contraste texto/fondo es mayor en blanco puro que en negro puro para la mayoría
   de la gente (WCAG AAA: #000 sobre #fff = 21:1). */
:root[data-theme="alto-contraste"] {
  --bg:        #ffffff;
  --bg-panel:  #ffffff;
  --bg-elev:   #eeeeee;
  --border:    #000000;
  --text:      #000000;
  --text-dim:  #333333;
  --accent:    #0044cc;
  --accent-2:  #002f99;
  --green:     #006600;
  --amber:     #9c5700;
  --red:       #b30000;
  --violet:    #5500aa;
  /* Los mismos cuatro conceptos, re-escalonados contra fondo blanco: no es el juego oscuro
     invertido, son pasos propios que vuelven a pasar las mismas medidas sobre #ffffff. */
  --c1: #1f5fb0;
  --c2: #c04a17;
  --c3: #0d7a52;
  --c4: #b354f0;
  --radius:    4px;
  --shadow:    0 2px 0 #000000;
  --zebra:     rgba(0,0,0,.05);
  --zebra-strong: rgba(0,0,0,.08);
  color-scheme: light;
}
/* En alto contraste, los controles interactivos llevan borde de 2px (más notorio) en vez del
   1px tenue del resto de temas. */
:root[data-theme="alto-contraste"] .btn, :root[data-theme="alto-contraste"] .btn-icon,
:root[data-theme="alto-contraste"] input, :root[data-theme="alto-contraste"] select,
:root[data-theme="alto-contraste"] textarea, :root[data-theme="alto-contraste"] .b-edit:hover {
  border-width: 2px !important;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("/fonts/IBMPlexSans-Variable.woff2") format("woff2-variations"), url("/fonts/IBMPlexSans-Variable.woff2") format("woff2");
  font-weight: 100 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("/fonts/IBMPlexSans-Variable-Italic.woff2") format("woff2-variations"), url("/fonts/IBMPlexSans-Variable-Italic.woff2") format("woff2");
  font-weight: 100 700;
  font-style: italic;
  font-display: swap;
}

* { box-sizing: border-box; }
button, input, select, textarea { font-family: inherit; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
}

/* ---------- Topbar ---------- */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 20px; min-height: 56px;
  background: var(--bg-panel);
  border-bottom: 1px solid var(--border);
  /* Por encima de la cabecera y la cinta del Gantt (z-index 30). La barra superior crea su propio
     contexto de apilado, asi que el z-index:50 de sus menus desplegables solo compite DENTRO de
     ella: contra el Gantt vale lo que valga la barra. Con 20 quedaba por debajo y el menu de Temas
     salia cortado en esa vista. */
  position: sticky; top: 0; z-index: 40;
  flex-wrap: wrap; row-gap: 8px;
}
.topbar[hidden] { display: none; }
@font-face {
  font-family: "Oswald";
  src: url("/fonts/Oswald-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 19px; letter-spacing: .3px; }
#brand-text {
  font-family: "Oswald", "Arial Narrow", "Helvetica Neue Condensed", Impact, sans-serif;
  font-weight: 900;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: .5px;
  font-size: 37px;
  line-height: 1;
  background: linear-gradient(100deg, #E2572A 0%, #E2572A 45%, #4A4A4A 55%, #4A4A4A 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-stroke: .3px rgba(0,0,0,.15);
}
.brand .logo { color: var(--accent); font-size: 11px; }
.topbar-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; row-gap: 8px; justify-content: flex-end; }
/* Estandariza los botones de solo-icono (🔄 recargar, 🔑 cambiar contraseña, 🚪 cerrar sesión) para
   que tengan el mismo aspecto (borde, fondo, tamaño) que "🔎 Buscar" y "🎨 Temas ▾" — antes eran
   completamente planos (sin borde) y quedaban visualmente sueltos junto a los botones con caja. */
.topbar-right .btn-icon {
  border: 1px solid var(--border); background: transparent; color: var(--text);
  width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
  padding: 0; font-size: 17px;
}
.topbar-right .btn-icon:hover { background: color-mix(in srgb, var(--bg-elev), var(--text) 12%); color: var(--text); }
.topnav { display: flex; gap: 6px; }
#theme-toggle { font-size: 18px; }

/* Tags llamativos (tooltips personalizados) para los botones de la barra superior — el color
   sigue al tema activo (--accent/--accent-2, ambos definidos por tema) en vez de un degradado
   acento+violeta fijo, que desentonaba en Alto contraste, Terracota y Sepia. */
.topbar [data-tooltip] { position: relative; }
.topbar [data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute; top: calc(100% + 10px); left: 50%; transform: translateX(-50%) translateY(-4px) scale(.92);
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff; padding: 6px 12px; border-radius: 8px; font-size: 13px; font-weight: 700;
  white-space: nowrap; box-shadow: 0 8px 20px rgba(0,0,0,.35); pointer-events: none;
  opacity: 0; visibility: hidden; transition: opacity .16s ease, transform .16s ease; z-index: 100;
}
.topbar [data-tooltip]::before {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%) translateY(2px);
  border: 6px solid transparent; border-bottom-color: var(--accent-2);
  opacity: 0; visibility: hidden; transition: opacity .16s ease; pointer-events: none; z-index: 100;
}
/* Alto contraste: nada de degradado de color — negro sólido con texto blanco, coherente con el
   resto del tema (que evita cualquier tono intermedio). */
:root[data-theme="alto-contraste"] .topbar [data-tooltip]::after { background: #000000; box-shadow: none; }
:root[data-theme="alto-contraste"] .topbar [data-tooltip]::before { border-bottom-color: #000000; }
.topbar [data-tooltip]:hover::after, .topbar [data-tooltip]:hover::before { opacity: 1; visibility: visible; }
.topbar [data-tooltip]:hover::after { transform: translateX(-50%) translateY(0) scale(1); }
.navbtn {
  background: transparent; color: var(--text-dim); border: 1px solid transparent;
  padding: 8px 14px; border-radius: var(--radius); cursor: pointer; font-size: 15px; font-weight: 500;
  white-space: nowrap; transition: background .12s, color .12s, border-color .12s;
}
.navbtn:hover { color: var(--text); background: var(--bg-elev); }
/* Activo con el ACENTO, no un gris tenue: mismo criterio que la barra de espacios — el "aqui
   estas" se lee de un vistazo y es coherente en toda la app. */
.navbtn.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); border-color: color-mix(in srgb, var(--accent) 32%, transparent); font-weight: 600; }

/* ---------- Layout ---------- */
/* ---------- RIEL: NAVEGACIÓN Y HERRAMIENTAS ----------
   Sustituye a la barra superior entera. 210px de ancho: caben icono y etiqueta en una línea, que
   es lo que hace acertable un botón sin mirar. El alto completo de la pantalla queda para
   trabajar — en un presupuesto de cien renglones, esos 56px de cabecera se notan.
   En móvil se acuesta abajo, en iconos y con desplazamiento lateral: un carril vertical se come
   el ancho justo donde menos sobra. */
.riel[hidden] { display: none; }
.riel { position: fixed; top: 0; left: 0; bottom: 0; width: 210px; z-index: 45;
  background: var(--bg-panel); border-right: 1px solid var(--border);
  /* SIN overflow: los menús (Pendientes, Tema) salen por el borde derecho del riel, y cualquier
     recorte los deja invisibles — que es justo lo que pasaba con `overflow-y: auto`. Para que en
     pantallas bajas no se desborde, el hueco central cede y los botones se aprietan un poco. */
  display: flex; flex-direction: column; padding: 10px 8px; gap: 4px; overflow: visible; }

/* La marca va en columna y centrada: el logotipo arriba, el nombre debajo. El bloque del logo
   tiene alto propio (48px) porque es ESPACIO RESERVADO — cuando exista el logotipo definitivo
   entra ahí sin recolocar nada. El nombre venía a 36px de la barra ancha y en 210px se salía. */
.riel-marca { display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 8px 4px 14px; color: var(--text); }
.riel-marca .logo { display: flex; align-items: center; justify-content: center;
  width: 100%; min-height: 48px; color: var(--accent); }
.riel-marca .logo svg { width: 36px; height: 36px; }
.riel-marca #brand-text { font-size: 27px; letter-spacing: .4px; }

.riel-grupo { display: flex; flex-direction: column; gap: 2px; }
.riel-hueco { flex: 1 1 auto; min-height: 0; }
@media (max-height: 720px) and (min-width: 901px) {
  .riel-btn, .riel .navbtn { padding: 6px 10px; font-size: 14px; }
  .riel-marca { padding-bottom: 8px; }
}
/* Cada sección con su rótulo: en un riel de once botones, saber de qué va cada bloque ahorra
   leerlos todos. El primero no lleva rótulo — está pegado a la marca y es lo evidente. */
.riel-seccion { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); }
.riel-rotulo { font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-dim); font-weight: 600; padding: 2px 10px 4px; }
.riel-util { margin-top: 0; }

.riel-btn, .riel .navbtn { position: relative; display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 9px 10px; background: none; border: 0; border-radius: var(--radius);
  color: var(--text-dim); cursor: pointer; font: inherit; font-size: 14.5px; font-weight: 500;
  text-align: left; white-space: nowrap; }
.riel-btn i, .riel .navbtn i { font-size: 20px; line-height: 1; flex-shrink: 0; }
.riel-btn:hover, .riel .navbtn:hover { background: var(--bg-elev); color: var(--text); }
.riel-btn:focus-visible, .riel .navbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Activo: el acento a la izquierda, como una marca de pintura en el canto. */
.riel .navbtn.active { background: var(--bg-elev); color: var(--text); font-weight: 600;
  box-shadow: inset 3px 0 0 var(--accent); }
.riel .notif-badge { position: static; margin-left: auto; }
.riel .dropdown { width: 100%; }
/* Los menús cuelgan hacia la derecha del riel, no hacia abajo como colgaban de la barra. */
/* TODAS las cajas que cuelgan del riel se comportan igual: pegadas a su botón, saliendo por la
   derecha, con el mismo ancho mínimo y el mismo tope de alto. Antes cada una traía sus medidas
   (Pendientes pedía 340px y se anclaba a la derecha de la pantalla), y dos cajas del mismo sitio
   con dos aspectos distintos se leen como dos cosas distintas. */
/* Contenido de una caja del riel: cabecera con título y cierre, cuerpo con aire, y un pie para
   los botones cuando los lleva. Mismo esqueleto para todas, así ninguna se siente ajena. */
.caja-riel .caja-riel-head { display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 10px 12px 8px; border-bottom: 1px solid var(--border); }
.caja-riel .caja-riel-head h3 { margin: 0; font-size: 14px; font-weight: 600; letter-spacing: -.01em; }
.caja-riel .caja-riel-body { padding: 12px; display: flex; flex-direction: column; gap: 10px; }
.caja-riel .caja-riel-body .field { margin: 0; }
.caja-riel .caja-riel-foot { display: flex; gap: 8px; justify-content: flex-end; padding-top: 4px; }
.caja-riel .gs-campo { width: 100%; box-sizing: border-box; font-size: 15px; padding: 8px 10px;
  border-radius: var(--radius); border: 1px solid var(--border); background: var(--bg-elev); color: inherit; }
.caja-riel .gs-campo:focus { outline: none; border-color: var(--accent); }
.caja-riel .gs-lista { max-height: 46vh; overflow-y: auto; }
/* La clave de IA lleva una pista larga ("Empieza por «sk-»…") que partida en dos líneas se lee
   peor de lo que ocupa. Se le da ancho propio para que entre de una: es la única caja con un texto
   de ese largo, y ensanchar las cinco por una sola sería pagarlo en todas. */
#clave-ia-menu { min-width: 420px; }
/* Pendientes no usa .caja-riel-body (sus filas van a sangre para que el hover ocupe toda la caja),
   pero sí comparte cabecera, bordes y colores del tema. */
.caja-riel.notif-menu .notif-group-title:first-of-type { border-top: 0; }
.caja-riel .notif-empty { padding: 18px 14px; }

.riel .dropdown { position: relative; }
.riel .dropdown-menu,
.riel .notif-menu {
  left: calc(100% + 6px); right: auto; top: auto; bottom: 0;
  min-width: 300px; max-width: min(440px, calc(100vw - 230px));
  max-height: calc(100vh - 32px);
}
/* Las cajas del riel cuelgan por abajo del botón; cuando el botón está en lo alto (Pendientes) y
   la caja es larga, se salía por arriba de la pantalla. ajustarAltoDropdown() le pone esta clase
   para que crezca hacia abajo, que es donde hay sitio. */
.riel .dropdown-menu.abre-abajo, .riel .notif-menu.abre-abajo { top: 0; bottom: auto; }

@media (max-width: 900px) {
  /* Acostado abajo: solo iconos, con desplazamiento lateral si no caben. */
  .riel { top: auto; left: 0; right: 0; bottom: 0; width: auto; height: 58px;
    flex-direction: row; align-items: center; gap: 2px; padding: 0 6px;
    border-right: 0; border-top: 1px solid var(--border); overflow-x: auto; overflow-y: hidden; }
  .riel-marca, .riel-hueco { display: none; }
  .riel-grupo { flex-direction: row; gap: 2px; }
  /* Acostado no hay sitio para rótulos: las secciones se separan con una línea vertical. */
  .riel-rotulo { display: none; }
  .riel-seccion { margin-top: 0; padding-top: 0; border-top: 0;
    border-left: 1px solid var(--border); padding-left: 6px; margin-left: 6px; }
  .riel-btn, .riel .navbtn { flex-direction: column; gap: 1px; padding: 6px 9px; font-size: 10.5px;
    width: auto; text-transform: uppercase; letter-spacing: .04em; }
  .riel .navbtn.active { box-shadow: inset 0 3px 0 var(--accent); }
  .riel .dropdown-menu { left: auto; right: 6px; bottom: 62px; }
  .riel .notif-badge { position: absolute; top: 2px; right: 4px; margin-left: 0; }
}

body { padding-left: 210px; }
@media (max-width: 900px) { body { padding-left: 0; padding-bottom: 58px; } }

/* EL ANCHO DE TRABAJO, IGUAL EN TODAS LAS PANTALLAS. Antes el área útil eran 1240 px y solo unas
   pocas vistas —el Gantt, el tablero, abastecimiento— subían a 1900. El resultado era que la
   aplicación cambiaba de ancho al cambiar de pestaña: unas pegadas al riel y otras flotando en el
   centro con un hueco a la izquierda. Un salto así se lee como un error, no como una decisión.
   Ahora manda el mismo límite en todas y en un monitor normal eso es el ancho completo. La clase
   .app-wide se conserva porque renderTab la sigue poniendo, pero ya no hace diferencia. */
#app { max-width: 1900px; margin: 0 auto; padding: 24px 20px 80px; }
#app.app-wide { max-width: 1900px; }
.loading { text-align: center; color: var(--text-dim); padding: 60px; }
/* Esqueleto de carga: barras grises con un brillo que recorre de izquierda a derecha, en vez de
   un texto "Cargando…" — se ve un instante al cambiar de pestaña o al abrir la app. */
.skeleton { padding: 8px 0; }
.skeleton-bar {
  height: 14px; border-radius: 6px; margin-bottom: 10px; background: var(--bg-elev);
  background-image: linear-gradient(90deg, var(--bg-elev) 0%, var(--border) 50%, var(--bg-elev) 100%);
  background-size: 200% 100%; animation: skeleton-shine 1.4s ease-in-out infinite;
}
@keyframes skeleton-shine { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

.page-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; gap: 12px; flex-wrap: wrap; }
.page-head h1 { font-size: 23px; margin: 0; }
.page-head .sub { color: var(--text-dim); font-size: 14px; }
/* Logo de la empresa en la barra superior, junto a la marca "Proiectus" (visible en toda la app). */
/* Logo de la empresa debajo de la barra superior, arriba a la izquierda; su ancho se iguala
   por JS al ancho del texto "Proiectus" (ver app.js). */
/* --logo-h la fija app.js (refreshCompanyLogo) midiendo el logo real de la empresa — 220px es
   solo el respaldo mientras esa medición aún no llegó (primer paint). */
.company-logo-row { padding: 8px 20px 0; max-height: var(--logo-h, 220px); overflow: hidden; transition: max-height .18s ease, padding .18s ease, opacity .18s ease; }
/* Replegado automáticamente mientras se trabaja en Presupuesto (ver syncCompanyLogoCollapse en
   app.js) — libera esa franja de alto para ver más partidas sin desplazar. */
.company-logo-row.collapsed { max-height: 0; padding-top: 0; padding-bottom: 0; opacity: 0; }

.stats-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin: 0 0 20px; }
.stat-card {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px 18px;
}
.stat-value { font-size: 27px; font-weight: 800; color: var(--text); line-height: 1.2; }
.stat-label { font-size: 13px; color: var(--text-dim); margin-top: 4px; }
@media (max-width: 720px) { .stats-row { grid-template-columns: repeat(2, 1fr); } }

/* Campos de la portada. Antes esto colgaba de `.proj-filter-bar`, que dejó de existir al
   reescribir la portada: el campo de filtro se quedó SIN estilo ninguno —un input crudo del
   navegador— y por eso desentonaba. El radio sale del token del tema, no de un número a mano. */
.proj-mando input, .proj-mando select,
.proj-mando-extra input, .proj-mando-extra select {
  padding: 7px 10px; border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--bg-panel); color: inherit; font: inherit; font-size: 14.5px;
}
.proj-mando input:focus, .proj-mando select:focus,
.proj-mando-extra input:focus, .proj-mando-extra select:focus {
  outline: none; border-color: var(--accent);
}
.company-logo-btn { position: relative; display: inline-block; background: none; border: 0; padding: 0; cursor: pointer; border-radius: 8px; transition: transform .15s ease, filter .15s ease; }
.company-logo-btn:hover { transform: scale(1.04); filter: drop-shadow(0 4px 14px color-mix(in srgb, var(--accent) 35%, transparent)); }
.company-logo-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.brand-company-logo { display: block; height: auto; object-fit: contain; filter: saturate(1.6) contrast(1.12); }
/* Burbuja de ayuda bajo el logo de empresa y recuadro de invitación a configurarlo: siguen el
   tema activo (--accent/--accent-2) en vez de un azul+violeta fijo, que desentonaba en Alto
   contraste, Terracota y Sepia. */
.company-logo-hint {
  position: absolute; left: 50%; bottom: -8px; transform: translate(-50%, 100%);
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff; font-size: 12px; font-weight: 700; white-space: nowrap;
  padding: 4px 10px; border-radius: 20px; box-shadow: 0 6px 16px rgba(0,0,0,.3);
  animation: logo-hint-bounce 1.6s ease-in-out infinite;
}
:root[data-theme="alto-contraste"] .company-logo-hint { background: #000000; }
@keyframes logo-hint-bounce { 0%, 100% { transform: translate(-50%, 100%) translateY(0); } 50% { transform: translate(-50%, 100%) translateY(-4px); } }
/* Invitación a configurar el logo cuando la empresa aún no tiene uno cargado. */
.company-logo-placeholder {
  display: flex; align-items: center; gap: 10px; min-width: 220px; height: 56px;
  padding: 8px 16px; border-radius: 12px; box-sizing: content-box;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 14%, transparent), color-mix(in srgb, var(--accent-2) 14%, transparent));
  border: 1.5px dashed var(--accent); animation: logo-placeholder-pulse 2.2s ease-in-out infinite;
}
.company-logo-placeholder-icon { font-size: 23px; line-height: 1; }
.company-logo-placeholder-text { font-size: 13px; font-weight: 700; color: var(--accent); line-height: 1.3; text-align: left; }
@keyframes logo-placeholder-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 25%, transparent); }
  50% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--accent) 0%, transparent); }
}

/* ---------- Botones ---------- */
.btn {
  background: var(--bg-elev); color: var(--text); border: 1px solid var(--border);
  padding: 8px 14px; border-radius: var(--radius); cursor: pointer; font-size: 14px; font-weight: 500;
  display: inline-flex; align-items: center; gap: 6px; transition: background .12s;
  white-space: nowrap;
}
/* Antes era un gris-azulado fijo (#2a3644): se veía bien en el tema oscuro pero fuera de
   lugar en los temas claros (light/alto-contraste/terracota/sepia), donde un botón se ponía
   oscuro al pasar el mouse mientras el resto de la ventana seguía clara. color-mix reacciona
   al fondo/texto de cada tema, así el hover se ve consistente en los 5. */
.btn:hover { background: color-mix(in srgb, var(--bg-elev), var(--text) 12%); }
.btn.primary { background: var(--accent-2); border-color: var(--accent-2); color: #fff; }
.btn.primary:hover { background: var(--accent); }
.btn.danger { color: var(--red); }
.btn.danger:hover { background: rgba(248,81,73,.12); }
.btn.small { padding: 4px 9px; font-size: 13px; }
.btn-icon { background: none; border: none; color: var(--text-dim); cursor: pointer; padding: 4px 7px; border-radius: var(--radius); font-size: 15px; }
.btn-icon:hover { background: var(--bg-elev); color: var(--text); }
.btn-icon.danger:hover { color: var(--red); }

/* ---------- Cards / grid proyectos ---------- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
.card {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 18px; cursor: pointer; transition: border-color .12s, transform .12s;
  display: flex; flex-direction: column; height: 100%;
}
.card:hover { border-color: var(--accent); transform: translateY(-2px); }
.card h3 { margin: 0 0 6px; font-size: 17px; }
.card .cliente { color: var(--text-dim); font-size: 13px; margin-bottom: 12px; }
.card .meta { display: flex; justify-content: space-between; align-items: center; font-size: 13px; color: var(--text-dim); margin-top: 12px; }

.meta-dates { display: flex; align-items: center; gap: 6px; }
.meta-dates-arrow { color: var(--text-dim); font-size: 12px; }
.mini-cal {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 6px; overflow: hidden;
  border: 1px solid var(--border); background: var(--bg-elev, var(--bg-panel));
  box-shadow: 0 1px 3px rgba(0,0,0,.15);
}
.mini-cal-month {
  width: 100%; text-align: center; font-size: 9px; font-weight: 700; letter-spacing: .3px;
  color: #fff; background: var(--red, #e5484d); padding: 1.5px 0;
}
.mini-cal-day { font-size: 15px; font-weight: 700; color: var(--text); line-height: 1; margin-top: 2px; }
.mini-cal-empty { width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; border: 1px dashed var(--border); border-radius: 6px; color: var(--text-dim); }

/* Porcentaje de incidencia junto a un importe */
.inc { color: var(--text-dim); font-size: 12px; font-weight: 400; }

/* ---------- Fila de subtotal (presupuesto) ---------- */
.subtotal-row td { background: rgba(79,156,249,.07); font-size: 13px; color: var(--text-dim); border-bottom: 1px solid var(--border); }
.subtotal-row td:nth-child(2) { font-style: italic; }
.subtotal-row td.num { color: var(--accent); font-weight: 700; font-size: 14px; }

/* ---------- Código de proyecto ---------- */
.code-chip {
  display: inline-block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; font-weight: 700; color: var(--accent);
  background: rgba(79,156,249,.12); border: 1px solid rgba(79,156,249,.3);
  border-radius: 6px; padding: 1px 7px; letter-spacing: .5px;
}

/* ---------- Badges de estado ---------- */
.badge { display: inline-block; padding: 2px 9px; border-radius: 20px; font-size: 12px; font-weight: 600; }
/* Ícono pequeño junto al texto de la naturaleza, en los encabezados de grupo de la ficha de costos. */
.cat-badge-icon { display: inline-flex; vertical-align: -2px; margin-right: 4px; }
.cat-badge-icon svg { width: 12px; height: 12px; display: block; }
.badge.activo, .badge.en_curso { background: rgba(63,185,80,.15); color: var(--green); }
.badge.pausado, .badge.pendiente { background: rgba(210,153,34,.15); color: var(--amber); }
.badge.terminado, .badge.hecho { background: rgba(79,156,249,.15); color: var(--accent); }
.badge.enviada { background: rgba(79,156,249,.15); color: var(--accent); }
.badge.pagada { background: rgba(63,185,80,.15); color: var(--green); }
.badge.adicional { background: rgba(244,114,182,.15); color: #f472b6; }
/* `good` y `param` se usaban en fichas típicas sin regla propia: salían con el fondo transparente
   del .badge base mientras el resto de variantes iban en color. */
.badge.good { background: rgba(63,185,80,.15); color: var(--green); }
.badge.param { background: rgba(79,156,249,.15); color: var(--accent); }
.badge.excedente { background: rgba(210,153,34,.15); color: var(--amber); }
.badge.borrador { background: rgba(147,161,176,.18); color: var(--text-dim); }
.badge.pedido { background: rgba(210,153,34,.15); color: var(--amber); }
.badge.recibido_parcial { background: rgba(79,156,249,.15); color: var(--accent); }
.badge.recibido { background: rgba(63,185,80,.15); color: var(--green); }
.badge.cancelado { background: rgba(248,81,73,.15); color: var(--red); }
.badge.autorizada { background: rgba(63,185,80,.15); color: var(--green); }
.badge.rechazada { background: rgba(248,81,73,.15); color: var(--red); }
.badge.cerrada { background: rgba(163,113,247,.15); color: var(--violet); }
.badge.compuesto { background: rgba(163,113,247,.15); color: var(--violet); cursor: help; padding: 1px 5px; }
.badge.bad, .badge.warn { background: rgba(248,81,73,.15); color: var(--red); }
.badge.ok { background: rgba(63,185,80,.15); color: var(--green); }
.badge.homologada { background: color-mix(in srgb, var(--text-dim) 12%, transparent); color: var(--text-dim); }

/* categorias de insumo */
.badge.material { background: rgba(79,156,249,.15); color: var(--accent); }
.badge.mano_obra { background: rgba(163,113,247,.15); color: var(--violet); }
.badge.equipo { background: rgba(210,153,34,.15); color: var(--amber); }
.badge.subcontrato { background: rgba(63,185,80,.15); color: var(--green); }
.badge.herramienta { background: rgba(45,212,191,.15); color: #2dd4bf; }
.badge.flete { background: rgba(244,114,182,.15); color: #f472b6; }

/* Fila de encabezado de grupo dentro de la ficha APU */
.apu-group td { background: var(--bg-elev); border-bottom: 1px solid var(--border); }
.apu-tipo-subgroup td { padding-left: 24px; font-size: 13px; color: var(--text-dim); font-weight: 600; background: transparent; }

/* ---------- Barra de progreso ---------- */
.progress { height: 7px; background: var(--bg-elev); border-radius: 20px; overflow: hidden; }
.progress > span { display: block; height: 100%; background: var(--green); border-radius: 20px; }
.progress > span.warn { background: var(--amber); }
.progress > span.bad { background: var(--red); }

.alerts-box { display: flex; flex-direction: column; gap: 8px; margin-bottom: 22px; }
.alert-row { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-radius: var(--radius); border-left: 3px solid var(--border); background: var(--bg-panel); font-size: 14px; }
.alert-row.bad { border-left-color: var(--red); }
.alert-row.warn { border-left-color: var(--amber); }
.alert-icon { font-size: 16px; }
.alert-name { font-weight: 600; flex: 1 1 auto; }
.alert-date { color: var(--text-dim); font-size: 13px; white-space: nowrap; }

.card-avance { margin-top: auto; padding-top: 10px; }
.card-avance-top { display: flex; justify-content: space-between; font-size: 12.5px; color: var(--text-dim); margin-bottom: 4px; text-transform: uppercase; letter-spacing: .3px; }
.card-avance-top span:last-child { font-weight: 700; color: var(--text); }

/* ---------- Tabs de proyecto ---------- */
/* Barra de ESPACIOS (nivel superior de la navegación del proyecto: Resumen · Planeación ·
   Abastecimiento · Finanzas · Expediente). Más prominente que las sub-pestañas .tab de abajo;
   agrupa los 11 módulos en 5 espacios y es la frontera de venta por módulos. */
.espacios { display: flex; gap: 6px; flex-wrap: wrap; margin: 8px 0 4px; }
/* Control segmentado: las inactivas llevan texto PLENO (no atenuado) y solo contorno — antes iban
   rellenas de gris con texto tenue y en los temas claros el contraste caia a 3.4-4.3, por debajo
   del minimo legible. La activa se distingue por el relleno de acento, no por ser la unica legible. */
.espacio { background: transparent; border: 1px solid var(--border); color: var(--text); padding: 8px 16px; border-radius: 10px; cursor: pointer; font-size: 15px; font-weight: 600; transition: background .12s, color .12s, box-shadow .12s; }
.espacio:hover { background: var(--bg-elev); }
.espacio.active { background: var(--accent); border-color: var(--accent); color: #fff; box-shadow: 0 1px 4px rgba(0,0,0,.14); }
.espacio.active:hover { background: var(--accent); }
.espacio.tab-locked { opacity: .5; cursor: not-allowed; }
.espacio.tab-locked:hover { background: transparent; color: var(--text); }
/* Espacio de un módulo comercial no incluido en el plan (venta por módulos): clic muestra upsell. */
.espacio.espacio-upsell { border-style: dashed; opacity: .7; }
.espacio.espacio-upsell.active { background: none; color: var(--text-dim); border-color: var(--accent); }
/* Tarjeta de upsell que reemplaza el contenido de un espacio no contratado. */
.upsell-card { max-width: 620px; margin: 30px auto; text-align: center; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 14px; padding: 32px 28px; }
.upsell-icono { font-size: 45px; line-height: 1; margin-bottom: 8px; }
.upsell-card h2 { font-size: 20px; margin: 6px 0 10px; }
.upsell-card .sub { margin: 0 auto 14px; }
.upsell-lista { list-style: none; padding: 0; margin: 0 auto 18px; display: inline-block; text-align: left; }
.upsell-lista li { padding: 4px 0; color: var(--text); font-size: 15px; }
.upsell-cta { margin-top: 8px; }
/* Panel "Plan / Módulos" en Empresa: una fila por módulo (núcleo + complementos). */
.plan-modulo { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 10px; margin-bottom: 8px; }
.plan-modulo.plan-nucleo { background: var(--bg-elev, rgba(127,127,127,.08)); }
.plan-modulo-info { flex: 1; min-width: 0; }
.plan-switch { display: flex; align-items: center; gap: 6px; cursor: pointer; white-space: nowrap; font-size: 14px; }
/* Asistente de recomendación de compra: tarjetas de estrategia lado a lado. */
.rec-opciones { display: flex; gap: 12px; flex-wrap: wrap; margin: 12px 0; }
.rec-card { flex: 1 1 300px; border: 1px solid var(--border); border-radius: 12px; padding: 14px 16px; display: flex; flex-direction: column; gap: 8px; }
.rec-card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.rec-badge { font-weight: 700; font-size: 15px; }
.rec-total { font-size: 21px; font-weight: 700; color: var(--accent); }
.rec-metas { display: flex; flex-direction: column; gap: 2px; font-size: 14px; }
.rec-card .btn { margin-top: auto; }
/* Fila de detalle de alquiler de equipo bajo su renglón de compra. */
tr.ci-alquiler td { background: color-mix(in srgb, var(--accent) 6%, transparent); border-top: none; padding-top: 4px; padding-bottom: 6px; }
tr.ci-alquiler input[type="date"] { padding: 3px 5px; }
/* Nueva requisición: lista de resultados con filas seleccionables por doble clic. */
.nr-lista-cab { font-size: 12px; margin: 2px 0 4px; }
.nr-lista { max-height: 240px; overflow: auto; border: 1px solid var(--border); border-radius: 8px; }
.nr-result-row { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-bottom: 1px solid var(--border); cursor: pointer; user-select: none; }
.nr-result-row:last-child { border-bottom: none; }
.nr-result-row:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.nr-result-row .nr-add { color: var(--accent); font-weight: 700; font-size: 19px; opacity: 0; transition: opacity .1s; }
.nr-result-row:hover .nr-add { opacity: 1; }
/* Cuando hay barra de espacios, las sub-pestañas van pegadas debajo sin tanto margen superior. */
.espacios + .tabs { margin-top: 6px; }
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin: 8px 0 20px; flex-wrap: wrap; }
.tab { background: none; border: none; color: var(--text-dim); padding: 10px 16px; cursor: pointer; font-size: 15px; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tab:hover { color: var(--text); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
/* Punto de aviso en una pestaña (ej. Presupuesto/Análisis P.U. con partidas sin pareja). */
.tab-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--red); margin-left: 5px; vertical-align: super; }
/* Pestañas de ejecución (Requisiciones, Compras, Bodega...) deshabilitadas hasta cerrar el presupuesto. */
.tab-locked { opacity: .45; cursor: not-allowed; }
.tab-locked:hover { color: var(--text-dim); }
/* Aviso de presencia: alguien más tiene abierto el mismo proyecto ahora mismo. */
.presence-banner { margin: 8px 0; padding: 8px 12px; border-radius: 8px; font-size: 14px; background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); }
/* Barra de pestañas de capítulos abiertos en Presupuesto (estilo navegador: "Todos" fija + una
   por capítulo abierto, cada una con su ✕ para cerrarla). Reusa .tabs/.tab, con un poco menos de
   margen inferior que la barra de pestañas del proyecto para no repetir tanto espacio. */
.presu-chap-tabbar { margin: 0 0 12px; }
.presu-chap-tab-item { display: inline-flex; align-items: center; gap: 6px; padding-right: 8px; }
.presu-chap-tab-item span { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.presu-chap-tab-item .btn-icon { padding: 1px 4px; font-size: 12px; }

.back-link { color: var(--text-dim); cursor: pointer; font-size: 14px; margin-bottom: 8px; display: inline-block; }
.back-link:hover { color: var(--text); }

/* ---------- Tablas ---------- */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--border); }
th { color: var(--text-dim); font-weight: 600; font-size: 13px; text-transform: uppercase; letter-spacing: .4px; background: var(--bg-elev); position: sticky; top: 0; z-index: 2; box-shadow: 0 1px 0 var(--border); }
tbody tr:nth-child(even) { background: var(--zebra); }
tbody tr:hover { background: var(--bg-elev) !important; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Estimaciones: encabezados e info en una sola línea, sin mayúsculas forzadas (muchas columnas cortas). */
.est-list-table th, .est-list-table td { white-space: nowrap; text-transform: none; padding: 8px 10px; }
.est-list-table td .btn.small, .est-list-table td .inline-edit { white-space: nowrap; }
.table-wrap { overflow-x: auto; background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); max-height: 70vh; overflow-y: auto; }

/* ---------- Stats / KPIs ---------- */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; margin-bottom: 22px; }
.kpi { background: var(--bg-panel); border: 1px solid var(--border); border-left: 3px solid var(--border); border-radius: var(--radius); padding: 16px; display: flex; flex-direction: column; gap: 4px; transition: border-color .15s, transform .15s; }
.kpi:hover { transform: translateY(-1px); border-left-color: var(--accent-2, #5a8cff); }
.kpi.ok { border-left-color: var(--green); }
.kpi.warn { border-left-color: var(--amber); }
.kpi.bad { border-left-color: var(--red); }
.kpi-top { display: flex; align-items: center; justify-content: space-between; }
.kpi .icon { font-size: 19px; opacity: .85; }
.kpi .label { color: var(--text-dim); font-size: 13px; text-transform: uppercase; letter-spacing: .4px; }
.kpi .value { font-size: 25px; font-weight: 700; margin-top: 2px; font-variant-numeric: tabular-nums; }
.kpi .sublabel { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.kpi .value.green { color: var(--green); }
.kpi .value.red { color: var(--red); }
.kpi .value.amber { color: var(--amber); }

.section-title { font-size: 16px; font-weight: 600; margin: 26px 0 12px; }

/* ---------- Gantt ---------- */
.gantt { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; overflow-x: auto; }
.gantt-row { display: grid; grid-template-columns: 200px 1fr; align-items: center; gap: 12px; padding: 6px 0; }
.gantt-label { font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gantt-track { position: relative; height: 22px; background: var(--bg-elev); border-radius: 5px; }
.gantt-bar { position: absolute; height: 100%; background: var(--accent-2); border-radius: 5px; display: flex; align-items: center; padding: 0 6px; font-size: 12px; color: #fff; overflow: hidden; }
.gantt-bar .fill { position: absolute; left: 0; top: 0; height: 100%; background: rgba(63,185,80,.55); border-radius: 5px; }
.gantt-scale { display: grid; grid-template-columns: 200px 1fr; gap: 12px; color: var(--text-dim); font-size: 12px; margin-bottom: 6px; }
.gantt-months { display: flex; justify-content: space-between; }

/* ---------- Gantt avanzado (lista + barras + dependencias + ruta crítica) ---------- */
.gantt2-wrap { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 1px 3px rgba(0,0,0,.05); }
.gantt2 { display: flex; align-items: flex-start; }
/* OJO con el recorte de este panel: `overflow-x: hidden` obliga a `overflow-y: auto`, y eso lo
   convierte en contenedor de scroll. La cabecera de la tabla (sticky, top = alto de la barra
   superior) pasaba entonces a anclarse contra ESTE panel en vez de contra la página: como el panel
   no hace scroll vertical, quedaba empujada 56px hacia abajo, se separaba de su propia fila —que
   se veía vacía— y aterrizaba encima de las filas siguientes, tapando un capítulo entero.
   `overflow-x: clip` recorta igual pero NO crea contenedor de scroll, que es lo que hace falta.
   El ancho y el recorte los pone renderGantt en línea al arrastrar el separador. */
.gantt2-left { flex-shrink: 0; border-right: 1px solid var(--border); background: var(--bg-panel); }
.gantt2-tasks { border-collapse: collapse; font-size: 13px; white-space: nowrap; }
.gantt2-tasks th { text-align: left; padding: 0 10px; color: var(--text-dim); font-size: 12px; text-transform: uppercase; letter-spacing: .3px; border-bottom: 1px solid var(--border); vertical-align: middle; position: sticky; top: 0; z-index: 15; background: var(--bg-panel); }
.gantt2-tasks td { padding: 0 10px; border-bottom: 1px solid var(--border); vertical-align: middle; overflow: hidden; }
.gantt2-tasks tbody tr:nth-child(even) > td { background: color-mix(in srgb, var(--text-dim) 3%, transparent); }
/* La cebra pinta el TD y el tinte de capítulo va en el TR: sin esto, un capítulo que cayera en
   fila par perdía su color. Se deja el TD transparente para que se vea el del TR. */
.gantt2-tasks tbody tr.chap-row > td,
.gantt2-tasks tbody tr.g-chaprow > td,
.gantt2-tasks tbody tr.g-subrow > td { background: transparent; }
.gantt2-tasks tbody tr:hover > td { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.gantt2-tasks td, .gantt2-tasks th { border-bottom-color: color-mix(in srgb, var(--border) 60%, transparent); }
.gantt2-tasks tr.g-crit td:first-child { box-shadow: inset 3px 0 0 var(--red); }
.gantt2-tasks .g-name { max-width: 230px; overflow: hidden; text-overflow: ellipsis; }
.gantt2-split { flex-shrink: 0; width: 5px; align-self: stretch; cursor: col-resize;
  background: color-mix(in srgb, var(--text-dim) 12%, transparent); transition: background .12s ease; }
.gantt2-split:hover, .gantt2-split.dragging { background: var(--accent-2, #5a8cff); }
/* La escala NO puede vivir dentro del panel que hace scroll horizontal: `overflow-x:auto` obliga a
   `overflow-y:auto`, eso convierte al panel en contenedor de scroll, y entonces `position:sticky` de
   la escala se resuelve contra ESE panel (que no hace scroll vertical) en vez de contra la página.
   Resultado: la cabecera de la izquierda se quedaba fija y la escala se iba con el scroll — las dos
   filas desalineadas. Por eso la escala va en su propio envoltorio pegajoso, FUERA del scroller, y
   se desplaza horizontalmente a mano para seguir a las barras. */
.gantt2-rcol { flex: 1; min-width: 120px; display: flex; flex-direction: column; }
.gantt2-right { overflow-x: auto; }
.g-scale-fix { position: sticky; top: 0; z-index: 14; overflow: hidden;
  border-bottom: 1px solid var(--border); background: var(--bg-panel); }
.g-scale { position: relative; will-change: transform; }
.g-tick { position: absolute; top: 0; height: 100%; display: flex; align-items: center; padding-left: 3px; font-size: 11px; color: var(--text-dim); border-left: 1px solid var(--border); white-space: nowrap; }
.g-body { position: relative; }
.g-grid { position: absolute; top: 0; width: 1px; background: var(--border); opacity: .32; }
.g-bar { position: absolute; border-radius: 5px; display: flex; align-items: center; overflow: hidden;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent-2) 88%, #fff) 0%, var(--accent-2) 100%);
  box-shadow: 0 1px 2px rgba(0,0,0,.16), inset 0 0 0 1px rgba(0,0,0,.06);
  transition: box-shadow .12s ease, filter .12s ease; }
.g-bar:hover { box-shadow: 0 3px 8px rgba(0,0,0,.2), inset 0 0 0 1px rgba(0,0,0,.1); filter: brightness(1.05); z-index: 2; }
.g-bar-crit { background: linear-gradient(180deg, color-mix(in srgb, var(--red) 85%, #fff) 0%, var(--red) 100%); }
.g-fill { position: absolute; left: 0; top: 0; height: 100%; opacity: .95;
  background: linear-gradient(180deg, color-mix(in srgb, var(--green) 85%, #fff) 0%, var(--green) 100%);
  box-shadow: 1px 0 0 rgba(0,0,0,.12); }
.g-bar-date { position: absolute; display: flex; align-items: center; font-size: 10px; color: var(--text-dim); opacity: .55; white-space: nowrap; pointer-events: none; font-variant-numeric: tabular-nums; }
.g-bar-date-s { transform: translateX(-100%); padding-right: 4px; }
.g-bar-date-e { padding-left: 4px; }
/* Estructura de capítulos replegables en Tareas y Gantt */
.chap-row { cursor: pointer; background: color-mix(in srgb, var(--accent) 9%, transparent); }
.chap-row:hover { background: color-mix(in srgb, var(--accent) 15%, transparent); }
.chap-row td { border-top: 1px solid var(--border, rgba(127,127,127,.25)); }
.chap-caret { display: inline-block; width: 1em; color: var(--text-dim); font-size: 12px; }
.tree-table .task-name { padding-left: 18px; }
.g-chapbar { position: absolute; border-radius: 2px; background: var(--text-dim); color: var(--text-dim); opacity: .6;
  overflow: visible; height: 9px !important; margin-top: 5px; }
/* Puntas del resumen: los dos triangulitos que marcan dónde abre y cierra el capítulo. */
.g-chapbar::before, .g-chapbar::after { content: ""; position: absolute; top: 100%; width: 0; height: 0;
  border-top: 5px solid currentColor; color: inherit; opacity: .9; }
.g-chapbar::before { left: 0; border-right: 5px solid transparent; }
.g-chapbar::after { right: 0; border-left: 5px solid transparent; }
.g-chapbar .g-fill { background: rgba(255,255,255,.4); }
.g-chaprow td { font-weight: 600; }
.g-subrow td { font-weight: 600; }
.g-subrow { background: rgba(127,127,127,.06); }
.g-subbar { opacity: .42; height: 7px !important; margin-top: 6px; }
.dropdown { position: relative; display: inline-block; }
.dropdown-menu { position: absolute; top: calc(100% + 4px); left: 0; z-index: 50; background: var(--bg-panel, #1c1c22); border: 1px solid var(--border, rgba(127,127,127,.3)); border-radius: 8px; box-shadow: 0 6px 20px rgba(0,0,0,.35); min-width: max-content; overflow: hidden; }
.dropdown-menu[hidden] { display: none; }
/* Menú anclado al borde DERECHO del botón: se usa cuando abrirlo hacia la derecha lo sacaría de la
   pantalla (lo decide solo `ajustarLadoDropdown`). Sin esto, "⋯ Más" en las barras de herramientas
   quedaba con sus opciones cortadas fuera del viewport. */
.dropdown-menu.abre-izquierda { left: auto; right: 0; }
/* Un menú con muchas opciones tampoco debe salirse por abajo: se le pone tope y scroll propio. */
.dropdown-menu { max-height: calc(100vh - 120px); overflow-y: auto; }
.dropdown-menu button { display: block; width: 100%; text-align: left; padding: 9px 14px; background: none; border: 0; color: inherit; font: inherit; cursor: pointer; white-space: nowrap; }
.dropdown-menu button:hover { background: var(--bg-elev, rgba(127,127,127,.15)); }
.notif-badge { position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 3px; border-radius: 8px; background: var(--red, #e5484d); color: #fff; font-size: 11px; font-weight: 700; line-height: 16px; text-align: center; }
/* Sin anclaje propio: cuando cuelga del riel manda la regla del riel (.riel .notif-menu), y esta
   solo aporta el desbordamiento. Antes fijaba `right: 0` y en pantallas estrechas se iba al borde
   derecho de la ventana, lejos del botón que la abrió. */
.notif-menu { max-height: 70vh; overflow-y: auto; }
.notif-menu .notif-empty { padding: 16px; text-align: center; color: var(--text-dim); font-size: 14px; }
/* PENDIENTES, VESTIDO DEL TEMA. Los colores salen de las variables (--red, --amber, --border,
   --text-dim), nunca de rgba sueltos: así la caja sigue al tema claro/oscuro como el resto de la
   aplicación. Cada frente lleva su franja de gravedad —el mismo criterio que la franja «Hoy» de la
   portada, ver nivelPendiente()— y su cuenta a la derecha. */
.notif-menu .caja-riel-head { position: sticky; top: 0; z-index: 2; background: var(--bg-panel); }
/* El título y su cuenta van en la misma línea: el contador caía a un renglón propio. */
.notif-menu .caja-riel-head h3 { white-space: nowrap; }
.notif-menu .notif-cuenta { display: inline-block; margin-left: 6px; padding: 0 7px; border-radius: 999px;
  background: var(--red); color: #fff; font-size: 11.5px; font-weight: 700; vertical-align: middle; }
.notif-menu .notif-group-title { display: flex; align-items: center; gap: 8px;
  margin-top: 6px; padding: 7px 14px 6px; font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--text-dim); background: var(--bg-elev);
  border-top: 1px solid var(--border); border-left: 3px solid var(--border); }
.notif-menu .notif-group-title:first-of-type { margin-top: 0; }
.notif-menu .notif-group-title.n-mal { border-left-color: var(--red); }
.notif-menu .notif-group-title.n-ojo { border-left-color: var(--amber); }
.notif-menu .notif-group-n { margin-left: auto; min-width: 1.5rem; padding: 0 5px; text-align: center;
  border: 1px solid var(--border); border-radius: 999px; font-size: 11px; font-variant-numeric: tabular-nums;
  background: var(--bg-panel); }
.notif-menu .notif-row { display: block; width: 100%; text-align: left; padding: 9px 14px 9px 17px;
  background: none; border: 0; border-top: 1px solid var(--border); border-left: 3px solid transparent;
  color: var(--text); font: inherit; cursor: pointer; white-space: normal; }
.notif-menu .notif-row:hover { background: var(--bg-elev); border-left-color: var(--accent); }
.notif-menu .notif-row-title { font-size: 14px; }
.notif-menu .notif-row-sub { font-size: 12px; color: var(--text-dim); margin-top: 2px; }
.notif-menu .notif-row-split { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
  padding: 9px 14px 9px 17px; border-top: 1px solid var(--border); border-left: 3px solid transparent; }
.notif-menu .notif-row-main { flex: 1 1 auto; min-width: 160px; text-align: left; padding: 0; background: none; border: 0; color: inherit; font: inherit; cursor: pointer; white-space: normal; }
.notif-menu .notif-row-hint { flex-basis: 100%; font-size: 11.5px; color: var(--text-dim); font-style: italic; }
.chk { display: flex; align-items: center; gap: 8px; margin: 8px 0; font-size: 15px; cursor: pointer; }
.chk input { width: 16px; height: 16px; }
.b-edit { width: 100%; font: inherit; padding: 2px 4px; border: 1px solid transparent; border-radius: 4px; background: transparent; color: inherit; }
.b-edit[type="number"] { text-align: right; -moz-appearance: textfield; }
.b-edit[type="number"]::-webkit-inner-spin-button, .b-edit[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
/* Quita las flechas de incremento/decremento de TODAS las celdas numéricas editables de la
   app (Presupuesto, APU, Gantt, estimaciones, control de costos, etc.) — solo estorban en
   celdas de tabla, donde se edita tecleando el valor, no con las flechas. */
input[type="number"] { -moz-appearance: textfield; }
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.b-edit:hover { border-color: var(--border, rgba(127,127,127,.4)); }
.b-edit:focus { border-color: var(--accent-2, #5a8cff); outline: none; background: var(--bg-elev, rgba(127,127,127,.15)); }

/* Presupuesto — vista de tarjetas: cada partida es su propia tarjeta apilada (fondo + borde
   redondeado, como las fichas de Análisis P.U.) en vez de una grilla continua tipo Excel. Sin
   encabezado de tabla compartido no hay dónde arrastrar para redimensionar a mano, así que
   Unidad/Cantidad/P.U./Importe se autoajustan siempre al contenido más largo (calculado en
   app.js) — el mismo diseño sirve en escritorio y en móvil, sin una vista compacta aparte. */
.compact-toolbar { margin-bottom: 8px; }
.presu-cards { display: flex; flex-direction: column; gap: 8px; }
/* LA TARJETA APROVECHA EL ANCHO. Con el panel lateral fuera la fila mide 1400 px y el contenido
   seguía apilado a la izquierda: la descripción en su renglón, las cifras debajo, y media pantalla
   vacía a la derecha. Ahora es una rejilla como la fila de Control por actividad —el texto toma
   todo el espacio que sobra y las cifras se alinean a la derecha—, así el nombre de la partida
   respira y los números quedan en columna entre tarjetas para poder compararlos de un vistazo. */
.presu-card {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 10px 12px 12px;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 24px;
  grid-template-areas: "head head" "desc stats"; align-items: start;
}
.presu-card-head { grid-area: head; }
.presu-card-desc { grid-area: desc; align-self: center; }
.presu-card-stats { grid-area: stats; }
/* En pantalla angosta vuelve a apilarse: con 700 px no hay ancho que repartir y las cifras
   apretadas contra el texto se leen peor que debajo. */
@media (max-width: 900px) {
  .presu-card { grid-template-columns: 1fr; grid-template-areas: "head" "desc" "stats"; }
}
.presu-card .b-edit { padding: 2px 4px; font-size: 13.5px; }
.presu-card-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 4px; }
.presu-card-head input[data-field="clave"] { width: auto; font-weight: 700; }
.presu-card-actions { margin-left: auto; display: flex; gap: 2px; flex-shrink: 0; }
/* LA DESCRIPCIÓN, AL TAMAÑO DE EJECUCIÓN. Es el campo que se lee —el nombre de la actividad— y
   estaba a 13.5 px mientras la fila de Control por actividad usa 17. Con el panel lateral fuera
   sobra el ancho, así que la partida ocupa su renglón entero y se lee de un vistazo, igual en las
   dos pantallas. */
.presu-card-desc { margin-bottom: 0; }
.presu-card-desc .b-edit-desc,
.presu-card-desc .b-edit {
  font-size: 17px; font-weight: 600; line-height: 1.25;
}
.presu-card-stats { display: flex; flex-wrap: wrap; gap: 12px 22px; align-items: flex-end;
  justify-content: flex-end; }
.presu-stat { display: flex; flex-direction: column; gap: 2px; flex-shrink: 0; }
.presu-stat label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .3px; color: var(--text-dim); }
.presu-stat.num { align-items: flex-end; }
.presu-stat.num .b-edit { text-align: right; }
/* Importe: el número que más importa en la tarjeta, con más peso y tamaño (tabular para que
   alinee entre tarjetas). El resto de números se quedan en su tamaño normal. */
.presu-stat strong { font-size: 16px; font-variant-numeric: tabular-nums; }
/* Los valores editables de la tarjeta al mismo paso que las cifras de Ejecución (.obra-cifra b),
   para que las dos pantallas se lean con la misma escala y no parezcan de aplicaciones distintas. */
.presu-card-stats .b-edit { font-size: 15px; }
.presu-card .b-edit[type="number"], .presu-stat.num .b-edit { font-variant-numeric: tabular-nums; }
/* % DE INCIDENCIA: al mismo tamaño que el resto, por peticion del propietario. En un presupuesto
   el peso de una partida NO es un dato de referencia: es lo que dice dónde está el dinero y por
   dónde conviene empezar a apretar. Empequeñecerlo lo escondía justo de quien lo necesita. */
.presu-stat.inc { font-size: 16px; font-variant-numeric: tabular-nums; padding-bottom: 3px; }
.b-edit-desc {
  display: block; width: 100%; resize: none; overflow: hidden; white-space: pre-wrap;
  word-break: break-word; font: inherit; line-height: 1.4; min-height: 1.4em; max-height: 300px;
}
/* Red de seguridad: si el auto-crecimiento (ver autoGrowDesc en app.js) llegara a medir mal por
   algún motivo, que se vea un scroll interno en vez de una tarjeta gigante rompiendo la página. */
.b-edit-desc { overflow-y: auto; }
.presu-pu-cell { display: flex; align-items: center; gap: 6px; justify-content: flex-end; }
.presu-pu-cell .apu-price-stale { flex-shrink: 0; }
.presu-pu-cell .btn-icon { margin-left: 2px; }
/* El asa "⠿" es el único punto fiable para seleccionar (para ⬆/⬇/◀/▶/Supr de la barra de
   herramientas) — el resto de la tarjeta son inputs editables o el punto de arrastre. */
.presu-grip { cursor: grab; color: var(--text-dim); user-select: none; padding: 2px 5px; border-radius: 4px; flex-shrink: 0; }
.presu-grip:hover { background: var(--bg-elev); color: var(--text); }
.presu-grip:active { cursor: grabbing; }
/* Tarjeta seleccionada para mover con los botones ⬆/⬇/◀/▶ de la barra de herramientas. */
.presu-card.row-selected { border-color: var(--accent); box-shadow: inset 3px 0 0 0 var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--bg-panel)); }
/* Estado de una partida segun su relacion con el cierre de presupuesto. Colores tomados del TEMA
   (no hardcodeados) para que sigan cualquier paleta: violeta = adicional (nueva tras el cierre) ·
   ambar = excedente de cantidad. La HOMOLOGADA ya no se pinta: es el estado normal y colorear lo
   normal es ruido. Mismo criterio en las dos vistas — ver .presu-tabla mas abajo. */
/* Homologada = normal: sin color (ver .apu-tarjeta.ficha-homologada). */
.presu-card.budget-adicional:not(.row-selected) { background: color-mix(in srgb, var(--violet) 9%, transparent); }
.presu-card.budget-excedente:not(.row-selected) { background: color-mix(in srgb, var(--amber) 10%, transparent); }
/* Arrastrar tarjetas: se toma desde cualquier parte de la tarjeta (no solo el asa) y al pasar
   sobre otra se marca dónde caería (encima/debajo); al soltar se reordena — si cae entre el
   encabezado de un capítulo y su siguiente encabezado, la tarjeta queda integrada (y sumada)
   dentro de ese capítulo. */
.presu-card[draggable="true"], .presu-chap-bar[draggable="true"] { cursor: grab; }
.presu-card.drag-over-top, .presu-chap-bar.drag-over-top { box-shadow: inset 0 2px 0 0 var(--accent); }
.presu-card.drag-over-bottom, .presu-chap-bar.drag-over-bottom { box-shadow: inset 0 -2px 0 0 var(--accent); }

/* Capítulos/subcapítulos: barra de color sólido a modo de cabecera de sección (no una tarjeta
   blanca más) — banda bien saturada, con el nombre en mayúsculas y texto claro para buen
   contraste; los subcapítulos bajan la saturación pero mantienen la misma lógica. El color usa
   el acento del tema activo (en el tema "Proiectus" da el mismo naranja de siempre, porque ahí
   el acento ES ese naranja). */
.presu-chap-bar {
  --presu-chap-color: var(--accent);
  display: flex; align-items: center; gap: 8px; cursor: pointer;
  /* Lo más angosto posible sin recortar el texto: solo el padding mínimo para que el borde de
     color no toque las letras, nada del "aire" extra que llevaba una tarjeta de tarea. */
  padding: 3px 12px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--presu-chap-color) 55%, var(--bg-panel));
  border-left: 4px solid var(--presu-chap-color);
}
.presu-chap-bar:hover { background: color-mix(in srgb, var(--presu-chap-color) 65%, var(--bg-panel)); }
.presu-chap-bar .b-edit { font-weight: 700; font-size: 14px; text-transform: uppercase; letter-spacing: .3px; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.25); }
.presu-chap-bar input[data-field="descripcion"] { flex: 1; min-width: 0; }
.presu-chap-bar .chap-caret { color: #fff; flex-shrink: 0; }
.presu-chap-bar .presu-grip { color: rgba(255,255,255,.75); }
.presu-chap-bar .presu-grip:hover { background: rgba(255,255,255,.18); color: #fff; }
.presu-chap-bar.nivel-2 {
  background: color-mix(in srgb, var(--presu-chap-color) 22%, var(--bg-panel));
  border-left: 3px solid var(--presu-chap-color);
}
.presu-chap-bar.nivel-2:hover { background: color-mix(in srgb, var(--presu-chap-color) 30%, var(--bg-panel)); }
.presu-chap-bar.nivel-2 .b-edit { font-weight: 600; font-size: 13px; text-transform: none; color: var(--text); text-shadow: none; }
.presu-chap-bar.nivel-2 .chap-caret, .presu-chap-bar.nivel-2 .presu-grip { color: var(--text-dim); }
.presu-chap-bar.nivel-2 .presu-grip:hover { background: var(--bg-elev); color: var(--text); }
.presu-chap-bar.nivel-3 { background: transparent; border-left: 1px solid var(--border); }
.presu-chap-bar.nivel-3 .b-edit { font-weight: 500; font-size: 13px; text-transform: none; }
.presu-chap-bar.nivel-4 { background: transparent; border-left: 1px dashed var(--border); }
.presu-chap-bar.nivel-4 .b-edit { font-weight: 400; font-size: 12.5px; text-transform: none; color: var(--text-dim); }
.presu-chap-bar.row-selected { box-shadow: inset 0 0 0 2px var(--accent); }
/* Etiqueta compacta junto al campo Clave de la barra de capítulo — la barra es de una sola línea
   (a propósito, sin el aire de una tarjeta de tarea), así que va en línea, no apilada como en
   .presu-stat. */
/* El Uniformat del capítulo deja de ser botón y pasa a etiqueta: informa a qué familia pertenece,
   y cambiarlo se hace por el clic derecho, como el resto de acciones de la barra. */
.chap-uniformat { font-size: 11px; letter-spacing: .3px; opacity: .85; flex-shrink: 0; white-space: nowrap; }
.presu-chap-clave-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .3px; opacity: .8; flex-shrink: 0; }
.presu-chap-bar.nivel-2 .presu-chap-clave-label, .presu-chap-bar.nivel-3 .presu-chap-clave-label { color: var(--text-dim); }

.presu-subtotal-line { display: flex; justify-content: flex-end; align-items: baseline; gap: 16px; padding: 2px 12px; font-size: 12px; color: var(--text-dim); }
.presu-total-line { display: flex; justify-content: space-between; padding: 12px; font-size: 15px; border-top: 2px solid var(--border); margin-top: 6px; }
/* Panel de análisis APU (doble clic en P.U. de una partida): drawer lateral fijo, no insertado
   en el flujo de la tabla — con fichas largas, una fila-panel empujaba todo el presupuesto de
   abajo y era difícil distinguir dónde terminaba la ficha. El drawer se queda a la altura de la
   pantalla, con scroll propio, y el presupuesto de fondo no se mueve. */
.presu-apu-drawer-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 90;
  animation: presuDrawerFade .16s ease both;
}
@keyframes presuDrawerFade { from { opacity: 0; } to { opacity: 1; } }
.presu-apu-drawer {
  /* Prioridad a la ficha sobre el presupuesto de fondo: se le da casi todo el ancho de la
     pantalla (deja un margen angosto a la izquierda solo para insinuar que hay algo detrás),
     aunque eso signifique tapar el presupuesto mientras el cajón está abierto. */
  position: fixed; top: 0; right: 0; bottom: 0; width: min(1400px, 96vw); z-index: 91;
  background: color-mix(in srgb, var(--accent) 10%, var(--bg-panel)); border-left: 2px solid var(--accent);
  box-shadow: -8px 0 30px rgba(0,0,0,.35); display: flex; flex-direction: column;
  animation: presuDrawerSlide .18s ease both;
}
@keyframes presuDrawerSlide { from { transform: translateX(100%); } to { transform: translateX(0); } }
.presu-apu-panel-head {
  display: flex; align-items: center; gap: 10px; padding: 14px 16px; flex-wrap: wrap;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border)); flex-shrink: 0;
}
.presu-apu-panel-head .sub { font-size: 13px; }
.presu-apu-panel-head .btn-icon { margin-left: auto; }
.presu-apu-drawer-body { padding: 14px 16px; overflow-y: auto; flex: 1; min-height: 0; }
@media (max-width: 640px) { .presu-apu-drawer { width: 100vw; } }
.col-resizer { position: absolute; top: 0; right: -4px; width: 8px; height: 100%; cursor: col-resize; z-index: 3; }
.col-resizer:hover, .col-resizer.dragging { background: var(--accent-2, #5a8cff); opacity: .5; }
/* En el Gantt esta barra dice en qué MODO estás (marcando avance, siguiendo la cadena de una
   tarea). Tiene que seguir a la vista: en el flujo normal se quedaba arriba y, al bajar por la
   lista, la tapaba la cabecera pegajosa. Su `top` lo calcula renderTareas con el resto de la pila. */
.hint-bar.hint-fija { position: sticky; z-index: 29; margin: 0 0 6px;
  box-shadow: 0 2px 6px rgba(0,0,0,.10);
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-panel)); }
.hint-bar { margin: 8px 0; padding: 8px 12px; border-radius: 6px; background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); font-size: 14px; }
/* Guía paso a paso del Presupuesto (ver presuHintDismissed en app.js): mismo hint-bar, con su
   botón de cierre alineado a la derecha en vez de quedar pegado al texto. */
.presu-hint { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.g-bar-edit { cursor: crosshair; outline: 1px dashed rgba(255,255,255,.5); }
.g-bar-edit .g-fill { pointer-events: none; }
.g-hito { text-align: center; }
.hito-toggle { background: none; border: 0; cursor: pointer; font-size: 16px; color: var(--text-dim); padding: 0 4px; }
.hito-toggle.on { color: var(--accent, #f5a623); }
.g-hito-mark { position: absolute; width: 13px; height: 13px; background: var(--accent, #f5a623);
  transform: rotate(45deg); border-radius: 3px; cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,.22), inset 0 0 0 1px rgba(255,255,255,.35);
  transition: transform .12s ease; }
.g-hito-mark:hover { transform: rotate(45deg) scale(1.18); }
.g-dep-hit:hover { stroke: color-mix(in srgb, var(--accent) 22%, transparent) !important; }
/* Dependencias: la que se señala se engrosa y se opaca, para poder seguirla entre muchas. */
.g-dep:hover .g-dep-line { stroke: var(--accent) !important; stroke-width: 2.4; opacity: 1; }
.g-dep:hover .g-dep-lbl rect { fill: var(--accent); }
.g-dep:hover .g-dep-lbl text { fill: #fff; }
.g-dep-lbl rect { fill: var(--bg-panel); stroke: var(--border); stroke-width: .6; }
.g-dep-crit { stroke-dasharray: none; }
.g-baseline-line { position: absolute; top: 0; width: 0; border-left: 2px dashed var(--red, #f85149); pointer-events: none; z-index: 3; }
.g-baseline-line-lbl { position: absolute; bottom: 2px; transform: translateX(-50%); font-size: 11px; font-weight: 700; color: var(--red, #f85149); white-space: nowrap; }
.g-date { font: inherit; font-size: 12px; padding: 1px 3px; border: 1px solid transparent; border-radius: 4px; background: transparent; color: inherit; cursor: pointer; }
.g-date:hover { border-color: var(--border, rgba(127,127,127,.4)); }
.g-date:focus { border-color: var(--accent-2, #5a8cff); outline: none; background: var(--bg-elev, rgba(127,127,127,.15)); }
.g-dur { width: 46px; font: inherit; font-size: 12px; text-align: right; padding: 1px 3px; border: 1px solid transparent; border-radius: 4px; background: transparent; color: inherit; cursor: text; }
.g-dur:hover { border-color: var(--border, rgba(127,127,127,.4)); }
.g-dur:focus { border-color: var(--accent-2, #5a8cff); outline: none; background: var(--bg-elev, rgba(127,127,127,.15)); }
.avance-total { display: flex; align-items: center; gap: 10px; margin: 10px 0 4px; }
.avance-total-lbl { font-size: 14px; font-weight: 600; color: var(--text-dim); white-space: nowrap; }
.avance-total-bar { flex: 1; height: 16px; border-radius: 8px; background: rgba(127,127,127,.2); overflow: hidden; }
.avance-total-bar > span { display: block; height: 100%; background: var(--green); border-radius: 8px; transition: width .3s; }
.avance-total-pct { font-size: 15px; font-weight: 700; color: var(--green); min-width: 42px; text-align: right; }
.g-baseline { position: absolute; height: 5px; border-radius: 2px; background: var(--red, #ef4444); opacity: .95; cursor: pointer; }
.g-baseline:hover { box-shadow: 0 0 0 2px rgba(239,68,68,.4); }
.g-baseline-ghost { opacity: 0; border: 1px dashed var(--red, #ef4444); background: transparent; height: 6px; }
.g-baseline-ghost:hover { opacity: .7; }
.g-pct { position: relative; z-index: 1; font-size: 11px; color: #fff; padding: 0 5px; font-weight: 600;
  text-shadow: 0 1px 1px rgba(0,0,0,.35); letter-spacing: .2px; }
.gantt2-legend { padding: 7px 12px; border-top: 1px solid var(--border); font-size: 11.5px;
  color: var(--text-dim); display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  background: color-mix(in srgb, var(--text-dim) 4%, transparent);
  border-radius: 0 0 var(--radius) var(--radius); opacity: .9; }
.g-dot { width: 11px; height: 11px; border-radius: 3px; display: inline-block; margin-left: 6px; }

/* ---------- Formularios / modal ---------- */
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center; z-index: 200; padding: 20px; }
.modal { background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; width: 100%; max-width: 520px; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow); }
/* Tarjeta flotante (no modal): sin fondo que bloquee la página, se cierra solo con su botón ✕/Cerrar. */
.floating-card { position: fixed; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow); z-index: 45; min-width: 340px; min-height: 200px; max-height: 90vh; resize: both; overflow: auto; }
.floating-card .modal-head { border-top-left-radius: 12px; border-top-right-radius: 12px; }
.modal-head { display: flex; justify-content: space-between; align-items: center; padding: 18px 20px; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--bg-panel); z-index: 2; border-top-left-radius: 12px; border-top-right-radius: 12px; }
.modal-head h2 { margin: 0; font-size: 18px; }
.modal-body { padding: 20px; }
.modal-foot { padding: 16px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 10px; }

/* ---------- Editar insumos ---------- */
#floating-insumos .modal-head, .modal-book-insumos .modal-head { background: var(--bg-panel); }

.field { margin-bottom: 14px; }
/* Dentro de un modal el espacio es caro (compite con el scroll), asi que el ritmo vertical
   va mas apretado que en las pantallas normales. */
#modal-form .field { margin-bottom: 11px; }
#modal-form textarea { min-height: 58px; }
.field label { display: block; font-size: 13px; color: var(--text-dim); margin-bottom: 5px; font-weight: 500; }
.field input, .field select, .field textarea {
  width: 100%; background: var(--bg); color: var(--text); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 9px 11px; font-size: 15px; font-family: inherit;
}
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--accent); }
/* El width:100% de arriba tambien alcanzaba a los checkbox: la casilla se estiraba a todo el
   ancho y empujaba su texto al extremo derecho. La casilla debe conservar su tamano natural. */
.field input[type="checkbox"], .field input[type="radio"] {
  width: auto; flex: 0 0 auto; padding: 0; margin: 0;
}
.field label.chk { margin-bottom: 0; font-size: 15px; color: var(--text); }
.field textarea { resize: vertical; min-height: 70px; }
.field-row { display: flex; gap: 12px; }
.field-row[hidden] { display: none; }
.field-row .field { flex: 1; }
.field-info { padding: 9px 11px; font-size: 15px; font-weight: 700; color: var(--accent); }
.audit-section { margin-bottom: 24px; }
.audit-section:last-child { margin-bottom: 0; }
.audit-section h3 { display: flex; align-items: center; gap: 8px; font-size: 15px; margin: 0 0 4px; }
.budget-comments-list { display: flex; flex-direction: column; gap: 8px; max-height: 220px; overflow-y: auto; }
.budget-comment {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; padding: 8px 10px;
  background: var(--bg-elev); border-radius: 6px; font-size: 14px;
}
.budget-comment .sub { grid-column: 1 / -1; }
.budget-comment .btn-icon { grid-row: 1 / span 2; align-self: center; }
/* Panel retráctil de auditoría al pie de la hoja de Presupuesto (botón "🔍 Auditoría"). */
/* Mismo lenguaje visual que los demás paneles "insertados" de la hoja (fondo teñido de acento,
   borde grueso) — el panel de insumos de APU y el panel APU inline de Presupuesto. */
.presu-audit-panel {
  margin-top: 20px; padding: 16px; background: color-mix(in srgb, var(--accent) 8%, var(--bg-panel));
  border: 2px solid var(--accent); border-radius: var(--radius); max-height: 60vh; overflow-y: auto;
}
.presu-audit-panel .table-wrap { border: none; }
/* Encabezado fijo (sticky) con el botón de cerrar: el panel tiene su propio scroll interno
   (max-height: 60vh) y puede llevar varias secciones largas — sin esto, cerrarlo significaba
   desplazarse de vuelta hasta arriba del panel para encontrar dónde volver a pulsar "Auditoría"
   en la barra de herramientas. */
.presu-audit-head {
  position: sticky; top: -16px; margin: -16px -16px 12px; padding: 12px 16px;
  display: flex; align-items: center; justify-content: space-between; z-index: 2;
  background: color-mix(in srgb, var(--accent) 16%, var(--bg-panel));
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
}
/* Anchos estandar de modal. Antes cada cuadro llevaba su style="max-width:NNNpx" a mano y
   habia 16 medidas distintas; con estas tres clases todos los dialogos se ven de la misma familia. */
.modal.modal-sm { max-width: 440px; }
.modal.modal-md { max-width: 620px; }
.modal.modal-lg { max-width: 860px; }

/* Aviso de accion destructiva: lo que se va a perder, en una lista que se lee de un golpe. */
.modal-warn {
  background: color-mix(in srgb, var(--red) 8%, var(--bg));
  border: 1px solid color-mix(in srgb, var(--red) 35%, var(--border));
  border-radius: 8px; padding: 10px 12px; margin: 0 0 12px; font-size: 14px;
}
.modal-warn strong { color: var(--red); }
.modal-warn ul { margin: 6px 0 0; padding-left: 18px; }
.modal-warn li { margin: 2px 0; }
.modal-warn .modal-warn-keep { color: var(--text-dim); margin-top: 7px; display: block; font-size: 13px; }

/* Depurar proyecto: un hallazgo resuelto no merece un bloque completo, solo una linea. */
.audit-ok-line {
  display: flex; align-items: center; gap: 7px; padding: 7px 0;
  font-size: 14px; color: var(--text-dim); border-bottom: 1px solid var(--border);
}
.audit-ok-line i { color: var(--green); }
.audit-summary {
  display: flex; align-items: center; gap: 9px; padding: 10px 12px; margin-bottom: 12px;
  border-radius: 8px; font-size: 14px; font-weight: 600;
  background: var(--bg); border: 1px solid var(--border);
}
.audit-summary.tiene-pendientes {
  background: color-mix(in srgb, var(--amber) 10%, var(--bg));
  border-color: color-mix(in srgb, var(--amber) 40%, var(--border));
}

.field-section-title {
  font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
  color: var(--text-dim); margin: 14px 0 8px; padding-top: 10px; border-top: 1px solid var(--border);
}
/* Nota de ayuda compacta: misma informacion que .hint pero sin recuadro, para campos donde
   la aclaracion es secundaria y el recuadro rompia el ritmo vertical del formulario. */
.hint.hint-sm {
  border: none; background: none; padding: 0; margin: 4px 0 0;
  font-size: 12px; line-height: 1.35; display: block;
}
.field-section-title:first-child { margin-top: 0; padding-top: 0; border-top: none; }

.empty { text-align: center; color: var(--text-dim); padding: 40px 20px; background: var(--bg-panel); border: 1px dashed var(--border); border-radius: var(--radius); }

.inline-edit { width: 60px; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 5px; padding: 4px 6px; font-size: 14px; text-align: right; }
.pin { background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 5px; padding: 4px 6px; font-size: 13px; }
.pin:focus { outline: none; border-color: var(--accent); }
.pin.num { text-align: right; font-variant-numeric: tabular-nums; }

.toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; gap: 10px; flex-wrap: wrap; }

/* ---------- APU (diseño plano moderno, respeta el tema claro/oscuro de la app) ---------- */
.apu-card {
  background: var(--bg-panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 24px 26px;
  margin: 0;
  width: 100%;
  /* Ancho generoso para que la tabla de insumos muestre todas sus columnas sin recortar ni
     envolver (antes 900px); max-width:100% del contenedor sigue mandando en pantallas chicas. */
  max-width: 1250px;
  box-sizing: border-box;
}
.apu-card-row { display: flex; align-items: flex-start; margin-bottom: 20px; max-width: 100%; width: 100%; }
/* Vista de pagina: una sola ficha a la vez. Ya NO simula una hoja carta de tamano fijo (ver
   .apu-card.apu-page abajo). El contador de fichas y el modo de vista viven en la barra de
   herramientas, dentro del menu "Vista". */
.apu-page-stage { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.apu-page-nav { display: flex; align-items: center; gap: 6px; }
.apu-card.apu-page {
  /* La ficha se dimensiona por su CONTENIDO, no por el papel. Antes imitaba una hoja carta
     (ancho rigido de 1100px y min-height:1056px) y una ficha de 8 insumos dejaba 397px de blanco
     muerto — el 38% de la tarjeta. El tamano carta se conserva donde si es la metafora correcta:
     al imprimir y al exportar el PDF. De aqui se desprende que el control de zoom sobre, porque
     existia solo para compensar ese ancho rigido. */
  width: 100%; max-width: 1100px;
  margin: 0 auto; border-radius: 4px;
}
/* Envoltorio que centra las fichas (una sola o la lista completa). Ya no aplica zoom. */
.apu-fichas-wrap { display: flex; flex-direction: column; align-items: center; width: 100%; }
/* Modo "pestañas": una fila de pestañas por clave arriba de la hoja actual.
   OJO: este bloque estaba SIN SELECTOR —solo las declaraciones sueltas— así que el navegador lo
   descartaba entero, y con él se perdía también la regla de la ficha homologada que venía
   detrás. Por eso una ficha homologada no se distinguía en nada. */
.apu-tab-clave {
  flex: 0 0 auto; padding: 7px 12px; border-radius: 8px 8px 0 0;
  border: 1px solid var(--border); border-bottom: none; background: var(--bg-elev);
  color: var(--text); cursor: pointer; font: inherit; font-size: 13px; font-weight: 700;
}
/* FICHA HOMOLOGADA: el mismo verde suave que lleva su fila en el Presupuesto, del tema y no de un
   color escrito a mano, para que siga al claro y al oscuro. La franja izquierda es la misma señal
   que usa la fila de la hoja: se reconoce sin leer. */
/* HOMOLOGADA NO SE PINTA. Es el estado normal y sano de una partida —en una obra bien armada lo
   están todas—, así que pintarlas es ruido: 79 renglones de color no informan de nada. El color se
   reserva para lo que SE SALE de lo normal (adicional, excedente, sin ficha). Lo homologado se
   reconoce por su distintivo, no por el fondo. */
.apu-tarjeta.ficha-homologada, .apu-hoja.ficha-homologada {
  border-left: 3px solid var(--border);
}
.apu-index-item.active { background: var(--bg-elev); font-weight: 700; }
.apu-index-group-title {
  font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .3px;
  color: var(--text-dim); padding: 8px 6px 2px; margin-top: 2px; border-top: 1px solid var(--border);
}
.apu-index-group-title:first-child { margin-top: 0; padding-top: 2px; border-top: none; }
.apu-index-group-toggle:hover { color: var(--text); }
.apu-index-group-toggle .chap-caret { font-size: 10px; }
.apu-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.apu-head h3 { margin: 0 0 4px; font-size: 17px; }

.apu-card .table-wrap { background: transparent; border: none; border-radius: 0; box-shadow: none; }
/* table-layout:fixed iba scopeado a .apu-card, asi que la MISMA tabla se comportaba distinto
   dentro del Presupuesto (que no usa .apu-card): alli caia a layout "auto" y el navegador
   ignoraba los anchos calculados en fichaTablaHtml, dando columnas distintas en cada pantalla.
   Va sin scopear para que el ancho que se calcula sea el ancho que se ve, en las dos. */
.apu-grid-table { table-layout: fixed; font-size: 14px; border-collapse: collapse; }
.apu-grid-table th, .apu-grid-table td {
  padding: 8px; box-sizing: border-box;
  border-bottom: 1px solid var(--border);
}
.apu-grid-table th { background: var(--bg-elev); }
.apu-grid-table tr.apu-group td { background: var(--bg-elev); }
.apu-grid-table tr.apu-group .badge { text-transform: uppercase; letter-spacing: .3px; }
.apu-grid-table tr.subtotal-row td { background: var(--bg-elev); }
.apu-grid-table tr.apu-compuesto-row td { background: color-mix(in srgb, var(--violet) 8%, var(--bg-panel)); }
.apu-grid-table tr.apu-compuesto-row .presu-pu-cell { cursor: pointer; justify-content: flex-end; }
.apu-grid-table tr.apu-compuesto-desglose td { background: color-mix(in srgb, var(--violet) 4%, var(--bg-panel)); }
.apu-grid-table td, .apu-grid-table input { font-size: 14px; }
.apu-grid-table th { font-size: 11.5px; letter-spacing: .2px; white-space: normal; color: var(--text-dim); text-transform: uppercase; position: relative; }
.apu-grid-table td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Descripción: el resto de columnas se recorta con "…", pero esta se envuelve en varias líneas
   para que siempre se lea el texto completo (la fila crece de alto lo que haga falta). */
.apu-grid-table td.apu-desc-cell { white-space: normal; overflow: visible; text-overflow: clip; word-break: break-word; }
.apu-grid-table td.apu-actions-cell { overflow: visible; text-overflow: clip; white-space: nowrap; }
.apu-grid-table input.apu-edit-num { padding: 2px 4px; background: transparent; }
/* La celda de P.U. puede llevar el ⚠️ de "precio desactualizado" junto al input. Antes el <td>
   mismo llevaba display:flex — eso lo saca del layout de tabla (deja de estirarse a la altura
   completa de la fila cuando la Descripción ocupa varias líneas) y su borde inferior quedaba
   flotando a media fila, pareciendo un subrayado bajo el número. Por eso el flex va en un <div>
   envoltorio interno (.apu-price-cell-inner) y el <td> se queda como celda de tabla normal. */
.apu-grid-table td.apu-price-cell { overflow: visible; vertical-align: middle; }
/* width:100% es necesario: un contenedor flex en "auto" no se estira solo al ancho del padre
   (usa fit-content, a diferencia de un <div> normal) — sin esto quedaba tan angosto como su
   contenido mínimo y el número se recortaba igual que antes de este arreglo. */
.apu-price-cell-inner { display: flex; align-items: center; justify-content: flex-end; gap: 3px; width: 100%; }
/* "width: auto" cancela el "width: 100%" de input.apu-edit-num (más abajo) — con los dos a la
   vez, flex-basis:0% (de "flex:1") ganaba sobre el 100%, y el input quedaba MÁS ANGOSTO que la
   celda, recortando el número por la derecha ("L 223.0" en vez de "L 223.00"). */
.apu-price-cell-inner input { flex: 1 1 auto; width: auto; min-width: 0; }
.apu-price-stale { cursor: help; flex-shrink: 0; font-size: 13px; }
.apu-grid-table tfoot th { background: transparent; }

.apu-actions { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }

/* ---------- Zona APU: contenedor moderno que agrupa toolbar, catálogo, ficha y panel lateral ---------- */
.apu-zone {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 14px; padding: 18px;
}
/* Encabezado fijo: al bajar por las fichas/partidas, todos los botones quedan siempre a la mano. */
.apu-toolbar {
  position: sticky; top: 0; z-index: 15;   /* 0, no 56: ya no hay barra superior (todo está en el riel) */
  background: var(--bg);
  padding: 14px 18px;
  margin: 0 0 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  /* stretch, no center: al ser columna, el align-items:center que hereda de .toolbar encogia cada
     fila a su contenido y la dejaba centrada — con dos filas de anchos distintos se veia torcido. */
  display: flex; flex-direction: column; align-items: stretch; gap: 10px;
}
/* Dentro de la zona APU (con padding propio) el encabezado se extiende de borde a borde. */
.apu-zone .apu-toolbar { margin: -18px -18px 16px; border-width: 0 0 1px 0; border-radius: 14px 14px 0 0; }
.apu-toolbar-info { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.apu-toolbar-total { font-size: 16px; font-weight: 700; white-space: nowrap; }
.apu-toolbar-actions { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.apu-toolbar-group { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* BOTONERA A TAMAÑO DE DEDO. Al salir la línea de cifras la barra se quedó con espacio de sobra,
   y los botones seguían con la talla que tenían cuando competían por el sitio. Se suben aquí y solo
   aquí — la talla pequeña sigue siendo la correcta dentro de un modal o de una fila. */
.apu-toolbar .btn.small { font-size: 14px; padding: 8px 14px; }
.apu-toolbar .btn-icon { width: 38px; height: 38px; font-size: 18px; }
.apu-toolbar input, .apu-toolbar select { font-size: 14px; padding: 8px 10px; }
/* Los dos campos son lo unico elastico de la fila: se les pone techo para que los seis iconos de
   analisis quepan al lado y no caiga ninguno a una linea suelta. */
.apu-toolbar #presu-search { min-width: 180px; max-width: 240px; }
.apu-toolbar .presu-cap { max-width: 15rem; }
/* Las filas arrancan a la izquierda; lo que va al extremo derecho ya lleva su margin-left:auto.
   Con space-between y un solo grupo ancho la fila quedaba centrada, que no es de donde el ojo
   viene leyendo. */
.apu-toolbar .apu-toolbar-actions { justify-content: flex-start; }
/* Separador sutil entre grupos de una barra de herramientas (acciones primarias | buscar/filtrar |
   contexto de fila seleccionada | menú "⋯ Más") — mismo alto que un botón "small" para alinear. */
.toolbar-sep { width: 1px; align-self: stretch; min-height: 22px; background: var(--border); }
@media (max-width: 720px) { .toolbar-sep { display: none; } }
#apu-ficha-search {
  padding: 7px 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--bg-panel); color: inherit; font: inherit; min-width: 220px;
}

/* Campos editables dentro de la ficha APU */
.apu-edit {
  font-family: inherit; font-size: inherit; color: inherit; background: transparent;
  border: 1px solid transparent; border-radius: 6px; padding: 2px 5px;
}
.apu-edit:hover { border-color: var(--border); }
.apu-edit:focus { outline: none; border-color: var(--accent); background: var(--bg-elev); }
.apu-edit[disabled] { color: inherit; opacity: 1; cursor: not-allowed; }
.apu-edit[disabled]:hover { border-color: transparent; }
.apu-clave-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .3px; opacity: .7; color: var(--text-dim); flex-shrink: 0; }
/* 120px: ancho de un código de catálogo típico (ej. "MAT2205020", 10 caracteres) más su padding. */
.apu-edit-clave { width: 120px; font-weight: 700; }
/* Bloque a todo lo ancho de la ficha (no comparte fila con la clave) para que el nombre completo
   de la partida se lea sin recortarse, sin importar qué tan largo sea. */
.apu-edit-nombre { display: block; width: 100%; box-sizing: border-box; margin-top: 6px; font-weight: 700; font-size: 1.05em; }
.apu-edit-inline { width: 64px; display: inline-block; font-weight: 700; }
input.apu-edit-num { width: 100%; text-align: right; box-sizing: border-box; }

/* ---------- Selector de catálogo por ficha (íconos en el encabezado, debajo de los botones) ----------
   Ancho fijo y compacto (en vez de min-width + etiqueta larga sin recortar) para que las 8 opciones
   (Todos + 6 naturalezas + Compuestos) quepan siempre en una sola fila dentro del ancho de la hoja. */
/* Fluye a una segunda linea cuando no cabe, en vez de scrollear en horizontal: con scroll, los
   importes de las ultimas naturalezas quedaban ocultos y habia que arrastrar para verlos, que es
   justo lo contrario de para lo que esta la fila.
   (Se habia descartado antes, cuando las 8 pildoras pedian 1355px y fluir daba 3 lineas. Al
   reducir las naturalezas sin costo a solo icono bajaron a ~685px, asi que ahora son 2 como mucho.) */
.apu-cat-icons { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; margin-bottom: 4px; }
.apu-cat-icon-btn {
  /* Antes el icono iba apilado SOBRE la etiqueta: 54px de alto por una fila que solo sirve para
     abrir el cajon de insumos. En linea ocupa la mitad y se lee igual de bien. */
  display: flex; flex-direction: row; align-items: center; gap: 5px;
  /* 0 0 auto: la pildora conserva su ancho natural. Con "0 1 auto" se encogia y cortaba las
     etiquetas ("Ma...", "Sub..."); es preferible que la fila scrollee a que no se lean. */
  flex: 0 0 auto; padding: 4px 9px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--bg-elev); color: var(--text);
  cursor: pointer; font: inherit;
}
.apu-cat-icon-btn:hover { border-color: var(--accent); }
.apu-cat-icon-btn.active { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--bg-elev)); }
.apu-cat-icon-btn.violet.active { border-color: var(--violet); background: color-mix(in srgb, var(--violet) 14%, var(--bg-elev)); }
.apu-cat-icon-btn.azul.active { border-color: var(--accent-2); background: color-mix(in srgb, var(--accent-2) 14%, var(--bg-elev)); }
.apu-cat-icon-emoji { line-height: 1; display: flex; }
.apu-cat-icon-label {
  font-size: 12.5px; color: var(--text-dim); white-space: nowrap;
}
/* El subtotal de la naturaleza, dentro de su pildora: la fila es filtro y desglose a la vez. */
.apu-cat-importe {
  font-size: 12.5px; font-weight: 700; color: var(--text); white-space: nowrap;
  padding-left: 6px; margin-left: 2px; border-left: 1px solid var(--border);
}
.apu-cat-icon-btn.active .apu-cat-importe { border-left-color: var(--accent); }
/* Naturaleza que esta ficha no usa: solo el icono, atenuado. Sigue siendo un filtro válido. */
.apu-cat-icon-btn.vacia { padding: 4px 6px; opacity: .45; }
.apu-cat-icon-btn.vacia:hover { opacity: 1; }
/* Separador entre las naturalezas que la ficha usa y las que no. */
.apu-cat-sep {
  flex: 0 0 auto; width: 1px; align-self: stretch; margin: 2px 4px; background: var(--border);
}
/* El boton de agregar queda anclado a la derecha, arriba, aunque las pildoras ocupen dos lineas. */
.apu-cat-row { display: flex; align-items: flex-start; gap: 8px; margin-top: 10px; margin-bottom: 4px; }
.apu-cat-row .apu-agregar-insumo { margin-top: 10px; }
.apu-cat-row .apu-cat-icons { flex: 1 1 auto; min-width: 0; margin-top: 0; margin-bottom: 0; }
.apu-agregar-insumo { flex: 0 0 auto; white-space: nowrap; }
/* Pestañas de naturaleza dentro del cajon de agregar insumos. */
.drawer-nat-tabs {
  display: flex; flex-wrap: wrap; gap: 4px; padding: 8px 10px 0;
  border-bottom: 1px solid var(--border);
}
.drawer-nat-tab {
  padding: 4px 9px; border-radius: 999px 999px 0 0; border: 1px solid transparent; border-bottom: none;
  background: none; color: var(--text-dim); cursor: pointer; font: inherit; font-size: 13px;
}
.drawer-nat-tab:hover { color: var(--accent); }
.drawer-nat-tab.active {
  background: var(--bg-elev); border-color: var(--border); color: var(--text); font-weight: 600;
}
/* Carrito del cajon: barra inferior que solo aparece cuando hay algo marcado. */
.drawer-carrito {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px; margin-top: 8px;
  border-top: 1px solid var(--border); background: var(--bg-panel);
  position: sticky; bottom: 0; font-size: 13px;
}
.drawer-carrito.vacio { display: none; }
.drawer-carrito [data-carrito-cuenta] { margin-right: auto; color: var(--text-dim); }
.cat-drag-chk { flex: 0 0 auto; margin-right: 2px; cursor: pointer; }
.cat-drag-row .cat-drag-name { cursor: pointer; }
/* Acciones de la partida: el menu de tres puntos vive junto al precio, arriba a la derecha. */
.apu-head-right { display: flex; align-items: flex-start; gap: 8px; }
.apu-acciones-menu { left: auto; right: 0; }
.apu-acciones-menu button { display: flex; align-items: center; gap: 8px; }
.apu-acciones-menu button.danger { color: var(--red); }
/* Buscador de insumos por naturaleza (íconos grandes del encabezado de una ficha): cajón lateral
   fijo, igual patrón que .presu-apu-drawer — así la ficha nunca se corre hacia abajo mientras se
   está agregando un insumo, ni compite con ella por ancho el resto del tiempo. z-index por encima
   del drawer de análisis APU de Presupuesto porque puede abrirse anidado dentro de él. */
.apu-insumo-drawer-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 95;
  animation: presuDrawerFade .16s ease both;
}
.apu-insumo-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(420px, 92vw); z-index: 96;
  background: color-mix(in srgb, var(--accent) 10%, var(--bg-panel)); border-left: 2px solid var(--accent);
  box-shadow: -8px 0 30px rgba(0,0,0,.35); display: flex; flex-direction: column;
  animation: presuDrawerSlide .18s ease both;
}
.apu-insumo-drawer-head {
  display: flex; align-items: center; gap: 10px; padding: 12px 14px; flex-shrink: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
}
.apu-insumo-drawer-body { padding: 12px 14px; overflow-y: auto; flex: 1; min-height: 0; }
/* Un solo scroll (el del cajón) en vez de uno anidado dentro de la lista. */
.apu-insumo-drawer-body .cat-drag-list { max-height: none; overflow-y: visible; }
@media (max-width: 640px) { .apu-insumo-drawer { width: 100vw; } }
.apu-head-actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
/* Selector manual de confianza del precio de una ficha (baja/media/alta): 3 pastillas de color
   en un grupo segmentado — clic en una la selecciona directo; clic en la ya activa la limpia. */
.confianza-picker {
  display: inline-flex; gap: 4px; padding: 3px; border-radius: 999px;
  background: var(--bg-elev); border: 1px solid var(--border);
}
.confianza-seg {
  border: none; border-radius: 999px; padding: 6px 14px; font-size: 13px; font-weight: 600;
  color: var(--text-dim); background: transparent; cursor: pointer;
  transition: background .12s ease, color .12s ease, box-shadow .12s ease;
}
.confianza-seg:hover { background: color-mix(in srgb, var(--confianza-color) 16%, transparent); color: var(--text); }
.confianza-seg.active {
  background: var(--confianza-color); color: #fff;
  box-shadow: 0 1px 3px color-mix(in srgb, var(--confianza-color) 50%, transparent);
}
.apu-index-panel {
  width: 340px; flex-shrink: 0; position: sticky; top: 70px;
  max-height: calc(100vh - 90px); overflow-y: auto;
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 8px; display: flex; flex-direction: column; gap: 3px;
}
/* Botón "Fichas" y telón: solo hacen falta cuando el índice es cajón (pantalla angosta). */
.apu-index-btn, .apu-index-cerrar, .apu-index-backdrop { display: none; }
/* En pantalla angosta el índice lateral aplastaba la ficha (quedaban ~100px para la tabla).
   ANTES se ocultaba del todo y con 79 fichas solo quedaba avanzar de una en una; ahora pasa a
   cajón deslizante sobre el contenido, con su botón "Fichas" en la barra. */
@media (max-width: 900px) {
  .apu-index-btn, .apu-index-cerrar { display: inline-flex; }
  .apu-index-panel {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 60;
    width: min(330px, 86vw); max-height: none; border-radius: 0;
    transform: translateX(-102%); transition: transform .18s ease;
    box-shadow: var(--shadow);
  }
  .apu-index-panel.abierto { transform: none; }
  .apu-index-backdrop.abierto {
    display: block; position: fixed; inset: 0; z-index: 59; background: rgba(0, 0, 0, .45);
  }
}
/* La cabecera vive DENTRO del panel, que tiene su propio scroll: al usar el navegador ◀ ▶ (que
   desplaza el panel hasta el capitulo) se iba con el contenido y desaparecia justo cuando la
   estabas usando. Se queda pegada arriba del panel. */
.apu-index-head {
  display: flex; align-items: center; justify-content: space-between; padding: 6px 8px 8px;
  margin-bottom: 4px; border-bottom: 1px solid var(--border); font-size: 13px;
  position: sticky; top: 0; z-index: 3; background: var(--bg-panel);
}
.apu-index-item {
  display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-radius: 6px;
  color: var(--text); text-decoration: none; font-size: 13px;
}
.apu-index-item:hover { background: var(--bg-elev); }
.apu-index-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-drag-panel { border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; overflow: hidden; background: var(--bg); }
.cat-drag-panel-head { display: flex; align-items: center; gap: 6px; padding: 8px 10px; cursor: pointer; background: var(--bg-elev); user-select: none; }
.cat-drag-panel-head:hover { filter: brightness(1.08); }
.cat-drag-caret { font-size: 10px; color: var(--text-dim); width: 10px; }
.cat-drag-count { margin-left: auto; font-size: 12px; color: var(--text-dim); }
.cat-drag-panel-body { padding: 6px; }
.cat-drag-search {
  width: 100%; padding: 6px 9px; border-radius: 7px; border: 1px solid var(--border);
  background: var(--bg-panel); color: var(--text); font: inherit; box-sizing: border-box; margin-bottom: 6px; font-size: 13px;
}
.cat-drag-filters { display: flex; gap: 6px; margin-bottom: 6px; }
.cat-drag-filters select {
  flex: 1; min-width: 0; padding: 5px 7px; border-radius: 7px; border: 1px solid var(--border);
  background: var(--bg-panel); color: var(--text); font: inherit; font-size: 13px;
}
.cat-drag-filters select:disabled { opacity: .5; }
.cat-drag-list { display: flex; flex-direction: column; gap: 4px; max-height: 260px; overflow-y: auto; }
.cat-drag-row {
  display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-radius: 6px;
  border: 1px solid var(--border); background: var(--bg-elev); cursor: grab; font-size: 13px; color: var(--text);
}
.cat-drag-row:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, var(--bg-elev)); }
.cat-drag-row:active { cursor: grabbing; opacity: .6; }
.cat-drag-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-drag-price { color: var(--text-dim); font-size: 12px; white-space: nowrap; }
.cat-drag-fecha { color: var(--text-dim); font-size: 11px; white-space: nowrap; font-family: var(--font-mono, monospace);
  background: color-mix(in srgb, var(--text-dim) 12%, transparent); padding: 0 5px; border-radius: 4px; }
.apu-tipo-wiz-cap { font-size: 13px; font-weight: 700; margin: 10px 2px 2px; color: var(--text); }
.apu-tipo-wiz-cap:first-child { margin-top: 2px; }
.apu-tipo-wiz-sub { font-size: 12px; font-weight: 600; color: var(--text-dim); margin: 4px 2px 2px 10px; }
.apu-tipo-wiz-row { cursor: default; }
.apu-tipo-wiz-row .chk { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.apu-tipo-wiz-cant:disabled { opacity: .4; }

.apu-preview { max-width: 100%; max-height: 260px; border-radius: 8px; border: 1px solid var(--border); margin-top: 10px; display: block; }
.hint { font-size: 13px; color: var(--text-dim); background: var(--bg); border: 1px solid var(--border); border-radius: 7px; padding: 8px 10px; margin: 8px 0; }
/* Selector compacto de modo de importación de presupuesto: 3 opciones cortas en una fila (o
   apiladas si no caben), con el detalle como texto chico en vez de un párrafo aparte por opción. */
.presu-modo-picker { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.presu-modo-opt {
  flex: 1 1 200px; align-items: flex-start; margin: 0; padding: 7px 9px; gap: 6px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-elev);
}
.presu-modo-opt:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, var(--bg-elev)); }
.presu-modo-opt input { margin-top: 2px; flex-shrink: 0; }
.presu-modo-opt strong { font-size: 14px; }
.presu-modo-opt .hint { display: block; font-size: 12px; border: none; background: none; padding: 0; margin: 1px 0 0; }
.presu-modo-subopts { margin-top: 6px; padding: 7px 9px; border: 1px solid var(--border); border-radius: var(--radius); }
.presu-modo-subopts .hint { margin: 6px 0 0; }

.note-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; margin-bottom: 12px; }
.note-card .note-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.note-card h4 { margin: 0; font-size: 15px; }
.note-card .note-body { color: var(--text-dim); font-size: 14px; white-space: pre-wrap; }
.note-card .note-date { font-size: 12px; color: var(--text-dim); }

@media (max-width: 640px) {
  .gantt-row, .gantt-scale { grid-template-columns: 120px 1fr; }
  .field-row { flex-direction: column; gap: 0; }
  /* Presupuesto: la vista de tarjetas es la misma en escritorio y en móvil — las tarjetas
     envuelven sus datos (flex-wrap) en vez de recortar columnas, así que no hace falta ocultar
     nada aquí. */
  .apu-toolbar-actions { flex-direction: column; align-items: stretch; }
  .apu-toolbar-group { flex-wrap: wrap; }
  /* Control de costos: se ocultan las columnas menos críticas (Diferencia/% ejec. en la tabla
     de naturalezas; Referencia en gastos) — igual criterio que ya se usó en Presupuesto. */
  .control-table-cats th:nth-child(4), .control-table-cats td:nth-child(4),
  .control-table-cats th:nth-child(5), .control-table-cats td:nth-child(5) { display: none; }
  .control-table-gastos th:nth-child(4), .control-table-gastos td:nth-child(4) { display: none; }
}

/* Botón de refresco: giro breve al pulsar */
@keyframes spin { to { transform: rotate(360deg); } }
.btn-icon.spin { animation: spin 0.6s linear; }

/* Notificaciones "toast" (errores de red/guardado) — no bloquean como alert(), se apilan abajo
   a la derecha y se autodescartan. */
#toast-root { position: fixed; bottom: 20px; right: 20px; z-index: 300; display: flex; flex-direction: column; gap: 8px; max-width: 360px; }
.toast {
  background: var(--bg-panel); border: 1px solid var(--border); border-left: 4px solid var(--red);
  border-radius: var(--radius); padding: 12px 16px; font-size: 14px; color: var(--text);
  box-shadow: var(--shadow); opacity: 0; transform: translateX(20px); transition: opacity .2s ease, transform .2s ease;
}
.toast.show { opacity: 1; transform: translateX(0); }
.toast-error { border-left-color: var(--red); }
.toast-ok { border-left-color: var(--green); }

/* Buscador global (Cmd/Ctrl+K). */
.gs-result { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 8px; cursor: pointer; }
.gs-result:hover { background: var(--bg-elev); }
.gs-result .badge { flex-shrink: 0; }

/* Guía práctica (pestaña Resumen) — referencia compacta y siempre visible del flujo completo. */
.onboarding-checklist {
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-panel)); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 14px; margin-bottom: 16px;
}
/* La guia es un <details>: su titulo hace de resorte y conserva el aspecto de .section-title. */
.onboarding-checklist > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 7px;
}
.onboarding-checklist > summary::-webkit-details-marker { display: none; }
.onboarding-checklist > summary::before {
  content: "›"; font-size: 18px; line-height: 1; color: var(--text-dim);
  transition: transform .15s; display: inline-block;
}
.onboarding-checklist[open] > summary::before { transform: rotate(90deg); }
.onboarding-checklist > summary:hover { color: var(--accent); }
.onboarding-step i { font-size: 15px; }
.onboarding-step.done i { color: var(--green); }
.onboarding-steps { display: flex; flex-wrap: wrap; gap: 4px 10px; }
.onboarding-step {
  display: flex; align-items: center; gap: 5px; padding: 3px 8px; font-size: 13.5px; cursor: pointer;
  border-radius: 999px; background: var(--bg-panel); border: 1px solid var(--border); white-space: nowrap;
}
.onboarding-step:hover { color: var(--accent); border-color: var(--accent); }
.onboarding-step.done { color: var(--text-dim); cursor: default; text-decoration: line-through; opacity: .65; background: transparent; border-color: transparent; }
.onboarding-step.done:hover { color: var(--text-dim); border-color: transparent; }
.onboarding-step.locked { color: var(--text-dim); cursor: default; opacity: .55; background: transparent; }
.onboarding-step.locked:hover { color: var(--text-dim); border-color: var(--border); }

/* Vista compacta del Gantt (pantallas angostas): lista en vez de línea de tiempo. */
.gantt-compact { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.gc-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; border-bottom: 1px solid var(--border); font-size: 14px; }
.gc-row:last-child { border-bottom: none; }
.gc-group { background: var(--bg-elev); font-weight: 700; text-transform: uppercase; font-size: 12.5px; letter-spacing: .3px; color: var(--text-dim); }
.gc-group.nivel-2 { padding-left: 28px; font-weight: 600; }
.gc-task { padding-left: 20px; }
.gc-clave { flex-shrink: 0; width: 48px; color: var(--text-dim); font-size: 12px; }
.gc-nombre { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gc-fechas { flex-shrink: 0; font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.gc-pct { flex-shrink: 0; width: 34px; text-align: right; font-size: 12px; color: var(--text-dim); }

/* Pantalla de login / creación de cuenta */
.auth-screen { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.auth-card { width: 100%; max-width: 380px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px; padding: 28px 26px; }
.auth-brand { display: flex; align-items: center; gap: 8px; font-size: 21px; font-weight: 700; margin-bottom: 18px; }
.auth-brand .logo { color: var(--accent); }
.auth-tabs { display: flex; border-bottom: 1px solid var(--border); margin-bottom: 18px; }
.auth-tabs .tab { flex: 1; text-align: center; }
.auth-error { color: var(--red); font-size: 14px; margin-bottom: 12px; }
.invite-codigo { cursor: pointer; font-size: 15px; letter-spacing: 1.5px; padding: 2px 6px; border-radius: 6px; background: var(--bg-elev); }
.invite-codigo:hover { background: var(--accent); color: #fff; }

/* Ayuda visual con el orden de columnas para importar Excel (Presupuesto y APU) */
.excel-template-hint { background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; margin-bottom: 14px; }
.excel-template-hint .table-wrap { max-height: 160px; }
.mini-table { width: 100%; border-collapse: collapse; font-size: 12px; white-space: nowrap; }
.mini-table th, .mini-table td { padding: 4px 8px; border-bottom: 1px solid var(--border); text-align: left; }
.mini-table th { color: var(--text-dim); font-weight: 600; background: var(--bg-panel); position: sticky; top: 0; }

/* Tablero de abastecimiento (Kanban por etapas) */

/* Nueva requisición — modal compacto y moderno */
.nrq-body { padding: 16px 20px; display: flex; flex-direction: column; gap: 14px; }
.nrq-search { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.nrq-search input { flex: 1; min-width: 200px; }
.nrq-seg { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; flex-shrink: 0; }
.nrq-seg button { border: none; border-radius: 0; background: transparent; padding: 7px 12px; font-size: 14px; cursor: pointer; color: var(--text); border-left: 1px solid var(--border); }
.nrq-seg button:first-child { border-left: none; }
.nrq-seg button.active { background: var(--accent); color: #fff; }
.nrq-filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.nrq-filters select { font-size: 13px; padding: 5px 8px; max-width: 200px; }
.nrq-filters label { font-size: 12px; color: var(--text-dim); }
.nrq-cart-head { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: var(--text-dim); margin-top: 2px; }
.nrq-count { background: var(--accent); color: #fff; border-radius: 10px; font-size: 12px; padding: 1px 8px; font-weight: 600; }
.nrq-cart { display: flex; flex-direction: column; gap: 6px; max-height: 300px; overflow: auto; }
.nrq-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-elev); }
.nrq-item.warn { border-color: var(--amber); background: color-mix(in srgb, var(--amber) 8%, transparent); }
.nrq-item-main { flex: 1; min-width: 0; }
.nrq-item-name { font-size: 14px; font-weight: 500; }
.nrq-item-meta { font-size: 12px; color: var(--text-dim); margin-top: 1px; }
.nrq-item-qty { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.nrq-item-qty input { width: 78px; text-align: right; }
.nrq-unit { font-size: 12px; color: var(--text-dim); min-width: 24px; }
.nrq-empty { text-align: center; color: var(--text-dim); font-size: 14px; padding: 20px; border: 1px dashed var(--border); border-radius: 8px; }
.nrq-meta { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.nrq-meta .field { flex: 1; min-width: 150px; }

/* Badge de disponibilidad por insumo (semáforo) en resultados de Nueva requisición */
.nr-disp-badge { flex-shrink: 0; font-size: 12px; font-weight: 600; padding: 2px 9px; border-radius: 10px; white-space: nowrap; }
.nr-disp-badge.ok   { background: color-mix(in srgb, var(--green) 18%, transparent); color: var(--green); }
.nr-disp-badge.warn { background: color-mix(in srgb, var(--amber) 22%, transparent); color: var(--amber); }
.nr-disp-badge.low  { background: color-mix(in srgb, var(--red) 18%, transparent);  color: var(--red); }
.nr-disp-badge.none { background: var(--bg); color: var(--text-dim); font-weight: 400; }

/* Nueva requisición — mejoras: sticky, barra, sugerencias, teclado, agrupación, resumen */
.nrq-search { position: sticky; top: 0; z-index: 3; background: var(--bg-panel); padding: 4px 0; }
.nrq-foot { position: sticky; bottom: 0; background: var(--bg-panel); }
.nrq-summary { margin-right: auto; font-size: 14px; color: var(--text-dim); }
.nrq-summary strong { color: var(--text); }
.nrq-bar { height: 4px; border-radius: 3px; background: var(--bg); overflow: hidden; margin-top: 5px; }
.nrq-bar > div { height: 100%; border-radius: 3px; }
.nrq-cart-group { font-size: 12px; font-weight: 600; color: var(--text-dim); text-transform: uppercase; letter-spacing: .3px; margin: 6px 0 2px; }
.nr-en-carrito { flex-shrink: 0; font-size: 12px; font-weight: 600; color: var(--green); padding: 2px 8px; }
.nr-result-row.en-carrito { opacity: .55; cursor: default; }
.nr-result-row.en-carrito:hover { background: transparent; }
.nr-result-row.resaltado { background: color-mix(in srgb, var(--accent) 16%, transparent); outline: 1px solid var(--accent); }

/* Tarjeta de proyecto: foco visible por teclado (es role="button" tabindex=0) */
.card[tabindex]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Estado vacío / onboarding de la portada (empresa nueva sin proyectos) */
.onboarding { text-align: center; max-width: 460px; margin: 48px auto; padding: 32px 24px; border: 1px dashed var(--border); border-radius: 14px; }
.onboarding-icon { font-size: 45px; line-height: 1; margin-bottom: 10px; }
.onboarding h2 { margin: 0 0 6px; }
.onboarding .btn { margin-top: 16px; }

/* ===== TEMA BASE (único) =====
   Antes había tres temas de color (Industrial/Técnico/Sobrio) que solo cambiaban el ACENTO pero
   obligaban a verificar cada componente en 8 combinaciones. Ahora hay UNA base neutra —clara y
   oscura— y el color de acento lo pone la EMPRESA (empresa.color_acento), que es de quien es la
   marca. Se conservan los tres antiguos para no romper preferencias guardadas. */
/* FAENA (jul 2026). La identidad sale de la obra, no del software: hormigon frio de fondo, cal
   para el texto y OXIDO como color de la casa — el del minio y la varilla, no el naranja de cono
   ni el azul que trae por defecto cualquier herramienta tecnica. Nace en OSCURO (es una pantalla
   de campo, con sol encima) y el claro es la misma piel con luz, no otra identidad.
   Conserva el nombre `base` a proposito: asi nadie pierde su preferencia guardada. */
:root[data-theme="base"] {
  --bg: #eae8e3; --bg-panel: #f8f7f4; --bg-elev: #e0ddd6; --border: #d3cfc7;
  --text: #23262a; --text-dim: #6b7076; --accent: #b0501f; --accent-2: #94411a;
  --green: #4d7a36; --amber: #9a6b12; --red: #b23f2c; --violet: #6f5f96;
  --shadow: 0 4px 18px rgba(60,50,40,.10); --zebra: rgba(90,80,65,.045); --zebra-strong: rgba(90,80,65,.07);
  color-scheme: light;
}
:root[data-theme="base"][data-mode="oscuro"] {
  --bg: #22262a; --bg-panel: #2c3137; --bg-elev: #363c43; --border: #414851;
  /* En oscuro el oxido se aclara para TEXTO (--accent) y se conserva saturado para los RELLENOS
     (--accent-2, que es el fondo de .btn.primary con letra blanca). Con un solo tono no salen las
     dos cosas: al oscurecerlo gana el blanco encima y pierde el texto sobre el panel, y al revés.
     Medido: texto 4.87 sobre panel; blanco sobre el relleno 5.23. */
  --text: #e9e7e2; --text-dim: #9aa0a6; --accent: #e5854f; --accent-2: #b0501f;
  --green: #7fae6b; --amber: #dfa72c; --red: #ef7f6b; --violet: #9481b8;
  --shadow: 0 6px 24px rgba(0,0,0,.5); --zebra: rgba(255,255,255,.03); --zebra-strong: rgba(255,255,255,.05);
  color-scheme: dark;
}

/* ===== Temas antiguos (se conservan para preferencias ya guardadas) ===== */

/* Industrial / Obra: gris concreto + naranja seguridad, encabezado carbón. */
:root[data-theme="industrial"] {
  --bg: #eae7e1; --bg-panel: #ffffff; --bg-elev: #e1ddd4; --border: #d6d1c7;
  --text: #26251f; --text-dim: #79736a; --accent: #ea580c; --accent-2: #c2410c;
  --green: #3f6d11; --amber: #a86a10; --red: #b91c1c; --violet: #7a5cb8;
  --shadow: 0 4px 16px rgba(60,50,30,.10); --zebra: rgba(150,120,80,.05); --zebra-strong: rgba(150,120,80,.08);
  color-scheme: light;
}
/* Técnico / Ingeniería: azul acero sobre canvas frío, encabezado azul profundo. */
:root[data-theme="tecnico"] {
  --bg: #eef2f7; --bg-panel: #ffffff; --bg-elev: #e3ebf3; --border: #dbe3ec;
  --text: #17242f; --text-dim: #5c6f80; --accent: #2f6fed; --accent-2: #1f5ad6;
  --green: #1a8f4a; --amber: #b06f14; --red: #d1453b; --violet: #6a5cd6;
  --shadow: 0 4px 16px rgba(30,50,80,.10); --zebra: rgba(60,90,140,.05); --zebra-strong: rgba(60,90,140,.07);
  color-scheme: light;
}
/* Sobrio / Corporativo: neutro cálido con acento verde teal, encabezado claro. */
:root[data-theme="sobrio"] {
  --bg: #fbfbfa; --bg-panel: #ffffff; --bg-elev: #f2f1ee; --border: #ecebe7;
  --text: #1f2733; --text-dim: #7a808a; --accent: #0f766e; --accent-2: #0b5d56;
  --green: #166534; --amber: #b45309; --red: #b91c1c; --violet: #6d5bd0;
  --shadow: 0 4px 18px rgba(30,40,55,.08); --zebra: rgba(60,70,90,.04); --zebra-strong: rgba(60,70,90,.06);
  color-scheme: light;
}

/* La serie categorica de los graficos sigue al MODO, no al tema: lo que decide si un tono se lee
   es el fondo del panel, y ese fondo lo pone claro/oscuro. Dos juegos medidos —uno contra fondo
   claro (#f8f7f4) y otro contra fondo oscuro (#2c3137)— y no un juego invertido a ojo, que es
   como se pierde el contraste justo en el modo que menos se revisa. */
:root[data-theme="base"], :root[data-theme="industrial"],
:root[data-theme="tecnico"], :root[data-theme="sobrio"] {
  --c1: #1f5fb0; --c2: #c04a17; --c3: #0d7a52; --c4: #b354f0;
}
:root[data-theme="base"][data-mode="oscuro"], :root[data-theme="industrial"][data-mode="oscuro"],
:root[data-theme="tecnico"][data-mode="oscuro"], :root[data-theme="sobrio"][data-mode="oscuro"],
:root[data-theme="alto-contraste"][data-mode="oscuro"] {
  --c1: #3987e5; --c2: #d95926; --c3: #199e70; --c4: #9a67a6;
}

/* ===== MODO OSCURO ===== Segundo eje (data-mode="oscuro"): cada tema conserva su ACENTO/carácter
   y solo se cambian los NEUTROS (fondos, bordes, texto). Mayor especificidad que el bloque del tema,
   así gana sin !important. data-mode="claro" (o ausente) usa la variante clara de arriba. */
:root[data-theme="industrial"][data-mode="oscuro"] {
  --bg: #17130f; --bg-panel: #201a15; --bg-elev: #2a231b; --border: #382f25;
  --text: #efe7dc; --text-dim: #a99d8d; --accent: #f97316; --accent-2: #ea580c;
  --shadow: 0 6px 24px rgba(0,0,0,.5); --zebra: rgba(255,220,170,.04); --zebra-strong: rgba(255,255,255,.03);
  color-scheme: dark;
}
:root[data-theme="tecnico"][data-mode="oscuro"] {
  --bg: #0e1620; --bg-panel: #15202c; --bg-elev: #1c2937; --border: #2a3a4a;
  --text: #e6eef6; --text-dim: #93a4b6; --accent: #4f9cf9; --accent-2: #2f6fed;
  --shadow: 0 6px 24px rgba(0,0,0,.5); --zebra: rgba(120,160,220,.05); --zebra-strong: rgba(255,255,255,.03);
  color-scheme: dark;
}
:root[data-theme="sobrio"][data-mode="oscuro"] {
  --bg: #121615; --bg-panel: #1a201e; --bg-elev: #232a28; --border: #2e3734;
  --text: #e6eeeb; --text-dim: #8b9591; --accent: #2dd4bf; --accent-2: #14b8a6;
  --shadow: 0 6px 24px rgba(0,0,0,.45); --zebra: rgba(120,180,170,.05); --zebra-strong: rgba(255,255,255,.03);
  color-scheme: dark;
}
:root[data-theme="alto-contraste"][data-mode="oscuro"] {
  --bg: #000000; --bg-panel: #000000; --bg-elev: #111111; --border: #ffffff;
  --text: #ffffff; --text-dim: #cccccc; --accent: #4d9fff; --accent-2: #77b8ff;
  --green: #33d17a; --amber: #ffbf47; --red: #ff5c5c; --violet: #b98cff;
  --shadow: 0 2px 0 #ffffff; --zebra: rgba(255,255,255,.06); --zebra-strong: rgba(255,255,255,.1);
  color-scheme: dark;
}

/* Encabezado oscuro para Industrial y Técnico (como los mockups) — todo scoped a estos temas */
:root[data-theme="industrial"] .topbar { background: #26251f; border-bottom-color: #3a382f; }
:root[data-theme="tecnico"] .topbar { background: #122334; border-bottom-color: #223a52; }
:root[data-theme="industrial"] .topbar .navbtn,
:root[data-theme="tecnico"] .topbar .navbtn { color: #b7c2cf; }
:root[data-theme="industrial"] .topbar .navbtn:hover,
:root[data-theme="tecnico"] .topbar .navbtn:hover,
:root[data-theme="industrial"] .topbar .navbtn.active,
:root[data-theme="tecnico"] .topbar .navbtn.active { color: #fff; background: color-mix(in srgb, var(--accent) 55%, transparent); border-color: transparent; }
:root[data-theme="industrial"] .topbar .navbtn:hover,
:root[data-theme="tecnico"] .topbar .navbtn:hover { color: #fff; background: rgba(255,255,255,.10); }
:root[data-theme="industrial"] .topbar .btn-icon,
:root[data-theme="tecnico"] .topbar .btn-icon { color: #dce4ec; border-color: rgba(255,255,255,.20); }
:root[data-theme="industrial"] .topbar .btn-icon:hover,
:root[data-theme="tecnico"] .topbar .btn-icon:hover { color: #fff; background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.28); }
:root[data-theme="industrial"] .topbar .btn,
:root[data-theme="tecnico"] .topbar .btn { color: #dce4ec; border-color: rgba(255,255,255,.22); background: transparent; }
:root[data-theme="industrial"] .topbar .btn:hover,
:root[data-theme="tecnico"] .topbar .btn:hover { background: rgba(255,255,255,.10); }
:root[data-theme="industrial"] #brand-text,
:root[data-theme="tecnico"] #brand-text { background: none; -webkit-text-fill-color: #fff; color: #fff; -webkit-text-stroke: 0; }

/* Marca (logo) — el cuadro sigue el acento del tema */
.brand .logo { display: inline-flex; align-items: center; }
.brand .logo svg { display: block; }

/* Íconos de línea (Tabler) — alineación base inline */
/* Iconos Tabler un poco más grandes en toda la app: heredan el tamaño del texto, así que un
   factor em los agranda de forma proporcional a su contexto (sin descuadrar los que llevan un
   font-size propio en línea). */
.ti { vertical-align: -0.17em; line-height: 1; font-size: 1.3em; }
.navbtn .ti, .btn .ti { font-size: 1.3em; }

/* Familia/Subfamilia en la ficha APU: texto secundario, recortado si no cabe (el titulo del
   <td> lleva el valor completo para consultarlo al pasar el raton). */
.apu-clasif-cell {
  font-size: 12.5px; color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Filtrado de insumos dentro de una ficha APU (global + por columna, estilo OPUS). */
.apu-filtro-global { max-width: 190px; font-size: 13px; padding: 5px 9px; }
.apu-filtro-fila th { padding: 3px 4px; background: var(--bg-elev); }
.apu-filtro-col {
  width: 100%; font-size: 12.5px; padding: 3px 6px; border-radius: 5px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
}
.apu-filtro-col:focus { outline: none; border-color: var(--accent); }

/* Selector de catalogo de origen dentro del cajon de insumos. */
.drawer-fuente { padding: 8px 10px 0; font-size: 13px; }
.drawer-fuente > summary { cursor: pointer; color: var(--text-dim); list-style: none; display: flex; align-items: center; gap: 6px; padding: 4px 0; }
.drawer-fuente > summary::-webkit-details-marker { display: none; }
.drawer-fuente > summary:hover { color: var(--text); }
.drawer-fuente-list { display: flex; flex-direction: column; gap: 3px; max-height: 140px; overflow: auto;
  padding: 6px 8px; margin-top: 4px; border: 1px solid var(--border); border-radius: 7px; background: var(--bg-elev); }
.drawer-fuente-list .chk { display: flex; align-items: center; gap: 6px; color: var(--text); white-space: nowrap; cursor: pointer; }
.drawer-fuente-list .chk .sub { color: var(--text-dim); }

/* ---------------------------------------------------------------------------
   Densidad "hoja de calculo" para la tabla de insumos de una ficha APU.
   Filas apretadas + cifras en tipografia tabular, para que los decimales queden
   alineados en columna y quepan mas insumos sin scroll. Se activa desde el menu
   "Vista" y NO es el modo por defecto: comprime bastante y no le sirve a todos.
   --------------------------------------------------------------------------- */
.apu-grid-table.densa th,
.apu-grid-table.densa td { padding: 2px 6px; }
.apu-grid-table.densa td,
.apu-grid-table.densa input { font-size: 13px; }
.apu-grid-table.densa input.apu-edit-num { padding: 0 3px; }
/* Las columnas numericas (cantidad, rendimiento, P.U., importe) en cifras de ancho fijo:
   los decimales quedan alineados verticalmente, como en una hoja de calculo. */
.apu-grid-table.densa td.num,
.apu-grid-table.densa td.num input,
.apu-grid-table.densa td.apu-price-cell input {
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum";
}
.apu-grid-table.densa tr.apu-group td { padding: 1px 6px; }
.apu-grid-table.densa tr.subtotal-row td { padding: 2px 6px; }
.apu-grid-table.densa td.apu-desc-cell { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.apu-grid-table.densa .btn-icon { padding: 2px; }
.apu-grid-table.densa .apu-clasif-cell { font-size: 12px; }

/* Fila del cajon de insumos: un clic la marca, doble clic la agrega. Se hace evidente que la
   fila entera es pulsable, y la marcada se distingue de un vistazo. */
.cat-drag-seleccionable { cursor: pointer; user-select: none; }
.cat-drag-seleccionable:hover { background: var(--bg-elev); }
.cat-drag-seleccionable:has(.cat-drag-chk:checked) {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

/* Aviso de naturaleza fija en el cajon (cuando hay filtro activo) + su salida. */
.drawer-nat-fijo {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px 0;
  font-size: 13px; color: var(--text-dim);
}
.drawer-nat-fijo strong { color: var(--text); }

/* ---------------------------------------------------------------------------
   Analisis P.U. dentro del Presupuesto: al abrirlo con doble clic sobre el P.U., la hoja se
   reduce a la partida elegida (contexto) y el analisis toma TODO el ancho y alto de abajo.
   Antes era un cajon lateral estrecho que tapaba la hoja; asi hay espacio real para trabajar,
   y "Volver" devuelve a la lista con esa misma partida seleccionada.
   --------------------------------------------------------------------------- */
.presu-cards-wrap.en-analisis { flex: 0 0 auto; }
.presu-cards-wrap.en-analisis .presu-cards { border-bottom: 2px solid var(--accent); }
.presu-apu-inline {
  margin-top: 12px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-panel); display: flex; flex-direction: column; min-width: 0;
}
.presu-apu-inline .presu-apu-panel-head {
  display: flex; flex-direction: column; align-items: stretch; gap: 8px; flex-wrap: wrap;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
}
.presu-apu-inline-body { padding: 14px 16px; min-width: 0; }

/* Modo "todos los analisis" dentro de Presupuesto (Vista Lista mudada desde la pestaña APU). */
.presu-apu-ficha { margin-bottom: 18px; }
.presu-apu-ficha-head {
  display: flex; align-items: center; gap: 8px; padding: 6px 0; margin-bottom: 4px;
  border-bottom: 1px solid var(--border); font-size: 14px;
}

/* Aviso de fichas APU sin partida: no es una sugerencia opcional, es algo que hay que resolver. */
.presu-huerfanas {
  background: color-mix(in srgb, var(--amber) 12%, var(--bg-panel));
  border-color: color-mix(in srgb, var(--amber) 45%, var(--border));
}

/* Cabecera del analisis en DOS segmentos: arriba QUE estoy viendo (volver, clave, nombre, P.U.),
   abajo QUE puedo hacer (confianza, filtros, acciones). Antes eran 12 controles en una sola fila
   que envolvia sola, mezclando identidad con herramientas. */
.panel-head-fila { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.panel-head-nombre { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-head-pu { margin-left: auto; white-space: nowrap; }
.panel-head-sep { width: 1px; align-self: stretch; background: var(--border); margin: 0 2px; }

/* Dentro del analisis P.U., la barra del presupuesto y sus avisos se retiran para dar area de
   trabajo. Siguen en el DOM (su cableado no se rompe), solo dejan de ocupar sitio. */
.oculto-en-analisis { display: none !important; }

/* Navegador entre partidas dentro del analisis: recorrer el proyecto sin volver a la hoja. */
.panel-head-nav { display: flex; align-items: center; gap: 4px; }
.panel-head-nav select { max-width: 320px; font-size: 13px; padding: 4px 7px; }

/* Indice de Presupuesto: capitulos plegables con sus partidas. Es el navegador del proyecto y
   se queda a la izquierda TAMBIEN durante el analisis, fuera del area de trabajo. */
.apu-index-partida { padding-left: 22px; font-size: 13px; }
.apu-index-partida.active { background: var(--bg-elev); border-left: 2px solid var(--accent); }
.apu-index-group-toggle { display: flex; align-items: center; gap: 5px; cursor: pointer; }

/* Confianza compacta: boton con el nivel actual (punto de color) que despliega los tres. */
.confianza-punto { display: inline-block; width: 9px; height: 9px; border-radius: 50%; vertical-align: -1px; }
.confianza-menu button { display: flex; align-items: center; gap: 7px; }
.confianza-menu button.active { font-weight: 600; }

/* ---------------------------------------------------------------------------
   Vista TRADICIONAL del presupuesto (rejilla tipo hoja de calculo). Alternativa a la vista
   Proiectus (tarjetas). Comparte campos y cableado: solo cambia el marcado.
   --------------------------------------------------------------------------- */
.presu-tabla { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 14px; }
/* Fuera de la hoja (vista ancha) conserva su ancho minimo; dentro de la hoja manda el papel. */
.presu-cards-wrap > .presu-tabla { min-width: 900px; }
.presu-tabla td { overflow: hidden; }
.presu-tabla td .b-edit { min-width: 0; }
.presu-tabla th, .presu-tabla td {
  border: 1px solid var(--border); padding: 3px 6px; vertical-align: middle;
}
/* Cabecera fija al recorrer la hoja. El `top` lo calcula syncPresuTheadTop() con la altura REAL
   de la barra superior + la de herramientas, que tambien son sticky: con top:0 el encabezado se
   pegaba DETRAS de las dos y parecia que no funcionaba. El z-index queda por debajo de la barra
   de herramientas (15) y por encima de las filas. */
.presu-tabla thead th {
  background: var(--bg-elev); font-size: 11.5px; text-transform: uppercase;
  letter-spacing: .2px; color: var(--text); font-weight: 700;
  position: sticky; top: var(--thead-top, 178px); z-index: 6;
  box-shadow: 0 1px 0 var(--border);
}
.presu-tabla td.num, .presu-tabla th.num { text-align: right; }
.presu-tabla .b-edit { width: 100%; border: none; background: transparent; padding: 2px 3px; }
.presu-tabla .b-edit:focus { outline: 1px solid var(--accent); background: var(--bg); }
.presu-tabla .b-edit-desc { resize: none; min-height: 0; }
.presu-tabla tr.presu-t-chap td { background: var(--bg-elev); font-weight: 600; }
.presu-tabla tr.row-selected td { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.presu-tabla .presu-t-grip { width: 26px; text-align: center; cursor: grab; }
.presu-tabla .presu-t-acc { white-space: nowrap; width: 96px; }
/* Mismos estados en la hoja Tradicional: fondo tenue del tema + una franja izquierda de color
   como marcador rapido al recorrer la lista. La homologada faltaba aqui — ahora esta las dos. */
/* Homologada = normal: sin color. Solo lo que se sale de lo normal lleva franja. */
.presu-tabla tr.budget-adicional:not(.row-selected) td { background: color-mix(in srgb, var(--violet) 7%, transparent); }
.presu-tabla tr.budget-adicional td:first-child { border-left: 3px solid var(--violet); }
.presu-tabla tr.budget-excedente:not(.row-selected) td { background: color-mix(in srgb, var(--amber) 8%, transparent); }
.presu-tabla tr.budget-excedente td:first-child { border-left: 3px solid var(--amber); }
.presu-tabla tr.presu-t-sub td { font-size: 13px; color: var(--text-dim); }

/* La descripcion se envuelve en tantas lineas como haga falta para leerse entera: en una hoja de
   papel el texto no se recorta. Antes iba forzada a una linea porque el textarea crecia sin
   control (filas de 300px) — ahora el alto lo fija ajustarAltoDescripciones() con el scrollHeight
   real, que no puede dispararse porque la columna tiene un ancho calculado. */
.presu-tabla .b-edit-desc {
  overflow: hidden; white-space: normal; resize: none; line-height: 18px; padding: 3px;
  /* Anula el max-height:300px general de .b-edit-desc (pensado para la vista de tarjetas): en la
     hoja el texto se lee ENTERO, aunque la fila crezca. */
  max-height: none; overflow-y: hidden;
}
.presu-tabla .b-edit-desc:focus { position: relative; z-index: 3; background: var(--bg); }

/* El <tbody> reutiliza la clase .presu-cards (para no romper los selectores del cableado), pero
   esa clase es display:flex y rompia la rejilla: las filas dejaban de seguir las columnas. */
.presu-tabla tbody.presu-cards { display: table-row-group; }
/* Titulillos de seccion dentro de un menu desplegable. */
.dropdown-menu .menu-titulo {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-dim);
  padding: 8px 14px 3px; border-top: 1px solid var(--border);
}
.dropdown-menu .menu-titulo:first-child { border-top: none; }

/* La fila de acciones del encabezado del proyecto no saltaba de linea: en movil desbordaba la
   pagina a lo ancho (638px en un viewport de 390) en TODAS las pestañas. */
.page-head > div:last-child { flex-wrap: wrap; }

/* ---------------------------------------------------------------------------
   Invitacion al doble clic sobre el P.U. para entrar (y salir) del Analisis P.U.
   Discreta: el icono solo aparece al pasar el raton o cuando el analisis esta abierto; no
   ocupa sitio (position:absolute) para que no descuadre el ancho de la columna.
   --------------------------------------------------------------------------- */
.presu-pu-abrible { cursor: zoom-in; position: relative; }
.presu-pu-abrible.abierto { cursor: zoom-out; }
.presu-pu-lupa {
  position: absolute; left: 4px; top: 50%; transform: translateY(-50%);
  font-size: 14px; color: var(--text-dim); opacity: 0; transition: opacity .12s;
  pointer-events: none;
}
.presu-pu-abrible:hover .presu-pu-lupa { opacity: .75; }
.presu-pu-abrible.abierto .presu-pu-lupa { opacity: 1; color: var(--accent); }
/* En la rejilla el icono va pegado al borde izquierdo de la celda. */
.presu-tabla .presu-pu-lupa { left: 2px; }

/* ---------------------------------------------------------------------------
   Acabado de la vista Tradicional: rejilla de hoja de calculo.
   Los distintivos (homologada / adicional / excedente) salieron de la celda de Clave — se
   apilaban bajo el numero y ensuciaban la columna. La informacion no se pierde: la FILA ya los
   marca con su color de borde, y ahora tambien van en el tooltip de la clave.
   --------------------------------------------------------------------------- */
.presu-tabla thead th { text-align: center; vertical-align: middle; }
/* Alineadas ARRIBA: la descripción se envuelve en varias líneas y con `middle` el resto de la
   fila —clave, cantidad, importe y los iconos de acción— quedaba flotando a media altura,
   despegado del renglón al que pertenece (en una fila de 121px, el icono de borrar aparecía a 49
   del borde). El encabezado sí sigue centrado. */
.presu-tabla td { vertical-align: top; }
.presu-tabla tr.presu-t-chap td, .presu-tabla tr.presu-t-sub td { vertical-align: middle; }
/* Columnas cortas centradas; la descripcion a la izquierda y las cifras a la derecha, que es
   como se leen bien en un presupuesto. */
.presu-tabla td.presu-t-clave, .presu-tabla td.presu-t-clave .b-edit { text-align: center; }
.presu-tabla td.presu-t-und, .presu-tabla td.presu-t-und .b-edit { text-align: center; }
.presu-tabla td.num .b-edit { text-align: right; }
.presu-tabla td.presu-t-desc .b-edit { text-align: left; }
/* Columna Uniformat (abrible) en la hoja Tradicional: chip con el código, clic para clasificar. */
.presu-tabla td.presu-t-uniformat { text-align: center; }
.presu-uniformat-chip { font: 600 11px/1.4 var(--font-mono, monospace); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent); border: 1px solid transparent;
  border-radius: 5px; padding: 1px 6px; cursor: pointer; white-space: nowrap; }
.presu-uniformat-chip:hover { border-color: var(--accent); }
.presu-uniformat-chip.vacio { color: var(--text-dim); background: none; opacity: .6; }
.presu-uniformat-chip.vacio:hover { opacity: 1; color: var(--accent); }
/* Filas alternas y separacion vertical suave: se sigue la linea sin perderse. */
.presu-tabla tbody tr:hover:not(.presu-t-chap):not(.presu-t-sub) td { background: var(--bg-elev); }
.presu-tabla td, .presu-tabla th { border-color: color-mix(in srgb, var(--border) 55%, transparent); }
.presu-tabla thead th { border-bottom: 2px solid var(--border); }
.presu-t-aviso { color: var(--red); margin-left: 4px; font-size: 13px; }
/* `.presu-tabla th.num` (2 clases) gana por especificidad a `.presu-tabla thead th`, asi que los
   encabezados numericos se quedaban a la derecha: se centran explicitamente. */
.presu-tabla thead th.num { text-align: center; }

/* Estado vacio del presupuesto: en vez de un aviso seco, guia para armar el arbol. */
.presu-vacio {
  max-width: 560px; margin: 30px auto; text-align: center; padding: 28px 24px;
  border: 1px dashed var(--border); border-radius: 12px; background: var(--bg-panel);
}
.presu-vacio-icono { font-size: 35px; color: var(--accent); line-height: 1; margin-bottom: 8px; }
.presu-vacio h3 { margin: 0 0 6px; }
.presu-vacio .sub { margin: 0 auto; max-width: 460px; }
.presu-vacio-acciones { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 18px; }
.presu-vacio-truco { margin-top: 16px !important; font-size: 13px; opacity: .8; }
.presu-vacio kbd {
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: 4px;
  padding: 1px 5px; font-size: 12px; font-family: inherit;
}

/* Creador de arbol en la propia barra del capitulo: discreto, aparece al pasar el raton sobre
   la fila (o siempre, si se navega con teclado). Asi el arbol se arma donde se esta mirando. */
/* Visibles en reposo (no ocultos tras el hover): son la via principal para armar el arbol y
   nadie descubre un boton que no se ve. Al pasar el raton se realzan. */
.chap-crear { display: inline-flex; gap: 3px; opacity: .65; transition: opacity .12s; }
.presu-chap-bar:hover .chap-crear,
.presu-chap-bar:focus-within .chap-crear,
.presu-t-chap:hover .chap-crear,
.presu-t-chap:focus-within .chap-crear { opacity: 1; }
.chap-crear .btn-icon {
  padding: 3px 5px; color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); border-radius: 6px;
}
.chap-crear .btn-icon:hover {
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-color: var(--accent);
}

/* Capitulo del indice: el triangulo pliega, el nombre filtra la hoja. Son dos acciones
   distintas y por eso son dos objetivos distintos, no un unico bloque pulsable. */
.chap-caret-btn { background: none; border: 0; cursor: pointer; padding: 0 3px; color: inherit; font: inherit; }
.chap-caret-btn:hover { color: var(--accent); }
.apu-index-cap-nombre { display: flex; align-items: center; gap: 5px; min-width: 0; flex: 0 1 auto; text-decoration: none; color: inherit; }
.apu-index-cap-nombre:hover .apu-index-name { color: var(--accent); }
.apu-index-group-title.cap-filtrado { background: color-mix(in srgb, var(--accent) 12%, transparent); border-radius: 6px; }

/* Aviso de pantalla sin pestaña propia (ver TABS_OCULTAS): llegaste por un enlace, y esto dice
   por que ya no esta en la barra y por donde se hace ahora. */
.tab-oculta-aviso { margin-bottom: 12px; justify-content: space-between; gap: 12px; }
.tab-oculta-aviso button { flex-shrink: 0; }

/* Cuadro "Explotar hasta" de la Explosion de insumos (mismo reparto que el de OPUS: dos columnas
   de opciones, y las naturalezas en rejilla de tres). */
/* Panel "Opciones de explosion" compacto: dos columnas (nivel | naturalezas) y espaciado ajustado. */
.exp-filtro .field-section-title { margin: 0 0 6px; }
.exp-filtro-top { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 22px; margin-bottom: 10px; align-items: start; }
.exp-nivel { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-bottom: 0; }
.exp-filtro-top .exp-nivel { grid-template-columns: 1fr; gap: 6px; }
.exp-opt { display: flex; align-items: flex-start; gap: 8px; border: 1px solid var(--border); border-radius: 8px;
  padding: 7px 10px; cursor: pointer; background: var(--bg-elev); }
.exp-opt:hover { border-color: var(--border-strong, var(--accent)); }
.exp-opt.sel { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.exp-opt > span { display: flex; flex-direction: column; gap: 1px; }
.exp-opt .sub { font-size: 12px; }
.exp-naturalezas { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px 12px; margin-bottom: 0; }
.exp-naturalezas .chk { gap: 6px; }
.chk.deshabilitada { opacity: .45; cursor: not-allowed; }
.exp-nivel .sub { font-size: 12px; }
@media (max-width: 760px) { .exp-filtro-top { grid-template-columns: 1fr; } }

/* Hoja de escenario de la Explosion: se lee como el presupuesto (capitulos + partidas) pero es
   otra hoja — las cantidades que se editan aqui NO tocan el presupuesto. */
.exp-hoja { max-height: 340px; }
.exp-hoja-tabla { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: 13.5px; }
.exp-hoja-tabla th, .exp-hoja-tabla td { padding: 2.5px 8px; border-bottom: 1px solid var(--border); }
.exp-hoja-tabla thead th { position: sticky; top: 0; background: var(--bg-elev); z-index: 1; font-size: 11.5px; text-transform: uppercase; color: var(--text-dim); }
.exp-hoja-tabla td.num, .exp-hoja-tabla th.num { text-align: right; }
.exp-hoja-tabla tr.exp-cap td { background: var(--bg-elev); font-weight: 600; cursor: pointer; }
.exp-hoja-tabla tr.exp-cap:hover td { background: color-mix(in srgb, var(--accent) 8%, var(--bg-elev)); }
.exp-hoja-tabla tr.exp-cap .chap-caret { font-size: 10px; color: var(--text-dim); margin-right: 3px; }
.exp-hoja-tabla tr.exp-oculto { display: none; }
.exp-hoja-tabla tr.exp-cant-cambiada { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.exp-hoja-tabla tr.exp-cant-cambiada input { font-weight: 600; color: var(--accent); }

/* Resumen del proceso de explosion (parametros + cantidades de investigacion). */
.exp-resumen { border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: 8px;
  padding: 9px 12px; margin-bottom: 14px; font-size: 13.5px; display: flex; flex-direction: column; gap: 4px; }
.exp-resumen-linea { display: flex; gap: 7px; align-items: baseline; flex-wrap: wrap; }

/* Modal "Campos a imprimir": lista de columnas en recuadro, con toggle "Todas". */
.pf-todas { margin-bottom: 8px; }
.pf-cols { display: flex; flex-direction: column; gap: 4px; max-height: 320px; overflow: auto;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-elev); }
.pf-cols .chk { color: var(--text); }
/* Las listas de casillas en una sola columna estiraban el modal de impresión a lo largo de dos
   pantallas. En rejilla caben lo mismo en un tercio del alto. */
.pf-cols.pf-rejilla { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 2px 12px; max-height: none; }
/* Modal de impresión: mismas piezas del tema, solo más apretadas. */
.op-imprimir .field-section-title { margin: 10px 0 6px; padding-top: 8px; }
.op-imprimir .field-section-title:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.op-imprimir .field { margin-bottom: 6px; }
.op-imprimir .op-nota { margin: 8px 0 0; display: flex; gap: 6px; align-items: flex-start; font-size: 12.5px; }

/* Distribucion por naturaleza: barra proporcional + leyenda (donde esta el costo). */
.exp-dist { margin-bottom: 14px; }
.exp-dist-bar { display: flex; height: 12px; border-radius: 6px; overflow: hidden; background: var(--bg-elev); }
.exp-dist-bar span { display: block; min-width: 2px; }
.exp-dist-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 8px; font-size: 13px; }
.exp-dist-chip { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; color: var(--text); }
.exp-dist-chip .sub { color: var(--text-dim); }
.exp-dist-dot { width: 9px; height: 9px; border-radius: 2px; display: inline-block; flex: none; }

/* Tabla de explosion compacta: subtotal en la cabecera del grupo, filas densas. */
.exp-tabla { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.exp-tabla th, .exp-tabla td { padding: 3px 8px; border-bottom: 1px solid var(--border); }
.exp-tabla thead th { position: sticky; top: 0; background: var(--bg-panel); z-index: 1; font-size: 11.5px;
  text-transform: uppercase; letter-spacing: .02em; color: var(--text-dim); }
.exp-tabla td.num, .exp-tabla th.num { text-align: right; white-space: nowrap; }
.exp-tabla td.exp-cod { color: var(--text-dim); font-family: var(--font-mono, monospace); font-size: 12px; white-space: nowrap; }
.exp-tabla tr.exp-grp td { background: var(--bg-elev); cursor: pointer; padding: 5px 8px; }
.exp-tabla tr.exp-grp:hover td { background: color-mix(in srgb, var(--accent) 8%, var(--bg-elev)); }
.exp-tabla tr.exp-grp .exp-grp-n { display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 4px;
  font-size: 12px; color: var(--text-dim); background: color-mix(in srgb, var(--text-dim) 14%, transparent); border-radius: 9px; }
.exp-tabla tr.exp-grp .exp-grp-sub { float: right; font-size: 13.5px; }
.exp-tabla tfoot th { padding: 7px 8px; border-top: 2px solid var(--border); font-size: 14px; }

/* ---------- Vista Tradicional del presupuesto: una hoja de papel ----------
   El ancho y el margen salen del papel configurado en Empresa > Papelería (--hoja-ancho /
   --hoja-margen), no de un tamaño inventado: lo que se ve es lo que se imprime. El índice de
   capítulos no se pinta en esta vista — la hoja es el documento, y un documento no lleva
   navegador lateral. */
.presu-hoja {
  width: var(--hoja-ancho, 816px);
  max-width: 100%;
  margin: 0 auto 18px;
  padding: var(--hoja-margen, 45px);
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 3px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .13), 0 10px 30px rgba(0, 0, 0, .07);
}
.presu-hoja-cab {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding-bottom: 8px; margin-bottom: 12px; border-bottom: 2px solid var(--text);
}
.presu-hoja-cab strong { font-size: 16px; }
.presu-hoja-pie {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-top: 12px; padding-top: 8px; border-top: 2px solid var(--text); font-size: 15px;
}
/* La hoja ya tiene su propio marco: el contenedor no debe añadir otro ni recortarla. */
.presu-cards-wrap:has(.presu-hoja) { max-height: none; overflow: visible; background: none; border: 0; padding: 0; }
@media (max-width: 900px) {
  .presu-hoja { padding: 16px; border-radius: 0; box-shadow: none; }
  /* En un movil no cabe una hoja de papel: la tabla conserva sus anchos calculados y se desplaza
     dentro de la hoja. Aqui si se pierde la cabecera fija, pero es preferible a una tabla que se
     sale de la pantalla. */
  .presu-hoja-cuerpo { overflow-x: auto; }
}
/* Sin overflow propio: las columnas se calculan para caber en el papel, y ademas un contenedor
   con scroll aqui romperia la cabecera fija (el sticky se anclaria a el, que no tiene alto
   limitado, en vez de a la pagina). */

/* Hoja del Análisis P.U.: mismo papel que la del presupuesto pero APAISADO — una ficha tiene 8-10
   columnas y en vertical no se lee. Hereda de .presu-hoja el marco, el margen y la sombra. */
.apu-hoja { margin-bottom: 0; }
/* Dentro de la hoja la descripción del insumo se envuelve, como en el presupuesto: en papel el
   texto no se recorta. Fuera de la hoja sigue vigente el recorte con "…" de la vista compacta. */
.apu-hoja .apu-grid-table td.apu-desc-cell,
.apu-hoja .apu-grid-table.densa td.apu-desc-cell {
  white-space: normal; overflow: visible; text-overflow: clip; word-break: break-word;
}
.apu-hoja .apu-grid-table td { vertical-align: top; }
/* La tabla se calcula para caber en el papel, así que no debe imponer su propio mínimo. */
.apu-hoja .apu-grid-table { min-width: 0 !important; }
.apu-hoja .table-wrap { max-height: none; overflow: visible; }
/* Con Familia/Subfamilia activadas una ficha puede pedir mas ancho del que da el papel; en ese
   caso se desplaza DENTRO de la hoja en vez de deformarla. Por eso aqui no se fija la cabecera:
   un contenedor con scroll capturaria el sticky (misma razon explicada en la hoja del
   presupuesto), y una ficha son ~10 filas, no 80. */
.apu-hoja .presu-hoja-cuerpo { overflow-x: auto; }
/* El triángulo de capítulo invita a pulsarlo también en la vista Tradicional. */
.presu-tabla tr.presu-t-chap { cursor: pointer; }
.presu-tabla tr.presu-t-chap .chap-caret { display: inline-block; width: 12px; }
.presu-tabla tr.presu-t-chap input, .presu-tabla tr.presu-t-chap textarea { cursor: text; }

/* Vista Tradicional: la fila de capítulo es una BANDA de una sola línea, como en un presupuesto
   impreso — antes medía 51px porque los botones de inserción y el campo la estiraban. Y el color
   de fondo queda solo aquí: las partidas y los subtotales van sobre papel limpio (por eso se
   quitaron la cebra y el fondo del subtotal). */
.presu-tabla tr.presu-t-chap td { padding: 1px 6px; height: 24px; line-height: 20px; }
.presu-tabla tr.presu-t-chap .b-edit { padding: 0 3px; height: 20px; line-height: 20px; }
/* Los tres iconos de accion (Uniformat, historial, borrar) median 28px cada uno: 103px en una
   celda con 77 utiles, asi que el de BORRAR se veia cortado por la mitad. Compactados aqui — en
   una hoja de papel el ancho es escaso y estos botones no necesitan area de dedo. */
.presu-tabla .presu-t-acc .btn-icon { padding: 1px 3px; line-height: 18px; }
.presu-tabla tr.presu-t-chap .btn-icon { padding: 0 2px; line-height: 18px; }
.presu-tabla tr.presu-t-chap .presu-grip { line-height: 20px; }
/* La celda de clave del capítulo lleva el triángulo ▶/▼ (12px) y el campo. Con el campo a
   width:100% no cabían juntos y el campo saltaba a una SEGUNDA línea: por eso la fila medía 45px
   en vez de 24. Se le descuenta el ancho del triángulo. (No se usa display:flex en el <td>: eso
   lo saca del layout de tabla — mismo motivo documentado en .apu-price-cell.) */
.presu-tabla tr.presu-t-chap td:nth-child(2) .b-edit { width: calc(100% - 18px); }
.presu-tabla tr.presu-t-chap td:nth-child(2) { white-space: nowrap; }

/* Anula la cebra GLOBAL (`tbody tr:nth-child(even)`, que tiñe todas las tablas de la app) dentro
   de la hoja: el color queda solo en las bandas de capítulo. Iba en el <tr>, no en el <td> — por
   eso no bastó con quitar la regla propia del presupuesto. */
.presu-tabla tbody tr:nth-child(even) { background: none; }
/* Misma razón que en la hoja del presupuesto: el color queda solo en los encabezados de grupo
   (naturaleza) y en las filas de subtotal, no franja sí franja no. Afecta también a la lista de
   "todos los análisis", que usa esta misma tabla. */
.apu-grid-table tbody tr:nth-child(even) { background: none; }
/* Con el análisis abierto, la hoja del presupuesto queda como tira de CONTEXTO: solo el
   encabezado de columnas y la partida elegida, sin margen de papel arriba y abajo. */
.presu-hoja.hoja-contexto { padding-top: 10px; padding-bottom: 10px; margin-bottom: 10px; }
/* Contador de partidas del capítulo: pegado a su descripción, no empujado al borde derecho —
   ahí quedaba suelto y, con nombres largos que se envuelven, a distinta altura que el texto. */
.apu-index-cuenta {
  flex-shrink: 0; font-size: 11.5px; color: var(--text-dim);
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: 9px; padding: 0 6px; line-height: 15px; margin-left: 4px;
}
/* En la fila de capítulo el nombre no debe estirarse: si crece, empuja el contador hasta el borde
   derecho y queda suelto en vez de junto a la descripción. */
.apu-index-cap-nombre .apu-index-name { flex: 0 1 auto; min-width: 0; }
/* Cerrar el análisis del compuesto: una ✕ al final de su propia cabecera, como se cierra una
   ventana. Sustituye al botón "Volver a la ficha" — al cerrarlo se vuelve solo a la ficha. */
.comp-cerrar { margin-left: 8px; }
.comp-cerrar:hover { color: var(--red); }

/* Selección de filas en la ficha (columna "C") para copiarlas a otra partida. */
.apu-grid-table th.apu-sel-col, .apu-grid-table td.apu-sel-col { text-align: center; padding-left: 2px; padding-right: 2px; }
.apu-grid-table tr.fila-sel td { background: color-mix(in srgb, var(--accent) 14%, transparent); }
/* Va ARRIBA de la ficha, no al pie: con fichas largas la barra quedaba fuera de la pantalla justo
   despues de marcar las filas, que es cuando hace falta. */
.apu-sel-barra {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 10px; padding: 8px 12px; border: 1px solid var(--accent);
  border-radius: 9px; background: color-mix(in srgb, var(--accent) 8%, transparent);
}
/* Interruptor de selección, junto a las naturalezas. */
.apu-sel-toggle { flex-shrink: 0; }

/* Divisor entre los grupos de la barra superior (navegar+buscar · utilidades · apariencia+sesión):
   hace visible la agrupación lógica sin ruido. */
.topbar-div { width: 1px; align-self: stretch; margin: 4px 2px; background: var(--border); opacity: .7; }
:root[data-theme="industrial"] .topbar .topbar-div,
:root[data-theme="tecnico"] .topbar .topbar-div { background: rgba(255,255,255,.16); }

/* APU paramétrica: panel de Dimensiones del detalle. */
.apu-dim { border: 1px solid var(--border); border-radius: 10px; margin: 0 0 10px; overflow: hidden; }
.apu-dim-head { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; padding: 8px 12px; background: var(--bg-elev); border: none; color: inherit; cursor: pointer; font-size: 14px; }
.apu-dim-head:hover { background: color-mix(in srgb, var(--accent) 8%, var(--bg-elev)); }
.apu-dim-cuenta { font-size: 11.5px; background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); border-radius: 9px; padding: 0 7px; line-height: 16px; }
.apu-dim-hint { font-weight: 400; }
.apu-dim-hint code, .apu-dim code { font-family: var(--font-mono, monospace); font-size: 12.5px; background: color-mix(in srgb, var(--accent) 10%, transparent); padding: 1px 4px; border-radius: 4px; }
.apu-dim-body { padding: 8px 10px; }
.apu-dim-tabla { border-collapse: collapse; margin-bottom: 6px; width: auto; }
.apu-dim-tabla th { font-size: 11px; text-transform: uppercase; letter-spacing: .3px; color: var(--text-dim); text-align: left; padding: 1px 6px 3px; font-weight: 600; }
.apu-dim-tabla th.num { text-align: right; }
.apu-dim-tabla td { padding: 1px 6px; white-space: nowrap; }   /* columnas al contenido, no estiradas */
/* Anchos por campo: el número (lo que se cambia) prominente; la descripción absorbe el resto y va discreta. */
.apu-dim-tabla .apu-edit { width: 100%; }
.apu-dim-tabla input[data-dim-nombre] { width: 88px; font-family: var(--font-mono, monospace); }
.apu-dim-tabla input[data-dim-valor] { width: 78px; text-align: right; font-weight: 600; }
.apu-dim-tabla .fm-desc-cell { white-space: nowrap; }   /* se ajusta al texto, no se estira */
.apu-dim-tabla input[data-dim-desc] { color: var(--text-dim); font-size: 13px; }
.apu-dim-tabla select[data-dim-compuesto] { min-width: 220px; }
.apu-dim-tabla .fm-celda-letra { text-align: left; font-weight: 700; font-style: italic; color: var(--accent); padding-left: 8px; white-space: nowrap; }
.apu-dim-tabla tr.fm-fila-sel td { padding-bottom: 4px; }
/* Rendimiento definido por fórmula: se distingue del número normal. */
.apu-grid-table input.tiene-formula { color: var(--accent); font-family: var(--font-mono, monospace); font-size: 12.5px; }

/* Asistente "Detalle paramétrico (IA)". */
.param-cabecera { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.param-cabecera label { display: flex; align-items: center; gap: 6px; font-size: 14px; }
.param-tabla { width: 100%; border-collapse: collapse; margin: 6px 0; }
.param-tabla th { font-size: 11.5px; text-transform: uppercase; color: var(--text-dim); text-align: left; padding: 2px 6px; font-weight: 600; }
.param-tabla th.num, .param-tabla td.num { text-align: right; }
.param-tabla td { padding: 2px 6px; border-bottom: 0.5px solid var(--border); }
.param-tabla .apu-edit, .param-tabla select { width: 100%; }
.ti.spin { display: inline-block; animation: spin 0.9s linear infinite; }
/* Los inputs de descripción de dimensiones toman el ancho de su propio texto (ver ajustarDescDims). */
.apu-dim-tabla input[data-dim-desc] { width: var(--w, 22ch); max-width: 46ch; box-sizing: content-box; }
/* Homologación de insumos contra el catálogo de la empresa (asistente paramétrico). */
.homo-badge { display: inline-block; font-size: 11px; font-family: var(--font-mono, monospace); border-radius: 5px; padding: 1px 5px; white-space: nowrap; }
.homo-alta { background: color-mix(in srgb, var(--green, #2e7d32) 18%, transparent); color: var(--green, #2e7d32); }
.homo-media { background: color-mix(in srgb, var(--amber, #b8860b) 20%, transparent); color: var(--amber, #b8860b); }
.homo-baja { background: color-mix(in srgb, var(--red, #c62828) 16%, transparent); color: var(--red, #c62828); }
.homo-nuevo { background: color-mix(in srgb, var(--text-dim) 16%, transparent); color: var(--text-dim); }
.homo-traza { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; line-height: 1.3; }
/* Diccionario de homologación (Catálogos → Homologación). */
.homo-tabla .homo-nombre { font-size: 13px; }
.homo-tabla tr.homo-huerfano { opacity: 0.65; }
.homo-check { display: flex; justify-content: center; }

/* Formatos de detalle: dibujo cotado + tabla de datos (APU paramétrica). */
.fm-layout { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.fm-dibujo { flex: 0 0 auto; text-align: center; padding: 8px 10px; background: color-mix(in srgb, var(--accent) 5%, var(--bg-panel)); border: 1px solid var(--border); border-radius: 10px; }
.fm-datos { flex: 1 1 auto; min-width: 0; }
.fm-svg { width: 158px; height: auto; display: block; }
.fm-titulo { font-size: 12px; font-weight: 600; margin-top: 5px; }
.fm-usos { font-size: 11px; max-width: 170px; margin: 0 auto; }
.fm-concreto { fill: color-mix(in srgb, var(--text-dim) 8%, transparent); stroke: var(--text); stroke-width: 1.3; }
.fm-estribo { fill: none; stroke: var(--accent); stroke-width: 1.3; }
.fm-bar { fill: var(--accent); }
.fm-var { stroke: var(--accent); stroke-width: 1.4; }
.fm-cota { stroke: var(--text-dim); color: var(--text-dim); stroke-width: 1; marker-start: url(#fmA); marker-end: url(#fmA); }
.fm-guia { stroke: var(--text-dim); stroke-width: 1; stroke-dasharray: 2 2; }
.fm-letra { fill: var(--text); font-size: 14px; font-weight: 700; font-style: italic; }
.fm-nota { fill: var(--text-dim); font-size: 10.5px; }
.fm-celda-letra { font-weight: 700; font-style: italic; text-align: center; width: 34px; }
.fm-picker { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; margin-top: 12px; }
.fm-opcion { background: var(--bg-elev); border: 1.5px solid var(--border); border-radius: 12px; padding: 10px; cursor: pointer; color: inherit; text-align: center; width: 210px; }
.fm-opcion:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--bg-elev)); }
.fm-opcion .fm-svg { width: 150px; margin: 0 auto; }
/* Fórmula que ya no evalúa: su cantidad está congelada. Tiene que verse. */
.apu-grid-table input.formula-rota { color: var(--red); text-decoration: underline wavy var(--red) 1px; }
/* Candado de las celdas con fórmula: se editan sólo a propósito. */
.fm-candado { background: none; border: none; padding: 0 3px 0 0; cursor: pointer; color: var(--text-dim); font-size: 12px; vertical-align: middle; }
.fm-candado:hover { color: var(--accent); }
.fm-candado.abierto { color: var(--accent); }
.apu-grid-table input[readonly].tiene-formula { cursor: default; opacity: 0.9; }

/* Auditoría: resaltado momentáneo al llegar desde "Revisar" (el panel vive al pie de la hoja). */
.audit-resaltado { animation: auditFlash 2.2s ease-out; border-radius: 10px; }
@keyframes auditFlash {
  0%, 55% { box-shadow: 0 0 0 3px var(--accent), 0 0 18px color-mix(in srgb, var(--accent) 45%, transparent); }
  100%    { box-shadow: 0 0 0 0 transparent; }
}

/* Ficha de solo consulta (presupuesto cerrado). */
.ficha-cerrada-badge { background: color-mix(in srgb, var(--amber, #b8860b) 18%, transparent); color: var(--amber, #b8860b); font-weight: 600; white-space: nowrap; }
.presu-apu-inline input:disabled, .presu-apu-inline select:disabled { opacity: .75; cursor: default; }

/* Distintivo discreto de ficha paramétrica en la partida. */
.badge.param { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }
.presu-t-param { color: var(--accent); opacity: .7; margin-left: 3px; font-size: 13px; }
.presu-t-param:hover { opacity: 1; }
/* Fórmula de rendimiento en la vista previa paramétrica de la Biblioteca (solo lectura). */
.fm-formula-chip { color: var(--accent); font-family: var(--font-mono, monospace); font-size: 12.5px;
  background: color-mix(in srgb, var(--accent) 12%, transparent); padding: 1px 6px; border-radius: 5px; }

/* Calculadora emergente del análisis P.U. */
.apu-calc-btn { padding: 6px 8px; }
.apu-calc-pop { position: fixed; z-index: 9000; width: 216px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow); padding: 10px; }
.apu-calc-display { width: 100%; box-sizing: border-box; text-align: right; font-size: 18px; font-family: var(--font-mono, monospace); padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-panel); color: inherit; }
.apu-calc-res { text-align: right; min-height: 18px; color: var(--accent); font-weight: 600; padding: 2px 4px 6px; }
.apu-calc-keys { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; }
.apu-calc-keys button { padding: 9px 0; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-panel); color: inherit; cursor: pointer; font-size: 15px; }
.apu-calc-keys button:hover { background: color-mix(in srgb, var(--accent) 12%, var(--bg-panel)); }
.apu-calc-keys button.op { color: var(--accent); }
.apu-calc-keys button.eq { background: var(--accent); color: #fff; border-color: var(--accent); }
.apu-calc-hist { max-height: 96px; overflow-y: auto; margin-top: 8px; }
.apu-calc-linea { font-size: 13px; padding: 3px 4px; border-radius: 6px; cursor: pointer; }
.apu-calc-linea:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }

/* "Desde ficha típica": selector de fichas modelo agrupadas por familia. */
.ft-familias { display: flex; flex-direction: column; gap: 12px; margin-top: 10px; }
.ft-familia-tit { font-size: 12px; text-transform: uppercase; letter-spacing: .3px; color: var(--text-dim); font-weight: 600; margin-bottom: 5px; }
.ft-opcion { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; text-align: left; padding: 8px 10px; margin-bottom: 5px; border: 1px solid var(--border); border-radius: 9px; background: var(--bg-panel); color: inherit; cursor: pointer; }
.ft-opcion:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--bg-panel)); }

/* Diálogo previo al crear proyecto: elección de ORIGEN (obra propia vs de cliente). */
.origen-choices { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.origen-choice { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: 12px; row-gap: 2px; align-items: center; width: 100%; text-align: left; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-panel); color: inherit; cursor: pointer; }
.origen-choice:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--bg-panel)); }
.origen-choice > i { grid-row: 1 / span 2; font-size: 23px; color: var(--accent); }
.origen-choice .oc-t { font-weight: 600; font-size: 15px; }
.origen-choice .oc-s { font-size: 13px; color: var(--text-dim); line-height: 1.35; }

/* Iconos en los títulos de sección de los modales (openModal): color de acento del tema. */
.field-section-title i { color: var(--accent); font-weight: 400; margin-right: 2px; }
/* Modal más compacto: dentro del formulario el ritmo vertical va aún más apretado — secciones
   con menos aire y campos más juntos, para que quepa más sin tener que hacer scroll. */
#modal-form .field { margin-bottom: 8px; }
#modal-form .field-section-title { margin: 9px 0 6px; padding-top: 7px; }
#modal-form .field label { margin-bottom: 3px; }
#modal-form .field input, #modal-form .field select, #modal-form .field textarea { padding: 7px 10px; }
#modal-form .hint.hint-sm { margin-top: 2px; }
#modal-form textarea { min-height: 48px; }

/* Secciones REPLEGABLES en modales (openModal con section.collapsible): el título es un botón que
   abre/cierra su grupo de campos, con un chevron que gira. Compacta formularios largos. */
.field-section .fs-toggle {
  display: flex; align-items: center; gap: 6px; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer; padding: 0; margin: 0;
}
.field-section .fs-toggle .fs-chevron { margin-left: auto; transition: transform .15s ease; font-size: 16px; }
.field-section.is-collapsed .fs-toggle .fs-chevron { transform: rotate(-90deg); }
.field-section .field-group[hidden] { display: none; }

/* P.U. en la vista "Todos los análisis P.U." resaltado en acento, para uniformar con cómo el
   Presupuesto marca los precios que emanan de la ficha. */
.presu-apu-ficha-head .u-accent-pu { color: var(--accent); }

/* Ficha APU en el modelo PROIECTUS: en vez de la hoja de papel (que es la metáfora del modelo
   Tradicional), la ficha va en una TARJETA como las del presupuesto Proiectus — ancho completo,
   esquinas redondeadas, sin márgenes de impresión ni sombra de papel. */
.apu-tarjeta {
  width: 100%; max-width: 100%; margin: 0 0 12px;
  background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 12px 12px;
}
.apu-tarjeta .presu-hoja-cuerpo { overflow-x: auto; }
.apu-tarjeta .presu-hoja-cab { border-bottom: 1px solid var(--border); margin-bottom: 8px; padding-bottom: 6px; }

/* Ficha APU en modelo PROIECTUS: una tarjeta por NATURALEZA, apiladas en scroll vertical. Cada
   tarjeta lleva su cabecera (naturaleza + subtotal) y su propia tabla; al final, la tarjeta de
   totales (costo directo → factor → precio unitario). */
.apu-nat-scroll { display: flex; flex-direction: column; gap: 10px; max-height: 62vh; overflow-y: auto; padding-right: 2px; }
.apu-nat-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 10px 4px; }
.apu-nat-card-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.apu-nat-card-total { margin-left: auto; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.apu-nat-card-totales { background: var(--bg-elev); position: sticky; bottom: 0; }
.apu-nat-card .table-wrap { overflow-x: auto; }

/* Curva de inversión: barras del desembolso mensual + punto del acumulado (curva S). */
.curva-graf { display: flex; align-items: flex-end; gap: 6px; height: 190px; padding: 8px 4px 22px; border-bottom: 1px solid var(--border); }
.curva-col { position: relative; flex: 1; height: 100%; display: flex; align-items: flex-end; }
.curva-barra { width: 100%; background: var(--accent); border-radius: 4px 4px 0 0; opacity: .8; min-height: 2px; }
.curva-col:hover .curva-barra { opacity: 1; }
.curva-acum { position: absolute; left: 50%; width: 7px; height: 7px; margin-left: -3.5px; border-radius: 50%; background: var(--green, #3fb950); }
.curva-mes { position: absolute; bottom: -20px; left: 0; right: 0; text-align: center; font-size: 11px; color: var(--text-dim); }

/* Columna "Da rend." del APU: el radio que marca qué insumo rige la duración de la actividad. */
.apu-rector-cell { text-align: center; }
.apu-rector-cell input[type="radio"] { cursor: pointer; }

/* ---------- Vista KANBAN del cronograma ---------- */
/* CINCO columnas (los tramos de avance) tienen que caber sin desplazamiento lateral, así que todo
   va más apretado que en el tablero de tres: menos separación, menos relleno y tipografía menor. */
.kb-board { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 7px; align-items: start; }
.kb-col { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); min-height: 140px; min-width: 0; }
.kb-col.kb-over { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--bg-panel)); }
/* Las dos columnas que no son "trabajo en curso" se distinguen de un vistazo: la de atraso pide
   acción, la de cerradas es el destino. */
.kb-col-tarde { border-color: color-mix(in srgb, var(--red) 40%, transparent); }
.kb-col-tarde .kb-col-head { color: var(--red); border-bottom-color: color-mix(in srgb, var(--red) 30%, transparent); }
.kb-col-tarde .kb-col-head i { color: var(--red); }
.kb-col-tarde.kb-over { border-color: var(--red); background: color-mix(in srgb, var(--red) 5%, var(--bg-panel)); }
.kb-col-hecho .kb-col-head i { color: var(--green); }
.kb-col-head { display: flex; align-items: center; gap: 4px; padding: 6px 8px; border-bottom: 1px solid var(--border);
  font-size: 12.5px; white-space: nowrap; overflow: hidden; }
.kb-col-head i { color: var(--accent); font-size: 16px; }
.kb-col-head strong { overflow: hidden; text-overflow: ellipsis; }
.kb-n { background: color-mix(in srgb, var(--text-dim) 16%, transparent); color: var(--text-dim);
  border-radius: 999px; padding: 0 6px; font-size: 11.5px; font-weight: 700; }
.kb-n-tarde { background: color-mix(in srgb, var(--red) 18%, transparent); color: var(--red); }
/* El importe de la columna cede primero: es contexto, no seguimiento. */
.kb-imp { margin-left: auto; font-size: 11px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; }
.kb-col-body { padding: 6px; display: flex; flex-direction: column; gap: 6px; max-height: 62vh; overflow-y: auto; }
.kb-vacio { text-align: center; color: var(--text-dim); font-size: 12px; padding: 14px 6px; border: 1px dashed var(--border); border-radius: var(--radius); }
.kb-card { background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); padding: 6px 8px; cursor: grab; }
.kb-card:hover { border-color: var(--accent); }
.kb-card.kb-drag { opacity: .5; }
.kb-card.kb-tarde { border-color: color-mix(in srgb, var(--red) 45%, transparent); }
.kb-card-top { display: flex; align-items: center; gap: 5px; margin-bottom: 3px; }
/* El % como pastilla con color propio: se lee el estado de un vistazo, sin recorrer la tarjeta. */
.kb-pct { margin-left: auto; display: inline-flex; align-items: center; gap: 3px;
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
  padding: 1px 7px; border-radius: 999px; white-space: nowrap; }
.kb-pct-cero { background: color-mix(in srgb, var(--text-dim) 15%, transparent); color: var(--text-dim); }
.kb-pct-act  { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent); }
.kb-pct-mal  { background: color-mix(in srgb, var(--red) 16%, transparent); color: var(--red); }
.kb-pct-ok   { background: var(--green); color: #fff; }
.kb-av-cero span { background: var(--text-dim); }
.kb-av-mal span  { background: var(--red); }
.kb-av-ok span   { background: var(--green); }
/* TERMINADA: distintivo verde y menos peso visual — ya no pide atención. */
.kb-hecha { border-color: color-mix(in srgb, var(--green) 45%, transparent);
  background: color-mix(in srgb, var(--green) 6%, var(--bg-elev)); }
.kb-hecha .kb-card-nom { color: var(--text-dim); }
.kb-hecha[style*="--g-bar-color"] { border-left-color: var(--green); }
.kb-card-nom { font-size: 13px; line-height: 1.25; margin-bottom: 5px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.kb-card-meta { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--text-dim); margin-bottom: 5px; }
.kb-resp { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-atraso { margin-left: auto; color: var(--red); font-weight: 600; white-space: nowrap; }
.kb-card-meta > span:last-child:not(.kb-resp) { margin-left: auto; white-space: nowrap; }
/* Piezas propias de la tarjeta de ABASTECIMIENTO, sobre el mismo esqueleto .kb-card del programa.
   Antes el tablero de compras tenía su propia familia (.kanban-*) con otros bordes y otro radio:
   dos tableros que el usuario llama igual no deben verse distinto. */
.kb-card-clave { font-weight: 600; font-size: 14px; cursor: pointer; }
.kb-card-clave:hover { color: var(--accent); text-decoration: underline; }
.kb-card-imp { margin-left: auto; font-size: 12.5px; color: var(--text-dim);
  font-variant-numeric: tabular-nums; }
.kb-card-accion { width: 100%; margin-top: 7px; justify-content: center; }
/* SELLO de la tarjeta: verde cuando esta etapa no espera la firma de nadie; reloj ámbar cuando
   falta alguna. Es lo primero que se busca al mirar una columna, así que va antes del folio. */
.kb-sello { display: inline-flex; align-items: center; font-size: 15px; line-height: 1; }
.kb-sello-ok { color: var(--green); }
.kb-sello-falta { color: var(--amber); }
/* Un filo verde a la izquierda: la columna se puede barrer de un vistazo sin leer los sellos. */
.kb-card-ok { box-shadow: inset 3px 0 0 var(--green); }
/* Solo las tarjetas que se pueden devolver muestran el cursor de arrastre: si todas lo mostraran,
   el usuario probaría en las que no se mueven y concluiría que el tablero está roto. */
.kb-card-mueve { cursor: grab; }
.kb-card-mueve:active { cursor: grabbing; }
/* La columna a la que SÍ se puede soltar se marca desde que empieza el arrastre, no al pasar por
   encima: así se ve el destino sin tener que ir probando columna por columna. */
.kb-destino { outline: 2px dashed color-mix(in srgb, var(--accent) 60%, transparent); outline-offset: -2px; }
.kb-col.kb-over { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--bg-panel)); }
/* La franja de color va SOLO en el tablero de abastecimiento, donde cada columna es una etapa con
   su color. Aplicarla a `.kb-col` a secas le pisaba el borde de 1px al Kanban del programa, que
   no usa color por columna: una regla pensada para un tablero no puede colarse en el otro. */
/* Filtros del tablero: etapas como segmentos arriba, y fechas y texto debajo. Cada segmento
   lleva el color de su columna, así el filtro y el tablero hablan el mismo idioma de colores. */
.kb-filtros { display: flex; flex-direction: column; gap: 8px; margin: 0 0 12px; }
.kb-segs { display: flex; flex-wrap: wrap; gap: 6px; }
.kb-seg { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; font: inherit;
  font-size: 13.5px; cursor: pointer; color: var(--text-dim); background: transparent;
  border: 1px solid var(--border); border-radius: var(--radius); }
.kb-seg:hover { color: var(--text); background: var(--bg-elev); }
.kb-seg[aria-pressed="true"] { color: var(--text); border-color: var(--kb-col-color);
  box-shadow: inset 0 -2px 0 var(--kb-col-color); background: var(--bg-elev); }
.kb-seg i { color: var(--kb-col-color); }
.kb-seg-n { font-variant-numeric: tabular-nums; background: var(--bg); border-radius: var(--radius);
  padding: 0 6px; font-size: 12px; }
.kb-filtros-fila { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.kb-filtros-fila label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px;
  color: var(--text-dim); }
.kb-filtros-fila input[type="date"] { padding: 6px 8px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--bg-panel); color: inherit; font: inherit; font-size: 14px; }
.kb-filtros-fila .filtro-lista { flex: 1 1 18rem; min-width: 12rem; padding: 6px 10px 6px 34px;
  border-radius: var(--radius); border: 1px solid var(--border); background: var(--bg-panel);
  color: inherit; font: inherit; font-size: 14px; }
.kb-filtros-fila input:focus { outline: none; border-color: var(--accent); }

/* CINCO columnas: Requisiciones · Cotizaciones · Orden de compra · Pendiente de entrega · Bodega.
   Decía seis (de cuando Solicitud y Cotizaciones estaban separadas) y la rejilla reservaba una
   pista de más: el tablero se dibujaba con 1/6 del ancho vacío a la derecha. */
.kb-board-etapas { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.kb-board-etapas .kb-col { border-top: 3px solid var(--kb-col-color, var(--border)); }
/* Seis columnas no caben en una pantalla mediana sin espachurrar las tarjetas: por debajo de
   1100px el tablero pasa a desplazamiento lateral con columnas de ancho fijo, que es preferible a
   seis columnas de 140px donde no se lee ni el folio. */
@media (max-width: 1100px) {
  .kb-board-etapas { display: flex; overflow-x: auto; padding-bottom: 8px; }
  .kb-board-etapas .kb-col { flex: 0 0 230px; }
}

.kb-card-avance { height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; }
.kb-card-avance span { display: block; height: 100%; background: var(--accent); }
/* Al estrecharse: 5 → 3 → 1. Cinco columnas por debajo de 1100px dan tarjetas ilegibles. */
@media (max-width: 1100px) { .kb-board { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 760px) { .kb-board { grid-template-columns: 1fr; } }

/* Control segmentado (grupo de botones que actúan como pestañas): selector de vista del
   cronograma, base de la curva de inversión, etc. */
.seg { display: inline-flex; gap: 0; }
.seg .btn { border-radius: 0; margin: 0; }
.seg .btn:first-child { border-top-left-radius: var(--radius); border-bottom-left-radius: var(--radius); }
.seg .btn:last-child { border-top-right-radius: var(--radius); border-bottom-right-radius: var(--radius); }
.seg .btn + .btn { border-left: none; }

/* Línea de tiempo del proyecto en el encabezado: plazo total, meses y marca de HOY. */
.proj-timeline { margin-top: 8px; max-width: 560px; }
.pt-bar { position: relative; height: 8px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: 5px; overflow: visible; }
.pt-avance { position: absolute; inset: 0 auto 0 0; background: color-mix(in srgb, var(--accent) 55%, transparent); border-radius: 5px 0 0 5px; }
.pt-hoy { position: absolute; top: -3px; width: 2px; height: 14px; background: var(--red); border-radius: 1px; }
.pt-mes { position: absolute; top: 10px; font-size: 10.5px; color: var(--text-dim); transform: translateX(-50%); white-space: nowrap; }
.pt-mes::before { content: ""; position: absolute; top: -10px; left: 50%; width: 1px; height: 8px; background: var(--border); }
.pt-pie { display: flex; justify-content: space-between; gap: 8px; margin-top: 18px; font-size: 11.5px; color: var(--text-dim); }
.pt-estado { color: var(--text); font-weight: 500; }

/* Apariencia de las barras del Gantt (color y forma elegidos por el usuario). */
.g-bar.g-bar-tinta { background: var(--g-bar-color) !important; }
.g-bar.g-bar-rayada { background-image: repeating-linear-gradient(45deg, rgba(255,255,255,.28) 0 5px, transparent 5px 10px); }
.g-bar.g-bar-contorno { background: transparent !important; border: 2px solid var(--g-bar-color, var(--accent-2)); }
.ap-colores { display: flex; gap: 8px; flex-wrap: wrap; }
.ap-color { width: 30px; height: 30px; border-radius: 50%; border: 2px solid var(--border); cursor: pointer; padding: 0; }
.ap-color:hover { border-color: var(--text); transform: scale(1.08); }

/* Escala del Gantt en UNA sola fila + marca de HOY. */
/* UNA SOLA FILA: el mes ya no ocupa banda propia. Cada mes es un tramo transparente cuyo único
   adorno es el corte vertical del día 1; su etiqueta va pegada (sticky) al borde izquierdo visible,
   así siempre se sabe en qué mes se está sin gastar una segunda fila de altura. */
.g-tick-mes { position: absolute; top: 0; height: 100%; display: flex; align-items: center;
  border-left: 2px solid var(--text-dim); box-sizing: border-box;
  white-space: nowrap; pointer-events: none; z-index: 2; }
.g-tick-mes span { position: absolute; left: 0; margin-left: 2px; padding: 1px 6px; border-radius: 4px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  color: var(--text); background: var(--bg-elev); border: 1px solid var(--border); }
.g-tick-mes-min { border-left-width: 1px; }
.g-tick-dia, .g-tick-sem { top: 0 !important; height: 100%; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  border-left: 1px solid var(--border); font-size: 11px; color: var(--text-dim); }
.g-tick-sem { font-weight: 600; letter-spacing: .3px; }
/* Días no laborables: banda sombreada que baja también por el cuerpo, para leer el fin de semana. */
.g-tick-finde { background: color-mix(in srgb, var(--text-dim) 8%, transparent); color: var(--text-dim); opacity: .7; }
.g-hoy-line { position: absolute; top: 0; width: 2px; background: var(--red); opacity: .75; z-index: 3; pointer-events: none; }
.g-hoy-lbl { position: absolute; top: 7px; transform: translateX(-50%); background: var(--red); color: #fff;
  font-size: 10.5px; font-weight: 600; padding: 1px 6px; border-radius: 8px; z-index: 5; }
/* Nombre de la actividad junto a su barra. */
.g-bar-lbl { position: absolute; display: flex; align-items: center; font-size: 12px; color: var(--text-dim);
  white-space: nowrap; pointer-events: none; }

/* Selectores dentro de la rejilla del Gantt (responsable, estado). */
.g-sel { width: 100%; background: transparent; color: inherit; border: 1px solid transparent;
  border-radius: 5px; font: inherit; font-size: 12.5px; padding: 2px 4px; }
.g-sel:hover, .g-sel:focus { border-color: var(--border); background: var(--bg); outline: none; }
.g-estado-hecho { color: var(--green); }
.g-estado-en_curso { color: var(--accent); }

/* Vista Resumen (Overview) del programa de obra. */
.ov-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 4px; }
.ov-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; }
.ov-lbl { font-size: 12px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-dim); }
.ov-val { font-size: 27px; font-weight: 700; margin: 2px 0 4px; }
.ov-extra { font-size: 12.5px; color: var(--text-dim); }
.ov-bar { height: 5px; background: var(--bg-elev); border-radius: 3px; margin-top: 6px; overflow: hidden; }
.ov-bar span { display: block; height: 100%; border-radius: 3px; }

/* Menú contextual de la barra del Gantt (clic derecho). */
.g-ctx { position: fixed; z-index: 200; min-width: 232px; background: var(--bg-panel);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 8px 26px rgba(0,0,0,.35);
  padding: 4px; font-size: 14px; }
.g-ctx button { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  background: none; border: 0; color: inherit; font: inherit; padding: 7px 10px; border-radius: 6px; cursor: pointer; }
.g-ctx button:hover { background: var(--bg-elev); }
.g-ctx button i { color: var(--text-dim); }
.g-ctx-tit { padding: 6px 10px 8px; font-size: 12px; color: var(--text-dim); border-bottom: 1px solid var(--border);
  margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.g-ctx-sep { height: 1px; background: var(--border); margin: 4px 0; }
.g-ctx-mas { margin-left: auto; color: var(--text-dim); }
.g-ctx-sub { position: absolute; min-width: 92px; max-height: 300px; overflow-y: auto; }
.g-ctx-sub button { justify-content: flex-end; padding: 5px 12px; }
.g-ctx-sub button.activo { background: var(--bg-elev); color: var(--accent); font-weight: 600; }

/* Vista TABLA del cronograma: rejilla editable a todo lo ancho. */
.tb-wrap { overflow-x: auto; }
.tb-cronograma { width: 100%; border-collapse: collapse; font-size: 13.5px; white-space: nowrap; }
/* La tabla tiene 15 columnas y no caben en 1240px: las dos últimas (Importe y Ejecutado) se salían
   del borde y parecía que la vista "no muestra las columnas". Se aprieta lo que no cuesta lectura
   —relleno de celda y ancho de los campos— para que entren TODAS de entrada. */
.tb-cronograma th, .tb-cronograma td { padding: 4px 6px; border-bottom: 1px solid var(--border); text-align: left; }
/* La descripción se queda con TODO el espacio que sobre. `width:100%` sobre una sola columna de
   una tabla de ancho automático hace que las demás se ajusten a su contenido y esta absorba el
   resto; `max-width:0` es el truco que permite recortarla con puntos suspensivos cuando no cabe
   (sin él, la celda crecería con el texto y volvería a empujar las cifras fuera de la pantalla).
   Así, en pantalla ancha se lee el nombre completo y en una angosta se recorta solo ella. */
.tb-cronograma th:nth-child(2), .tb-cronograma td:nth-child(2) {
  width: 100%; max-width: 0; min-width: 180px; overflow: hidden; text-overflow: ellipsis; }
.tb-cronograma thead th { position: sticky; top: 0; background: var(--bg-panel); z-index: 2;
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .3px; color: var(--text-dim); }
.tb-cronograma tfoot th { position: sticky; bottom: 0; background: var(--bg-elev); font-weight: 700; }
.tb-cronograma td.num, .tb-cronograma th.num { text-align: right; }
.tb-cronograma tbody tr:hover { background: var(--bg-elev); }
.tb-cronograma tr.tb-atrasada td:first-child { box-shadow: inset 3px 0 0 var(--red); }
.tb-cronograma .g-dur { width: 44px; }
.tb-cronograma .g-date { width: 106px; padding-left: 4px; padding-right: 2px; }
.tb-cronograma .g-sel { max-width: 110px; }

/* Cinta de herramientas del cronograma en pestañas: todas las funciones a la vista. */
.gantt-ribbon-tabs { margin: 0 0 6px; border-bottom: 1px solid var(--border); }
.gantt-ribbon { display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
  padding: 5px 9px; margin: 4px 0 6px; background: var(--bg-panel);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 1px 2px rgba(0,0,0,.04); }
.gantt-ribbon[hidden] { display: none; }
.gantt-ribbon .btn.small { padding: 3px 8px; font-size: 12.5px; }
.gantt-ribbon .rb-lbl { font-size: 10.5px; text-transform: uppercase; letter-spacing: .7px;
  color: var(--text-dim); font-weight: 700; opacity: .7; padding-right: 1px; }
.gantt-ribbon .rb-sep { width: 1px; align-self: stretch; margin: 3px 5px;
  background: linear-gradient(180deg, transparent, var(--border) 25%, var(--border) 75%, transparent); }
.gantt-ribbon input { padding: 5px 9px; font-size: 13.5px; }

/* Color por capítulo: barra resumen del capítulo y marca lateral de la tarjeta Kanban. */
.g-chapbar[style*="--g-cap-color"] { background: var(--g-cap-color); color: var(--g-cap-color); opacity: .62; }
.kb-card[style*="--g-bar-color"] { border-left: 3px solid var(--g-bar-color); }

/* Programa de obra en hoja: son 15 columnas, así que la hoja usa el lado LARGO del papel
   (apaisado, que es lo que ya calcula renderCronogramaTradicional) y la tabla va compacta. */
.tb-programa { font-size: 11.5px; }
.tb-programa th, .tb-programa td { padding: 3px 5px; white-space: nowrap; }
.tb-programa td:nth-child(2) { white-space: normal; min-width: 180px; }

/* AYUDA VISUAL al pasar el ratón: se resalta la fila completa a lo ancho del diagrama y el rango
   de fechas de esa actividad en la escala de arriba. */
.g-row-hl { position: absolute; left: 0; right: 0; z-index: 1; pointer-events: none;
  background: color-mix(in srgb, var(--accent) 12%, transparent); }
.g-scale-hl { position: absolute; top: 3px; height: 24px; z-index: 1; pointer-events: none;
  border-radius: 3px; background: color-mix(in srgb, var(--accent) 32%, transparent);
  border: 1px solid var(--accent); }
.gantt2-tasks tr.g-row-on > td { background: color-mix(in srgb, var(--accent) 12%, transparent); }

/* ---------- Termómetro del proyecto (cómo vamos contra la línea base) ---------- */
.salud { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 10px 14px; margin-bottom: 10px;
  background: var(--bg-panel); border: 1px solid var(--border); border-left: 4px solid var(--salud-col); border-radius: var(--radius); }
.salud-estado { display: flex; align-items: center; gap: 10px; }
.salud-estado > i { font-size: 27px; color: var(--salud-col); }
.salud-etq { font-size: 16px; font-weight: 700; color: var(--salud-col); line-height: 1.1; }
.salud-dias { font-size: 12.5px; color: var(--text-dim); }
.salud-medidor { position: relative; flex: 1; min-width: 180px; max-width: 380px; }
.salud-escala { display: flex; height: 8px; border-radius: 4px; overflow: hidden; }
.salud-escala .s-atras { flex: 46; background: color-mix(in srgb, var(--red) 45%, transparent); }
.salud-escala .s-ok    { flex: 8;  background: color-mix(in srgb, var(--green) 60%, transparent); }
.salud-escala .s-adel  { flex: 46; background: color-mix(in srgb, var(--accent) 35%, transparent); }
.salud-aguja { position: absolute; top: -4px; width: 3px; height: 16px; margin-left: -1.5px;
  background: var(--text); border-radius: 2px; box-shadow: 0 0 0 2px var(--bg-panel); }
.salud-topes { display: flex; justify-content: space-between; font-size: 10.5px; color: var(--text-dim); margin-top: 3px; }
.salud-cifras { display: flex; gap: 14px; flex-wrap: wrap; }
.salud-cifras > div { display: flex; flex-direction: column; }
.sc-lbl { font-size: 10.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-dim); }
.sc-val { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }
.salud-vacio { padding: 9px 14px; margin-bottom: 10px; font-size: 13.5px; color: var(--text-dim);
  background: var(--bg-panel); border: 1px dashed var(--border); border-radius: var(--radius); }
/* Línea de HOY: permanente y bien visible, es la referencia de todo el seguimiento. */
.g-hoy-line { width: 2px; background: var(--red); opacity: .85; box-shadow: 0 0 5px color-mix(in srgb, var(--red) 55%, transparent); }

/* Guía del cursor en el área de barras: cruz + fecha bajo el puntero. */
.g-guia-v { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--accent); opacity: .5; pointer-events: none; z-index: 4; }
.g-guia-h { position: absolute; left: 0; right: 0; background: color-mix(in srgb, var(--accent) 8%, transparent); pointer-events: none; z-index: 0; }
.g-guia-fecha { position: absolute; top: 2px; transform: translateX(-50%); z-index: 5; pointer-events: none;
  background: var(--accent); color: #fff; font-size: 10.5px; font-weight: 600; padding: 1px 6px; border-radius: 8px; white-space: nowrap; }

/* Tiradores de enlace: círculos en los extremos de la barra. Aparecen al pasar el ratón; el
   primer clic elige de dónde sale la dependencia y el segundo a dónde llega — esa combinación
   define el tipo (FS/SS/FF/SF) sin menús. */
.g-hnd { position: absolute; width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--bg-panel); cursor: crosshair; z-index: 6;
  opacity: 0; transition: opacity .12s, transform .12s; }
.g-bar:hover ~ .g-hnd, .g-hnd:hover, .g-hnd.g-hnd-activo { opacity: 1; }
.g-hnd:hover { transform: scale(1.45); }
.g-hnd.g-hnd-on { background: var(--red); opacity: 1; transform: scale(1.5); box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 30%, transparent); }

/* Barra de herramientas del cronograma FIJA: al bajar por las actividades sigue a la vista, que es
   donde están el selector de vista, la escala y las acciones. Sin esto había que subir hasta
   arriba para cualquier cosa en un programa de 80 actividades. */
.gantt-cab, .gantt-ribbon { position: sticky; z-index: 30; background: var(--bg); }
.gantt-cab { top: 0; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 4px 0 0; }
.gantt-cab .gantt-ribbon-tabs { margin: 0; border-bottom: none; flex: 0 0 auto; }
.gantt-cuenta { margin-left: auto; font-size: 12px; white-space: nowrap; }
.gantt-ribbon { top: 0; }   /* el valor real lo fija renderTareas midiendo la cabecera */
/* La escala del diagrama YA era sticky (top:56px, z-index:14) desde antes: no se toca aquí para
   no descolocarla. La barra fija va por encima con z-index mayor. */

/* La escala del diagrama se ancla DEBAJO de la barra fija (topbar 0 + pestañas 44 + cinta 80),
   si no quedaría oculta tras ella al hacer scroll. Se respeta su z-index original. */
/* .g-scale: su `top` lo fija renderTareas midiendo cabecera + cinta, para que no se descuadre
   cuando la cinta se pliega o la cabecera cambia de alto. */

/* Nota en la cinta: recuerda dónde nace cada cosa (los capítulos, en Presupuesto). */
.rb-nota { font-size: 12.5px; color: var(--text-dim); display: inline-flex; align-items: center; gap: 5px; }
.rb-nota i { color: var(--accent); }

/* ---------- Vista MAPA: organigrama de arriba abajo ---------- */
.mm-lienzo { overflow-x: auto; padding: 14px 6px 6px; }
.mm-arbol { display: inline-block; min-width: 100%; }
.mm-arbol ul { display: flex; justify-content: center; gap: 14px; list-style: none; margin: 0; padding: 26px 0 0; position: relative; }
.mm-arbol > ul { padding-top: 0; }
.mm-arbol li { position: relative; padding: 0; display: flex; flex-direction: column; align-items: center; }
/* Conectores: vertical desde el padre, horizontal entre hermanos, vertical hasta cada hijo. */
.mm-arbol ul ul::before { content: ""; position: absolute; top: 0; left: 50%; width: 1px; height: 13px; background: var(--border); }
.mm-arbol ul li::before { content: ""; position: absolute; top: -13px; left: 50%; width: 1px; height: 13px; background: var(--border); }
.mm-arbol > ul > li::before { display: none; }
.mm-arbol ul ul > li::after { content: ""; position: absolute; top: -13px; left: 0; right: 0; height: 1px; background: var(--border); }
.mm-arbol ul ul > li:first-child::after { left: 50%; }
.mm-arbol ul ul > li:last-child::after { right: 50%; }
.mm-arbol ul ul > li:only-child::after { display: none; }
/* Cajas */
.mm-caja { position: relative; width: 172px; min-height: 54px; padding: 7px 10px 9px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--bg-panel); font-size: 12.5px; overflow: hidden; text-align: left; }
.mm-p { border: 2px solid var(--accent); background: var(--bg-elev); width: 230px; }
.mm-c { cursor: pointer; border-top: 3px solid var(--mm-col); }
.mm-c:hover { border-color: var(--accent); }
.mm-t { width: 158px; }
.mm-t.mm-hecho { opacity: .58; }
.mm-t.mm-curso { border-color: var(--accent); }
.mm-caja-top { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; }
.mm-caja-nom { line-height: 1.25; }
.mm-caja-pie { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
.mm-clave { font-size: 11px; color: var(--text-dim); font-family: var(--font-mono, ui-monospace, monospace); }
.mm-caret { margin-left: auto; font-size: 10px; color: var(--text-dim); }
.mm-av { position: absolute; left: 0; bottom: 0; height: 3px; background: var(--green); opacity: .85; }

/* ---------- Visión general del proyecto ---------- */
.vg-panel { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px 14px; margin-bottom: 12px; }
.vg-tit { font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px;
  color: var(--text-dim); margin-bottom: 10px; display: flex; align-items: center; gap: 6px; }
.vg-tit i { color: var(--accent); }
.vg-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr); gap: 12px; align-items: start; }
@media (max-width: 900px) { .vg-cols { grid-template-columns: 1fr; } }
/* Línea de tiempo por capítulo */
.vg-tl { position: relative; }
.vg-tl-escala { position: relative; height: 16px; margin: 0 110px 4px 190px; }
.vg-tl-escala span { position: absolute; font-size: 10.5px; color: var(--text-dim); transform: translateX(-50%); }
.vg-tl-fila { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
.vg-tl-lbl { width: 182px; font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vg-tl-pista { position: relative; flex: 1; height: 20px; background: var(--bg-elev); border-radius: 4px; }
.vg-tl-barra { position: absolute; top: 2px; height: 16px; border-radius: 4px; opacity: .85; overflow: hidden;
  display: flex; align-items: center; }
.vg-tl-barra span { position: absolute; left: 0; top: 0; bottom: 0; background: rgba(255,255,255,.35); }
.vg-tl-barra em { position: relative; font-style: normal; font-size: 10px; color: #fff; padding-left: 5px; }
.vg-tl-imp { width: 102px; text-align: right; font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.vg-tl-hoy { position: absolute; top: 16px; bottom: 0; width: 2px; background: var(--red); opacity: .8; }
/* Curva de avance */
.vg-curva { width: 100%; height: 150px; display: block; }
.vg-esp-area { fill: color-mix(in srgb, var(--accent) 14%, transparent); }
.vg-esp-linea { stroke: var(--accent); stroke-width: 1.5; vector-effect: non-scaling-stroke; opacity: .7; }
.vg-real-linea { stroke: var(--green); stroke-width: 2.5; vector-effect: non-scaling-stroke; }
.vg-hoy-linea { stroke: var(--red); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-dasharray: 3 3; }
.vg-leyenda { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--text-dim); margin-top: 6px; }
.vg-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-left: 8px; }
.vg-dot-esp { background: var(--accent); } .vg-dot-real { background: var(--green); } .vg-dot-hoy { background: var(--red); }
.vg-cifras { width: 100%; margin-top: 12px; font-size: 13.5px; }
.vg-cifras td { padding: 5px 0; border-bottom: 1px solid var(--border); }
.vg-cifras td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Franja de estado del cronograma: termómetro + avance + avisos en UNA fila. */
.estado-fila { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.estado-fila > * { border-radius: var(--radius); }
.estado-fila .salud, .estado-fila .salud-vacio { margin-bottom: 0; flex: 1; min-width: 340px; }
.ef-avance { display: flex; flex-direction: column; justify-content: center; gap: 4px; min-width: 150px;
  padding: 10px 14px; background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); }
.ef-lbl { font-size: 10.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-dim); }
.ef-bar { height: 6px; background: var(--bg-elev); border-radius: 3px; overflow: hidden; }
.ef-bar span { display: block; height: 100%; background: var(--green); }
.ef-pct { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }
.ef-avisos { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  padding: 10px 16px; background: var(--bg-panel); border: 1px solid var(--border);
  border-left: 3px solid var(--amber); border-radius: var(--radius); color: inherit; font: inherit; cursor: pointer; }
.ef-avisos:hover { border-color: var(--amber); }
.ef-avisos i { font-size: 19px; color: var(--amber); }
.ef-avisos span { font-size: 12px; color: var(--text-dim); white-space: nowrap; }

/* Selector de días laborables del calendario. */
.cal-dias { display: flex; gap: 6px; flex-wrap: wrap; }
.cal-dia { padding: 7px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg); color: var(--text-dim); font: inherit; font-size: 13px; cursor: pointer; }
.cal-dia.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }

/* Cabecera del cronograma más baja: el termómetro y las tarjetas de estado iban con demasiado aire
   para ser información de cabecera. Con esto la zona de encabezado baja de ~4 franjas a 2. */
.estado-fila .salud { padding: 6px 12px; gap: 12px; }
.estado-fila .salud-estado > i { font-size: 21px; }
.estado-fila .salud-etq { font-size: 14px; }
.estado-fila .ef-avance, .estado-fila .ef-avisos { padding: 6px 12px; }
.estado-fila .ef-pct { font-size: 14px; }
.estado-fila .sc-val { font-size: 14px; }
.gantt-cab .tabs .tab { padding: 5px 12px; font-size: 13.5px; }
/* .g-scale: su `top` lo fija renderTareas midiendo cabecera + cinta (ver requestAnimationFrame). */

/* ---------- Cabecera compacta del proyecto (TODA la aplicación) ----------
   El encabezado (título, espacios, sub-pestañas y botones) gastaba demasiada altura en todas las
   pantallas: es navegación, no contenido. Se aprieta de forma pareja para que el trabajo —hoja de
   presupuesto, ficha APU, cronograma, tablas— gane pantalla. */
.page-head { margin-bottom: 8px; }
.page-head h1 { font-size: 19px; margin: 0; }
.page-head .sub { font-size: 12.5px; }
.back-link { font-size: 12.5px; }
.espacio { padding: 5px 13px; font-size: 14px; border-radius: 8px; }
.espacios { margin-bottom: 5px; }
.tabs { margin: 5px 0 8px; }
.tabs .tab { padding: 6px 13px; font-size: 14px; }
.page-head .btn { padding: 5px 10px; font-size: 13.5px; }

/* Ruta de tarea: la cadena señalada se mantiene, lo demás se atenúa. */
.g-bar.g-fuera-ruta { opacity: .18; }
.g-bar.g-en-ruta { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Inspector */
.insp-cab { padding-bottom: 8px; border-bottom: 1px solid var(--border); margin-bottom: 10px; }
.insp-razones { list-style: none; margin: 0 0 4px; padding: 0; }
.insp-razones li { display: flex; gap: 9px; align-items: flex-start; padding: 7px 0; font-size: 14px; line-height: 1.4; }
.insp-razones li i { font-size: 17px; margin-top: 1px; }

/* ---------- Arranque del cronograma vacío ---------- */
.arranque { max-width: 760px; margin: 24px auto; }
.arr-cab { text-align: center; margin-bottom: 20px; }
.arr-cab > i { font-size: 37px; color: var(--accent); opacity: .55; }
.arr-cab h2 { font-size: 19px; margin: 8px 0 4px; }
.arr-cab .sub { font-size: 14px; }
.arr-ops { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; }
.arr-op { position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  text-align: left; padding: 16px 16px 18px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg-panel); color: inherit; font: inherit; cursor: pointer; }
.arr-op:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 5%, var(--bg-panel)); }
.arr-op > i { font-size: 25px; color: var(--accent); margin-bottom: 4px; }
.arr-primaria { border-color: var(--accent); border-width: 2px; }
.arr-t { font-size: 15px; font-weight: 600; }
.arr-s { font-size: 13px; color: var(--text-dim); line-height: 1.4; }
.arr-x { position: absolute; top: 10px; right: 10px; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .4px; background: var(--accent); color: #fff; padding: 2px 8px; border-radius: 8px; }

/* Días no laborables sombreados a lo largo del cuerpo del diagrama: explica visualmente por qué una
   actividad de 5 días hábiles ocupa 7 en el calendario. */
.g-nolab { position: absolute; top: 0; background: color-mix(in srgb, var(--text-dim) 7%, transparent);
  pointer-events: none; z-index: 0; }

/* Botón de IMPRIMIR: el mismo aspecto y la misma posición (extremo derecho de la barra) en todas
   las pantallas. Antes en el Gantt era un icono sin etiqueta y en Presupuesto/APU estaba escondido
   dentro del desplegable "Más": no se encontraba, y no se parecia a si mismo de una vista a otra. */
.btn-imprimir { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.btn-imprimir:hover { background: color-mix(in srgb, var(--accent) 12%, transparent); }
/* 16px era la talla de cuando el boton llevaba texto al lado. Ya como icono suelto en la barra se
   veia mas chico que sus vecinos: hereda la talla del grupo y no la impone. */
.btn-imprimir:not(.btn-icon) i { font-size: 16px; }

/* ---------- REVISAR PROGRAMA: botón grande y diálogo de hallazgos ---------- */
/* El botón va en la fila de estado, no escondido en la cinta: se ve entres en la pestaña que
   entres, que es justo lo que se pidió para que no pase desapercibido. */
.ef-revisar { display: flex; align-items: center; gap: 10px; padding: 8px 16px; cursor: pointer;
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-panel));
  border: 2px solid var(--accent); border-radius: var(--radius); color: var(--text);
  font: inherit; text-align: left; transition: background .12s ease, transform .08s ease; }
.ef-revisar:hover { background: color-mix(in srgb, var(--accent) 20%, var(--bg-panel)); }
.ef-revisar:active { transform: translateY(1px); }
.ef-revisar > i { font-size: 25px; color: var(--accent); }
.ef-revisar .efr-t { display: block; font-weight: 700; font-size: 14.5px; }
.ef-revisar .efr-s { display: block; font-size: 11.5px; color: var(--text-dim); }
.ef-revisar .efr-n { margin-left: 4px; min-width: 24px; text-align: center; padding: 2px 7px;
  border-radius: 999px; font-size: 13px; font-weight: 700; color: #fff; }
.ef-revisar .efr-n.mal { background: var(--red); }
.ef-revisar .efr-n.ok { background: var(--green); }

.rev-cab { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.rev-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px;
  border-radius: 999px; font-size: 13px; font-weight: 600; }
.rev-chip.rev-alta { background: color-mix(in srgb, var(--red) 15%, transparent); color: var(--red); }
.rev-chip.rev-media { background: color-mix(in srgb, var(--amber, #d98324) 18%, transparent); color: var(--amber, #d98324); }
.rev-chip.rev-baja { background: color-mix(in srgb, var(--text-dim) 14%, transparent); color: var(--text-dim); }
.rev-grupo { border: 1px solid var(--border); border-left-width: 4px; border-radius: var(--radius);
  padding: 8px 10px; margin-bottom: 10px; }
.rev-grupo.rev-alta { border-left-color: var(--red); }
.rev-grupo.rev-media { border-left-color: var(--amber, #d98324); }
.rev-grupo.rev-baja { border-left-color: var(--text-dim); }
.rev-tit { display: flex; align-items: center; gap: 7px; font-weight: 700; font-size: 14px; margin-bottom: 6px; }
.rev-fix { margin-bottom: 8px; }
.rev-alts { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.rev-alts .sub { font-size: 12.5px; }
/* Lo que el sistema NO puede arreglar solo se dice con todas sus letras, en vez de dejar el hueco
   donde iría el botón: si no, parece que la revisión solo informa y no sirve para nada. */
.rev-manual { margin: 0 0 8px; display: flex; align-items: flex-start; gap: 6px; font-size: 12.5px; }
.rev-manual i { margin-top: 2px; }
.rev-cuenta { margin-left: auto; font-size: 12px; color: var(--text-dim);
  background: color-mix(in srgb, var(--text-dim) 12%, transparent); padding: 1px 8px; border-radius: 999px; }
.rev-ok { display: flex; align-items: center; gap: 12px; padding: 18px;
  border: 1px solid color-mix(in srgb, var(--green) 45%, transparent); border-radius: var(--radius);
  background: color-mix(in srgb, var(--green) 8%, transparent); }
.rev-ok > i { font-size: 33px; color: var(--green); }

/* ---------- PORTADA: LA LISTA DE OBRAS ----------
   Un renglón por obra en vez de tarjetas: caben todas de un vistazo y las cifras se comparan en
   columna, que es como se revisa de verdad. El estado va como FRANJA en el canto —se lee de lejos
   y sin leer ningún número—, y el plazo en cifra grande, que es el dato que más se consulta. */
.cartera { display: grid; grid-template-columns: repeat(4, 1fr); border: 1px solid var(--border);
  /* Franja de acento abajo, como el cajetín de la maqueta: separa la cartera del resto sin
     necesidad de un título, y ata la portada al color de la casa. */
  border-bottom: 3px solid var(--accent); border-radius: var(--radius) var(--radius) 0 0;
  background: var(--bg-panel); margin-bottom: 14px; overflow: hidden; }
/* Todos los cajetines con la MISMA altura, la del más alto, y la cifra siempre a la misma
   distancia del borde inferior. La rejilla ya los iguala en alto, pero sin esto la cifra flotaba
   a alturas distintas en cuanto una etiqueta pasaba a dos líneas ("Contratado" cabe, "Ejercido"
   con un importe largo no), y la fila se leía torcida. */
.cartera > div { padding: 10px 14px; border-right: 1px solid var(--border);
  display: flex; flex-direction: column; justify-content: space-between; gap: 4px; }
.cartera dt { min-height: 1.2em; }
.cartera > div:last-child { border-right: 0; }
.cartera dt { font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
.cartera dd { margin: 0; font-family: "Oswald", sans-serif; font-size: 1.45rem; line-height: 1.1;
  font-variant-numeric: tabular-nums; align-self: start; }
.cartera dd.alerta { color: var(--red); }
@media (max-width: 640px) { .cartera { grid-template-columns: repeat(2, 1fr); } }

.hoy-barra { display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; margin-bottom: 14px;
  border: 1px solid color-mix(in srgb, var(--amber) 45%, transparent);
  border-left: 4px solid var(--amber); border-radius: var(--radius);
  background: color-mix(in srgb, var(--amber) 7%, transparent); }
.hoy-barra h2 { margin: 0; font-size: 13px; letter-spacing: .1em; text-transform: uppercase; color: var(--amber); }
.hoy-barra ul { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 3px; }
.hoy-barra button { background: none; border: 0; padding: 0; text-align: left; cursor: pointer;
  color: var(--text); font: inherit; font-size: 14.5px; }
.hoy-barra button:hover { text-decoration: underline; }
/* La franja «Hoy» lleva el 100% de los avisos (los mismos de la campana), asi que se pliega por
   frentes: una fila por categoria con su cuenta, y al abrirla salen todos sus renglones. Veinte
   categorias siguen cabiendo en un vistazo sin empujar la lista de obras fuera de la pantalla. */
.hoy-cab { display: flex; align-items: baseline; gap: 10px; }
.hoy-cuenta { font-size: 12.5px; color: var(--text-dim); }
.hoy-grupos { max-height: 42vh; overflow-y: auto; }
.hoy-grupo { border-left: 3px solid var(--border); padding-left: 8px; }
.hoy-grupo.n-mal { border-left-color: var(--red); }
.hoy-grupo.n-ojo { border-left-color: var(--amber); }
.hoy-grupo-cab { display: flex; align-items: center; gap: 8px; width: 100%; padding: 2px 0 !important; }
.hoy-grupo-cab:hover { text-decoration: none !important; }
.hoy-grupo-cab i { font-size: 14px; color: var(--text-dim); transition: transform .12s; }
.hoy-grupo.abierto .hoy-grupo-cab i { transform: rotate(90deg); }
.hoy-grupo-txt { flex: 1; }
.hoy-grupo-n { min-width: 1.6rem; text-align: center; font-size: 12.5px; font-variant-numeric: tabular-nums;
  color: var(--text-dim); border: 1px solid var(--border); border-radius: 999px; padding: 0 6px; }
.hoy-items { padding-left: 22px !important; margin: 2px 0 6px !important; }
/* Sin esta linea los frentes nacian abiertos: `hidden` vale display:none, pero .hoy-barra ul pone
   display:flex y le gana por especificidad — el mismo tropiezo que .proj-mando-extra. */
.hoy-items[hidden] { display: none; }
.hoy-items button { display: flex; flex-direction: column; gap: 1px; width: 100%; }
.hoy-item-t { font-size: 14px; }
.hoy-item-s { font-size: 12.5px; color: var(--text-dim); }

.proj-mando { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
/* El filtro de texto a la DERECHA: los botones de la línea (segmentos y "Más filtros") quedan
   juntos a la izquierda, que es por donde se empieza a leer y donde está la mano. */
.proj-mando > .filtro-lista { margin-left: auto; flex: 0 1 22rem; min-width: 12rem; }
/* Embudo, no lupa: la lupa es de "Buscar" (riel), que va a toda la empresa. Este acota lo que ya
   está en pantalla, y el icono lo dice antes de leer el texto. */
.filtro-lista { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16v2l-6 7v6l-4 2v-8L4 6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: 10px center; background-size: 16px;
  padding-left: 34px; }
.proj-mando-extra { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
/* SIN ESTO "Más filtros" no hacía nada: el atributo `hidden` vale display:none, pero la regla de
   arriba pone display:flex y le gana por especificidad. El elemento quedaba oculto en el DOM y
   visible en pantalla — o al revés, según se mire: el botón alternaba un atributo sin efecto. */
.proj-mando-extra[hidden] { display: none; }
.segmentos { display: flex; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.segmentos button { background: transparent; border: 0; border-right: 1px solid var(--border);
  padding: 7px 14px; font: inherit; font-size: 14px; color: var(--text-dim); cursor: pointer; }
.segmentos button:last-child { border-right: 0; }
.segmentos button:hover { background: var(--bg-elev); color: var(--text); }
.segmentos button[aria-pressed="true"] { background: var(--accent-2); color: #fff; }

.obra-lista { display: flex; flex-direction: column; gap: 6px; }
/* Rectangular a propósito: Faena viene de la obra, y el canto redondeado la vuelve una tarjeta
   de aplicación cualquiera. La franja de color llega a los dos bordes, sin recorte. */
.obra-fila { display: grid; grid-template-columns: 6px 4.5rem 1fr 12rem 4.5rem; gap: 14px;
  align-items: center; padding: 12px 16px 12px 0; background: var(--bg-panel);
  border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; cursor: pointer; }
.obra-fila:hover { border-color: var(--accent); }
.obra-fila:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Sin redondeo propio: la esquina la recorta la fila (overflow:hidden), así la franja sigue el
   canto de la caja sea cual sea el radio del tema y no hay dos valores que mantener en paralelo. */
.obra-franja { align-self: stretch; background: var(--text-dim);
  margin: -12px 0 -12px 0; }   /* llega arriba y abajo, anulando el relleno de la fila */
.obra-fila.salud-bien .obra-franja { background: var(--green); }
.obra-fila.salud-ojo .obra-franja { background: var(--amber); }
.obra-fila.salud-mal .obra-franja { background: var(--red); }
.obra-fila.salud-cerrado .obra-franja { background: var(--border); }
.obra-cod { font-family: "Oswald", sans-serif; letter-spacing: .04em; color: var(--text-dim); font-size: 16px; }
.obra-datos { min-width: 0; }
.obra-datos b { display: block; font-weight: 600; font-size: 17px; line-height: 1.25; }
.obra-datos em { font-style: normal; font-size: 13.5px; color: var(--text-dim); }
/* El motivo va en su propia línea: pegado al sub se leía como una sola frase — «no gira cheques
   L 1,158,694.83 sin conciliar» parecía decir algo que no dice. */
.obra-motivo { color: var(--red); display: block; }
.obra-fila.salud-ojo .obra-motivo { color: var(--amber); }
/* La barra es el avance REAL y la muesca dónde debería ir según el plazo consumido. Si la muesca
   queda por delante de la barra, la obra va atrasada — se ve sin leer un solo número. */
.obra-medidor { display: block; position: relative; height: 5px; margin-top: 6px;
  background: var(--bg-elev); border-radius: var(--radius); }
.obra-medidor > i { position: absolute; inset: 0 auto 0 0; background: var(--text-dim); border-radius: var(--radius); }
.obra-fila.salud-mal .obra-medidor > i { background: var(--red); }
.obra-fila.salud-bien .obra-medidor > i { background: var(--green); }
.obra-medidor > u { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--text); }
.obra-cifra { text-align: right; font-variant-numeric: tabular-nums; }
.obra-cifra b { display: block; font-weight: 600; font-size: 16px; }
.obra-cifra em { font-style: normal; font-size: 13px; color: var(--text-dim); }
.obra-plazo { text-align: right; }
.obra-plazo b { display: block; font-family: "Oswald", sans-serif; font-size: 1.7rem; line-height: 1;
  font-variant-numeric: tabular-nums; }
.obra-fila.salud-mal .obra-plazo b { color: var(--red); }
.obra-plazo em { font-style: normal; font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-dim); }
@media (max-width: 760px) {
  .obra-fila { grid-template-columns: 6px 3.5rem 1fr auto; }
  .obra-cifra { display: none; }
}

/* ---------- PROGRESO DE IMPORTACIÓN ----------
   Una línea de texto que cambia cada 20 segundos no distingue "trabajando" de "colgado". Esto da
   las tres señales que sí lo distinguen: algo que se MUEVE siempre (el aro), CUÁNTO falta (la
   barra y el contador) y QUÉ está pasando ahora (la fase). */
.imp-progreso { display: flex; align-items: center; gap: 12px; padding: 12px 14px; margin-top: 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 7%, transparent); }
.imp-aro { width: 26px; height: 26px; flex-shrink: 0; border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--accent) 25%, transparent);
  border-top-color: var(--accent); animation: spin .8s linear infinite; }
.imp-txt { flex: 1; min-width: 0; }
.imp-fase { font-weight: 600; font-size: 14px; }
.imp-detalle { font-size: 12.5px; color: var(--text-dim); }
.imp-barra { height: 5px; margin-top: 6px; border-radius: 3px; overflow: hidden;
  background: color-mix(in srgb, var(--text-dim) 18%, transparent); }
.imp-barra > span { display: block; height: 100%; background: var(--accent); border-radius: 3px;
  transition: width .2s ease; }
/* Indeterminada: cuando aún no se sabe cuánto falta (lectura del documento), la barra se pasea
   para que se vea que hay actividad. */
.imp-barra.indet > span { width: 35%; animation: imp-vaiven 1.1s ease-in-out infinite; }
@keyframes imp-vaiven { 0% { margin-left: -35%; } 100% { margin-left: 100%; } }
/* Estados finales: el aro deja de girar y se vuelve marca, y la barra toma el color del resultado
   — una barra azul llena junto a un mensaje de error se leía como "sigue trabajando". */
.imp-progreso.ok .imp-aro, .imp-progreso.mal .imp-aro { animation: none; border-width: 2px;
  display: flex; align-items: center; justify-content: center; font-size: 16px; font-weight: 700; }
.imp-progreso.ok { border-color: color-mix(in srgb, var(--green) 45%, transparent);
  background: color-mix(in srgb, var(--green) 8%, transparent); }
.imp-progreso.ok .imp-aro { border-color: var(--green); color: var(--green); }
.imp-progreso.ok .imp-aro::after { content: "\2713"; }
.imp-progreso.ok .imp-fase { color: var(--green); }
.imp-progreso.ok .imp-barra > span { background: var(--green); }
.imp-progreso.mal { border-color: color-mix(in srgb, var(--red) 45%, transparent);
  background: color-mix(in srgb, var(--red) 8%, transparent); }
.imp-progreso.mal .imp-aro { border-color: var(--red); color: var(--red); }
.imp-progreso.mal .imp-aro::after { content: "!"; }
.imp-progreso.mal .imp-fase { color: var(--red); }
.imp-progreso.mal .imp-barra > span { background: var(--red); }

/* ---------- BARRA DE ESTADO del pie del Gantt ---------- */
/* Va pegada al fondo del marco: al pasar el ratón por una fila o por el diagrama, resume abajo la
   fecha bajo el puntero, el capítulo, la actividad y sus cifras, sin abrir nada ni subir la vista. */
/* Una línea SIEMPRE: con `flex-wrap: wrap` la barra se partía en cuatro renglones al estrecharse y
   pasaba de 28 a 121 px de alto, empujando el diagrama. Se deja sin envolver y lo que no cabe se
   recorta por la derecha, que es donde van los datos menos importantes. */
.g-estado { position: sticky; bottom: 0; z-index: 13; display: flex; align-items: center;
  gap: 16px; flex-wrap: nowrap; overflow: hidden; padding: 0 14px; height: 34px;
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-panel));
  border-top: 2px solid var(--accent);
  box-shadow: 0 -3px 10px rgba(0,0,0,.10);
  font-size: 13px; color: var(--text); white-space: nowrap; }
.g-estado .ge-d { flex: 0 0 auto; }
/* El nombre de la actividad es lo único que puede ser larguísimo: que ceda él y no los demás. */
.g-estado .ge-d:nth-child(3) { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.g-estado .ge-d { display: inline-flex; align-items: baseline; gap: 5px; }
.g-estado .ge-d em { font-style: normal; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .5px; color: var(--text-dim); opacity: .8; font-weight: 700; }
.g-estado .ge-d { font-weight: 500; }
/* La fecha bajo el puntero es el dato que más se busca: va como pastilla, no como texto suelto. */
.g-estado .ge-fecha { font-variant-numeric: tabular-nums; font-weight: 700;
  background: var(--accent); color: #fff; padding: 2px 9px; border-radius: 999px; }
.g-estado .ge-fecha em { color: #fff; opacity: .7; }
.g-estado .ge-crit { color: var(--red); font-weight: 600; }
.g-estado .ge-hint { margin-left: auto; color: var(--text-dim); opacity: .6; font-size: 11.5px; }

/* ---------- IMPRESIÓN / EXPORTAR A PDF ---------- */
/* En pantalla, `position: sticky` solo actúa al hacer scroll. Al imprimir no hay scroll, y el
   navegador coloca cada elemento pegajoso DESPLAZADO hacia abajo por su valor de `top`: las celdas
   de la cabecera se separaban de su propia fila (que quedaba vacía) y caían encima de las filas
   siguientes, tapándolas — en el Gantt, la cabecera aterrizaba sobre el segundo capítulo y ese
   capítulo desaparecía del papel. En impresión nada debe ir pegajoso: todo vuelve al flujo. */
@media print {
  .topbar, .gantt-cab, .gantt-ribbon, .g-scale-fix, .g-estado,
  .gantt2-tasks th, .presu-tabla thead th, .apu-index-panel, .apu-toolbar, .toolbar {
    position: static !important; top: auto !important; }
  /* La escala se desplaza con `transform` para seguir al scroll horizontal; en papel no hay scroll. */
  .g-scale { transform: none !important; }
  .g-scale-fix { overflow: visible !important; }
  /* Que la cabecera se repita en cada hoja y que no se parta una fila por la mitad. */
  .gantt2-tasks thead { display: table-header-group; }
  .gantt2-tasks tr, .presu-tabla tr { break-inside: avoid; page-break-inside: avoid; }
  /* Las sombras y los degradados se imprimen como manchas grises: fuera. */
  .g-bar, .g-chapbar, .g-hito-mark, .gantt2-wrap, .gantt-ribbon { box-shadow: none !important; }
}

/* ---------------------------------------------------------------------------
   SUBCONTRATO — modal a pantalla completa con dos columnas
   El encabezado son datos que se llenan una vez; el alcance es lo que se arma
   renglón por renglón y lo que se revisa, así que se lleva el espacio.
   --------------------------------------------------------------------------- */
.modal.modal-full { max-width: min(1500px, 96vw); width: 96vw; height: 92vh; display: flex; flex-direction: column; }
.modal.modal-full .modal-body { flex: 1; overflow: auto; }
/* Encabezado: una sola banda de campos apretados, con etiquetas pequeñas. */
.ct-cab { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: flex-end;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius);
  background: color-mix(in srgb, var(--text-dim) 5%, transparent); margin-bottom: 10px; }
.ct-cab .ct-campo { display: flex; flex-direction: column; gap: 2px; }
.ct-cab .ct-campo label { font-size: 11.5px; color: var(--text-dim); font-weight: 600;
  text-transform: uppercase; letter-spacing: .02em; }
.ct-cab .ct-campo input, .ct-cab .ct-campo select { padding: 5px 7px; font-size: 13.5px; }
/* DOBLE PANTALLA HORIZONTAL: arriba se elige, abajo se forma el subcontrato. Cada mitad a todo el
   ancho y con su propio desplazamiento — así las cifras caben en columnas etiquetadas y elegir
   arriba no empuja la tabla de abajo fuera de la vista. */
.ct-arriba, .ct-abajo { min-width: 0; }
.ct-arriba { border-bottom: 1px solid var(--border); padding-bottom: 10px; margin-bottom: 12px; }
.ct-picker { max-height: 34vh; overflow: auto; }
.ct-abajo .table-wrap { max-height: 34vh; overflow: auto; }
/* La cabecera de cada tabla se queda fija dentro de su mitad. */
.ct-picker thead th, .ct-abajo .table-wrap thead th { position: sticky; top: 0; z-index: 2;
  background: var(--bg-panel); }
.ct-picker tfoot th { position: sticky; bottom: 0; background: var(--bg-panel); }
/* Fila de capítulo: se distingue y se pliega con un clic. */
.ct-picker .ct-cap-row { cursor: pointer; background: color-mix(in srgb, var(--text-dim) 7%, transparent); }
.ct-picker .ct-cap-row:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.ct-picker .ct-ya { opacity: .5; }

/* ---------------------------------------------------------------------------
   BOTONERA COMPACTA — norma de la casa (jul 2026)
   En el pie de cualquier caja de diálogo, lo SECUNDARIO va en iconos de 32px con
   su tooltip completo y solo la acción del momento lleva texto. Ocho botones con
   letra convertían el pie en una segunda barra de herramientas. Los colores salen
   de las variables del tema (--accent, --red), nunca de estilos sueltos, para que
   siga al claro y al oscuro sin tocar nada.
   Uso:  <div class="acc-bar"><button class="acc-btn" title="…"><i …></i></button></div>
         acc-btn-danger para lo destructivo.
   --------------------------------------------------------------------------- */
.acc-bar, .ct-acciones { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.acc-btn, .ct-acciones .ct-acc { width: 32px; height: 32px; border: 1px solid var(--border);
  border-radius: 8px; display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-dim); background: var(--bg-panel); cursor: pointer;
  transition: color .12s, border-color .12s, background .12s; }
.acc-btn:hover, .ct-acciones .ct-acc:hover { color: var(--accent); border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, var(--bg-panel)); }
.acc-btn i, .ct-acciones .ct-acc i { font-size: 17px; }
.acc-btn[disabled] { opacity: .4; cursor: default; }
.acc-btn-danger:hover, .ct-acciones .ct-acc-danger:hover { color: var(--red); border-color: var(--red);
  background: color-mix(in srgb, var(--red) 10%, var(--bg-panel)); }

/* Capítulo aislado por doble clic en su fila: se marca el que quedó visible. */
.ct-picker .ct-cap-row.ct-filtrado { background: color-mix(in srgb, var(--accent) 16%, transparent); }

/* ---------------------------------------------------------------------------
   AVANCES DE OBRA — un renglón por CONTRATISTA
   Mismo idioma que la portada: franja de estado en el canto, medidor con muesca
   (barra = lo ejecutado, muesca = dónde debería ir según el plazo consumido) y
   cifra grande a la derecha. Si la muesca queda por delante de la barra, ese
   contratista va atrasado — se ve sin leer un número.
   --------------------------------------------------------------------------- */
.obra-fila.contra-fila { grid-template-columns: 6px 5.5rem 1fr 11rem 4.5rem 10.5rem; }
@media (max-width: 900px) {
  .obra-fila.contra-fila { grid-template-columns: 6px 1fr auto; }
  .obra-fila.contra-fila .obra-cifra, .obra-fila.contra-fila .obra-cod { display: none; }
}
.contra-accion { text-align: right; }
/* Resumen de contratación: una franja, no un tablero. El Kanban se abre si se pide. */
.contra-resumen { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 10px 14px; margin: 4px 0 14px; background: var(--bg-panel);
  border: 1px solid var(--border); border-radius: var(--radius); }
.contra-resumen .cr-dato { display: flex; align-items: baseline; gap: 6px; }
.contra-resumen .cr-dato b { font-family: "Oswald", sans-serif; font-size: 1.35rem; line-height: 1;
  font-variant-numeric: tabular-nums; }
.contra-resumen .cr-dato em { font-style: normal; font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-dim); }
.contra-resumen .cr-sin b { color: var(--red); }
.contra-resumen .cr-par b { color: var(--amber); }
.contra-resumen .cr-con b { color: var(--green); }
/* Barra de cuánto de la obra está colocada: una sola línea que se entiende de un golpe. */
.contra-barra { flex: 1; min-width: 140px; height: 6px; background: var(--bg-elev);
  border-radius: var(--radius); overflow: hidden; display: flex; }
.contra-barra i { display: block; height: 100%; }

/* Costo por naturaleza: barras proporcionales. La proporción se ve de un golpe y los números siguen. */
.cat-barras { display: flex; flex-direction: column; gap: 5px; }
.cat-fila { display: grid; grid-template-columns: 9rem 1fr 8rem 4rem; gap: 10px; align-items: center; }
.cat-barra { height: 8px; background: var(--bg-elev); border-radius: var(--radius); overflow: hidden; }
.cat-barra i { display: block; height: 100%; background: var(--accent); }
.cat-fila b { text-align: right; font-variant-numeric: tabular-nums; }
.cat-fila em { font-style: normal; text-align: right; color: var(--text-dim); font-size: 12px; }
.cat-fila.cat-total { border-top: 1px solid var(--border); padding-top: 5px; font-weight: 700; }
@media (max-width: 700px) { .cat-fila { grid-template-columns: 7rem 1fr 6.5rem; } .cat-fila em { display: none; } }

/* Peso de cada capítulo y partida dentro del índice del presupuesto: una barra fina contra el
   mayor. El índice era una lista de nombres; con esto dice dónde está el dinero. */
.apu-index-panel .idx-peso { display: flex; align-items: center; gap: 6px; padding: 0 8px 4px 30px; }
.apu-index-panel .idx-barra { flex: 1; height: 4px; background: var(--bg-elev); border-radius: var(--radius); overflow: hidden; }
.apu-index-panel .idx-barra i { display: block; height: 100%; background: var(--accent); opacity: .75; }
.apu-index-panel .idx-peso em { font-style: normal; font-size: 11px; color: var(--text-dim);
  font-variant-numeric: tabular-nums; min-width: 2.6rem; text-align: right; }
.apu-index-panel .idx-peso-part { flex: 0 0 46px; padding: 0; margin-left: auto; }
.apu-index-panel .idx-peso-part .idx-barra { height: 3px; }

/* De qué está hecho el precio unitario: una barra por naturaleza, proporcional al costo directo.
   Es la pregunta del APU y antes había que sumar los subtotales a ojo. */
.apu-composicion { padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); margin: 0 0 10px; width: 100%; box-sizing: border-box; }
.apu-comp-barra { display: flex; height: 10px; border-radius: var(--radius); overflow: hidden;
  background: var(--bg-elev); }
/* flex-shrink:0 — sin esto los segmentos con ancho en % se encogen dentro del contenedor flex y la
   barra se queda en nada. */
.apu-comp-barra i { display: block; height: 100%; flex: 0 0 auto; min-width: 1px; }
.apu-comp-datos { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 7px; }
.apu-comp-dato { display: flex; align-items: baseline; gap: 5px; font-size: 12px; }
.apu-comp-dato > i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
.apu-comp-dato b { font-weight: 600; }
.apu-comp-dato em { font-style: normal; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.apu-comp-dato.apu-comp-total b, .apu-comp-dato.apu-comp-total em { color: var(--accent); font-weight: 700; }

/* Emparejar a mano en la auditoría: el selector y su botón, juntos y compactos. */
.audit-emparejar { display: inline-flex; align-items: center; gap: 4px; margin-right: 6px; }
.audit-emparejar select { max-width: 260px; padding: 4px 6px; font-size: 12px; }

/* ---------------------------------------------------------------------------
   ESTIMACIÓN EN PANTALLA. Es EL MISMO documento que se imprime (una sola función lo arma), así que
   aquí solo se le pone la ropa del tema: los grises del papel no pegan en la pantalla oscura y la
   celda de captura tiene que verse capturable. La estructura —cuatro grupos de columnas, capítulos
   en romano, sub-totales, liquidación y firmas— viene del documento y no se toca desde aquí.
   --------------------------------------------------------------------------- */
.est-pantalla { font-size: 12px; color: var(--text); overflow-x: auto; }
.est-pantalla .est-datos { width: 100%; border-collapse: collapse; margin-bottom: 10px; font-size: 13px; }
.est-pantalla .est-datos td { padding: 2px 0; border: none; }
.est-pantalla .est-datos td:last-child { text-align: right; }
.est-pantalla .est-tabla { width: 100%; min-width: 1080px; border-collapse: collapse; table-layout: fixed; }
.est-pantalla .est-tabla th, .est-pantalla .est-tabla td {
  border: 1px solid var(--border); padding: 4px 5px; vertical-align: top; line-height: 1.3; }
.est-pantalla .est-tabla thead th { background: var(--bg-elev); color: var(--text-dim);
  text-align: center; font-size: 11px; font-weight: 700; vertical-align: middle; letter-spacing: .02em; }
.est-pantalla .est-tabla .e-n { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.est-pantalla .est-tabla .e-mon { float: left; color: var(--text-dim); }
.est-pantalla .est-tabla .e-cl { width: 4%; }
.est-pantalla .est-tabla .e-de { width: 20%; }
.est-pantalla .est-tabla .e-un { width: 4%; text-align: center; }
.est-pantalla .est-tabla .e-vacia { width: 2.5%; }
.est-pantalla .est-tabla .e-cap td { background: var(--bg-elev); font-weight: 700; letter-spacing: .04em; }
.est-pantalla .est-tabla .e-sub td, .est-pantalla .est-tabla .e-gran td { font-weight: 700; }
.est-pantalla .est-tabla .e-gran td { background: var(--bg-elev); }
.est-pantalla .est-tabla .e-sublbl { text-align: right; }
/* La columna que se captura: es la única casilla viva de la hoja. */
.est-pantalla .e-cap-per { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.est-pantalla .est-cant { width: 100%; min-width: 64px; padding: 2px 4px; text-align: right;
  font: inherit; font-variant-numeric: tabular-nums; color: var(--text);
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 3px; }
.est-pantalla .est-cant:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.est-pantalla .est-cant:disabled { background: transparent; border-color: transparent; color: var(--text-dim); }
.est-pantalla .est-cierre { margin-top: 16px; }
.est-pantalla .est-liq { width: 60%; min-width: 420px; margin-left: auto; border-collapse: collapse; font-size: 12.5px; }
.est-pantalla .est-liq th, .est-pantalla .est-liq td { border: 1px solid var(--border); padding: 5px 7px; }
.est-pantalla .est-liq th { background: var(--bg-elev); color: var(--text-dim); text-align: center; font-size: 11px; }
.est-pantalla .est-liq .e-lbl { width: 40%; text-align: left; }
.est-pantalla .est-liq .e-n { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.est-pantalla .est-liq .e-mon { float: left; color: var(--text-dim); }
.est-pantalla .est-liq .e-neto td { font-weight: 700; }
.est-pantalla .est-total-caja { width: 42%; min-width: 300px; margin: 8px 0 0 auto;
  border-collapse: collapse; font-size: 14px; font-weight: 700; }
.est-pantalla .est-total-caja td { border: 1px solid var(--accent); padding: 8px; }
.est-pantalla .est-total-caja td:last-child { text-align: right; color: var(--accent);
  font-variant-numeric: tabular-nums; }
/* Las firmas son de papel: en pantalla estorban. */
.est-pantalla .est-firmas { display: none; }
/* Encabezado de la estimación en pantalla: misma jerarquía que en papel, con el estado a la vista. */
.est-pantalla .est-datos .e-k { font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--text-dim); }
.est-pantalla .est-datos .e-v { font-size: 18px; font-weight: 700; line-height: 1.2; }
.est-pantalla .est-datos .e-sub2 { font-size: 12px; color: var(--text-dim); }
.est-pantalla .est-datos .e-estado { display: inline-block; margin-left: 8px; padding: 1px 8px;
  border: 1px solid var(--border); border-radius: 999px; font-size: 10px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); vertical-align: middle; }
.est-pantalla .est-datos .e-estado-borrador { border-color: var(--amber); color: var(--amber); }
.est-pantalla .est-datos .e-estado-pagada { border-color: var(--green); color: var(--green); }
/* Sin retícula también en pantalla: la hoja es la misma. */
.est-pantalla .est-tabla th, .est-pantalla .est-tabla td { border: none; }
.est-pantalla .est-tabla tbody td { border-bottom: 1px solid var(--border); }
.est-pantalla .est-tabla .e-gsep { border-left: 1px solid var(--border); }
.est-pantalla .est-tabla thead tr.e-g th { border-bottom: 1px solid var(--border); }
.est-pantalla .est-tabla thead tr.e-g2 th { border-bottom: 2px solid var(--text-dim); }
.est-pantalla .est-tabla thead th { background: none; }
.est-pantalla .est-tabla .e-cap td { background: none; border-bottom: 2px solid var(--text-dim); padding-top: 14px; }
.est-pantalla .est-tabla .e-sub td { border-top: 2px solid var(--text-dim); border-bottom: none; }
.est-pantalla .est-tabla .e-gran td { background: none; border-top: 2px solid var(--text); border-bottom: 4px double var(--text); }
.est-pantalla .est-liq th, .est-pantalla .est-liq td { border: none; }
.est-pantalla .est-liq tbody td { border-bottom: 1px solid var(--border); }
.est-pantalla .est-liq thead th { border-bottom: 2px solid var(--text-dim); }
.est-pantalla .est-liq .e-neto td { border-top: 2px solid var(--text-dim); border-bottom: none; }
.est-pantalla .est-total-caja td { border: none; border-top: 2px solid var(--accent); border-bottom: 2px solid var(--accent); }

/* ---------------------------------------------------------------------------
   EL DINERO DE LA IA (caja "Mi clave de IA"). Tres cifras arriba —mes, hoy, histórico—, el
   desglose por función con su barra, y el estado del tope de la empresa cuando el usuario todavía
   no puso su clave. Todo con variables del tema.
   --------------------------------------------------------------------------- */
.ia-gasto { margin: 10px 0 4px; }
.ia-cifras { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ia-cifras > div { padding: 7px 9px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-elev); }
.ia-k { font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); }
.ia-v { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; margin-top: 1px; }
.ia-s { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
.ia-s .sube { color: var(--red); } .ia-s .baja { color: var(--green); }
.ia-s.mal { color: var(--red); }
.ia-funciones { list-style: none; margin: 5px 0 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.ia-funciones li { display: grid; grid-template-columns: 1fr 4.5rem 4rem 2.2rem; gap: 8px;
  align-items: center; font-size: 12.5px; }
.ia-f-n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ia-f-b { height: 5px; background: var(--border); border-radius: 3px; overflow: hidden; }
.ia-f-b i { display: block; height: 100%; background: var(--accent); }
.ia-f-c { text-align: right; font-variant-numeric: tabular-nums; }
.ia-f-l { text-align: right; color: var(--text-dim); font-size: 11.5px; }
.ia-empresa { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); }
.ia-tope { height: 6px; margin-top: 5px; background: var(--border); border-radius: 3px; overflow: hidden; }
.ia-tope i { display: block; height: 100%; background: var(--accent); }
.ia-tope i.ojo { background: var(--amber); } .ia-tope i.mal { background: var(--red); }
/* Barra de la estimación: la nota de qué es esta hoja y el selector de conceptos, en una línea. */
.est-mando { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.est-mando .segmentos { flex: 0 0 auto; }
/* Aviso de que la hoja está acotada por un filtro (también en papel). */
.est-doc .e-filtro { font-size: 8px; color: #8a6d3b; margin-top: 3px; letter-spacing: .02em; }
.est-pantalla .e-filtro { font-size: 11.5px; color: var(--amber); }

/* ---------------------------------------------------------------------------
   FIRMAS DE LOS DOCUMENTOS (Empresa › Firmas). Cada bloque dice quién firma y en qué documentos
   aparece; los documentos las leen con firmasDeDocumento().
   --------------------------------------------------------------------------- */
.firma-fila { padding: 10px 0; border-bottom: 1px solid var(--border); }
.firma-fila:last-child { border-bottom: 0; }
.firma-campos { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.firma-campos .field { margin: 0; flex: 1 1 180px; }
.firma-docs { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 8px; }
.firma-docs-k { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); margin-right: 2px; }
.firma-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 999px; font-size: 12.5px; color: var(--text-dim); }
.firma-chip input { width: 13px; height: 13px; margin: 0; }
.firma-chip.on { border-color: var(--accent); color: var(--text); background: color-mix(in srgb, var(--accent) 10%, transparent); }

/* ---------------------------------------------------------------------------
   «CÓMO SALE ESTE DOCUMENTO»: el bloque de papel, orientación y firmas que llevan TODOS los
   diálogos de impresión. Plegado por defecto —lo normal es imprimir sin tocar nada— y con el
   resumen a la vista para saber qué va a salir sin abrirlo.
   --------------------------------------------------------------------------- */
.pf-papel { margin-top: 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-elev); }
.pf-papel > summary { display: flex; align-items: center; gap: 8px; padding: 8px 10px; cursor: pointer;
  font-size: 13.5px; font-weight: 600; list-style: none; }
.pf-papel > summary::-webkit-details-marker { display: none; }
.pf-papel > summary::after { content: "▾"; margin-left: auto; color: var(--text-dim); font-size: 11px; }
.pf-papel[open] > summary::after { content: "▴"; }
.pf-papel .pf-resumen { font-weight: 400; font-size: 12px; color: var(--text-dim); }
.pf-papel .pf-papel-cuerpo { padding: 0 10px 10px; border-top: 1px solid var(--border); }
.pf-papel .field-row { margin-top: 10px; }
.pf-papel .field { margin: 0; }
.pf-firmas { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 10px; }
.pf-firmas-k { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); }
.pf-firma-chip { padding: 2px 8px; border: 1px solid var(--border); border-radius: 999px; font-size: 12px; }

/* A dónde se fue el material (Bodega): el renglón por sujeto —actividad o contratista— y su
   detalle plegado. Mismo lenguaje que las demás listas de Faena. */
.bod-fila { grid-template-columns: 6px 5rem 1fr 9rem 1.6rem; }
.bod-fila.abierta .obra-chev i { transform: rotate(180deg); }
.obra-chev { color: var(--text-dim); display: flex; justify-content: center; }
.obra-chev i { transition: transform .12s; }
.bod-detalle { margin: -4px 0 8px 0; padding: 8px 16px 10px; background: var(--bg-panel);
  border: 1px solid var(--border); border-top: 0; border-radius: 0 0 var(--radius) var(--radius); }
.bod-detalle table { width: 100%; border-collapse: collapse; font-size: 13px; }
.bod-detalle th { text-align: left; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim); padding: 2px 6px; border-bottom: 1px solid var(--border); }
.bod-detalle td { padding: 3px 6px; border-bottom: 1px solid var(--border); }
.bod-detalle .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Pasarse del previsto del APU es el renglón que hay que mirar. */
.bod-detalle .bod-excede td { color: var(--red); }
/* El título y su explicación son dos líneas, no una frase pegada. */
.bod-fila .obra-tit strong, .bod-fila .obra-tit .sub { display: block; }
.bod-fila .obra-num strong, .bod-fila .obra-num .sub { display: block; }
.bod-fila .obra-num { text-align: right; }

/* Cifras de cabecera de la bodega central y del parque de equipo. */
.cifras-fila { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
.cifras-fila > div { padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); }

/* Finanzas: el pie del pago (lo que se salda vs. lo que sale de la cuenta) y los movimientos. */
.pg-total { display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); font-size: 13.5px; }
.pg-total .pg-neto { font-size: 15px; }
tr.mov-anulado { opacity: .5; text-decoration: line-through; }
td.num.mal { color: var(--red); } td.num.ojo { color: var(--amber); }

/* Catálogo de cuentas: se lee como un plan contable — por código, con la jerarquía sangrada. */
.cc-tabla .cc-cod { font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--text-dim); }
.cc-tabla tr.cc-grupo { background: var(--bg-elev); }
.cc-tabla tr.cc-grupo td { font-weight: 600; }
.cc-tabla tr.cc-inactiva { opacity: .5; }
/* Gráficos de Finanzas: se dibujan con las variables del tema, sin librerías. */
.fin-svg { width: 100%; height: auto; background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: var(--radius); }
.fin-svg-tx { font-size: 11px; fill: var(--text-dim); }
/* Barra de filtros de la búsqueda de movimientos. */
.bq-filtros { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; margin-bottom: 12px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-panel); }
.bq-filtros .field { margin: 0; }

/* ---------------------------------------------------------------------------
   FRANJA DE MANDO DE FINANZAS. Las tres cifras que se consultan a cada rato —cuánto hay, cuánto se
   debe, cuánto deben— no pueden vivir dentro de una pestaña: obligarían a ir y volver. Van arriba,
   siempre, con la franja de color a la izquierda como el resto de Faena.
   --------------------------------------------------------------------------- */
.fin-mando { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 1px;
  margin: 6px 0 10px; background: var(--border); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; }
.fin-mando-cifra { display: flex; flex-direction: column; gap: 1px; padding: 9px 14px;
  background: var(--bg-panel); border-left: 3px solid transparent; }
.fin-mando-cifra.n-mal { border-left-color: var(--red); }
.fin-mando-cifra.fm-pos { border-left-color: var(--accent); }
.fin-mando .fm-k { font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
.fin-mando .fm-v { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.15; }
.fin-mando .fm-s { font-size: 11.5px; color: var(--text-dim); }
.fin-mando-cifra.n-mal .fm-v, .fin-mando-cifra.n-mal .fm-s { color: var(--red); }
/* Las pestañas de segundo nivel, más discretas que los espacios: la jerarquía se ve, no se lee. */
.espacios + .tabs .tab { font-size: 14px; }

/* ---------------------------------------------------------------------------
   TABLERO DE LA EMPRESA. Bloques por pregunta, no por módulo: el dueño no piensa en «finanzas» y
   «ejecución», piensa en «¿tengo con qué pagar?» y «¿esto deja dinero?».
   --------------------------------------------------------------------------- */
.tb-bloque { margin-bottom: 16px; }
.tb-bloque-tit { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim);
  margin-bottom: 6px; }
.tb-cifras { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 1px;
  background: var(--border); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.tb-cifra { display: flex; flex-direction: column; gap: 2px; padding: 11px 14px; background: var(--bg-panel);
  border-left: 3px solid transparent; }
.tb-cifra.n-mal { border-left-color: var(--red); }
.tb-cifra.n-ojo { border-left-color: var(--amber); }
.tb-cifra.n-bien { border-left-color: var(--green); }
.tb-k { font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
.tb-v { font-size: 21px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.1; }
.tb-s { font-size: 11.5px; color: var(--text-dim); }
.tb-cifra.n-mal .tb-v { color: var(--red); }

/* Los graficos del tablero. Dos por fila en pantalla ancha y uno por fila en cuanto no caben:
   un grafico angosto no se lee, se adivina. */
.tb-graficos { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: 14px; margin: 6px 0 18px; }
.tb-fig { margin: 0; min-width: 0; }
.tb-fig figcaption { display: flex; flex-direction: column; gap: 2px; margin-bottom: 6px; }
.tb-fig-tit { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); }
/* La lectura: la frase que dice QUE hay que ver en el dibujo. Va en tinta de texto —nunca del
   color de una serie— y lo que se resalta lleva su palabra, no solo su color. */
.tb-fig-sub { font-size: 13.5px; color: var(--text); }
.tb-fig-sub .mal { color: var(--red); }
.tb-fig-sub .ojo { color: var(--amber); }
.tb-svg-val { font-weight: 600; fill: var(--text); font-variant-numeric: tabular-nums; }
.tb-svg-val-in { font-weight: 600; fill: var(--bg-panel); font-variant-numeric: tabular-nums; }
.tb-svg-apilada { height: 54px; padding: 0; border: none; background: none; }
.tb-leyenda { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px; font-size: 12.5px; color: var(--text-dim); }
.tb-chip { display: inline-flex; align-items: center; gap: 6px; }
.tb-chip i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; flex: 0 0 auto; }
.tb-chip strong { color: var(--text); font-variant-numeric: tabular-nums; }
/* La tabla de cada grafico: cerrada por defecto para no romper la lectura, pero SIEMPRE presente
   —es la version que lee un lector de pantalla, la que se copia y la que zanja una discusion. */
.tb-tabla { margin-top: 6px; }
.tb-tabla > summary { cursor: pointer; font-size: 12.5px; color: var(--text-dim); padding: 3px 0; }
.tb-tabla > summary:hover { color: var(--text); }

/* ---------------------------------------------------------------------------
   MODO CAMPO. La misma app, pero para el teléfono: de pie, con una mano, con guantes y con sol en
   la pantalla. Botones grandes (48px es el mínimo para un dedo), contraste alto y nada que exija
   apuntar con precisión. El riel se oculta: en obra no se navega, se apunta.
   --------------------------------------------------------------------------- */
body.modo-campo .riel { display: none; }
body.modo-campo #app { margin-left: 0; padding: 0 12px 24px; max-width: 760px; }
.campo-top { display: flex; align-items: center; gap: 10px; padding: 12px 0 8px; }
.campo-volver { width: 40px; height: 40px; flex: 0 0 40px; border: 1px solid var(--border);
  background: var(--bg-panel); border-radius: 10px; color: var(--text); font-size: 20px; cursor: pointer; }
.campo-obra { font-size: 17px; font-weight: 700; line-height: 1.2; }
.campo-fecha { font-size: 12.5px; color: var(--text-dim); }
.campo-acciones { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; margin: 6px 0; }
.campo-btn { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  min-height: 84px; padding: 10px; cursor: pointer; color: var(--text); font: inherit; font-weight: 600;
  background: var(--bg-panel); border: 1px solid var(--border); border-top: 3px solid var(--c, var(--accent));
  border-radius: var(--radius); }
.campo-btn i { font-size: 26px; color: var(--c, var(--accent)); }
.campo-btn:active { background: var(--bg-elev); }
.campo-mas { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.campo-aviso { display: flex; align-items: center; gap: 8px; padding: 9px 12px; margin-bottom: 10px;
  border-left: 3px solid var(--red); background: color-mix(in srgb, var(--red) 8%, transparent);
  border-radius: var(--radius); font-size: 13.5px; }
.campo-hoy { font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim);
  margin: 14px 0 6px; }
.campo-apunte { display: flex; gap: 10px; padding: 10px 12px; margin-bottom: 6px; cursor: pointer;
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius); }
.campo-apunte.abierto { border-left: 3px solid var(--red); }
.campo-ap-icono { width: 34px; height: 34px; flex: 0 0 34px; display: flex; align-items: center;
  justify-content: center; border-radius: 8px; background: var(--bg-elev); }
.campo-ap-icono i { font-size: 19px; color: var(--c, var(--accent)); }
.campo-ap-tit { font-weight: 600; line-height: 1.25; }
.campo-ap-sub { font-size: 12px; color: var(--text-dim); margin-top: 1px; }
.campo-ap-det { font-size: 13px; margin-top: 3px; }
.campo-ap-badge { display: inline-block; margin-top: 5px; padding: 1px 8px; border-radius: 999px;
  font-size: 11.5px; border: 1px solid var(--border); color: var(--text-dim); }
.campo-ap-badge.mal { border-color: var(--red); color: var(--red); }
.campo-ap-badge.ok { border-color: var(--green); color: var(--green); }
.campo-ap-badge.pend { border-color: var(--amber); color: var(--amber); }
.campo-fotos { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.campo-fotos img { width: 74px; height: 74px; object-fit: cover; border-radius: 8px; border: 1px solid var(--border); }
.campo-fotos.grande img { width: 46%; height: auto; max-height: 260px; }

/* Pase de lista: una fila por persona, con los cuatro botones de jornada al alcance del pulgar. */
.pl-lista { display: flex; flex-direction: column; gap: 6px; }
.pl-fila { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; padding: 8px 10px;
  border: 1px solid var(--border); border-left: 3px solid transparent; border-radius: var(--radius);
  background: var(--bg-panel); }
.pl-fila.presente { border-left-color: var(--green); }
.pl-fila.bloqueada { opacity: .6; }
.pl-quien { flex: 1 1 10rem; display: flex; flex-direction: column; }
.pl-quien span { font-size: 12px; color: var(--text-dim); }
.pl-jornadas { display: flex; gap: 4px; }
.pl-jornadas button { min-width: 62px; min-height: 40px; padding: 0 10px; cursor: pointer;
  border: 1px solid var(--border); background: transparent; color: var(--text); border-radius: 8px;
  font: inherit; font-size: 13px; }
.pl-jornadas button.on { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.pl-salario { width: 6.5rem; }

/* Plano con chinchetas: coordenadas relativas, así valen a cualquier zoom. */
.plano-caja { position: relative; display: inline-block; max-width: 100%; border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; }
.plano-caja img { display: block; max-width: 100%; height: auto; cursor: crosshair; }
.plano-marca { position: absolute; transform: translate(-50%, -50%); width: 30px; height: 30px;
  border-radius: 50%; border: 2px solid #fff; background: var(--accent); color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center; box-shadow: 0 1px 5px rgba(0,0,0,.4); }
.plano-marca i { font-size: 15px; }
.plano-marca.m-incidencia { background: var(--amber); }
.plano-marca.m-incidencia.abierta { background: var(--red); }
.plano-marca.m-avance { background: var(--green); }

@media (max-width: 700px) {
  .campo-acciones { grid-template-columns: repeat(2, 1fr); }
  .pl-jornadas { width: 100%; }
  .pl-jornadas button { flex: 1; }
}


/* ===== DATOS Y USUARIOS ===== La gente va en RENGLON, como las obras y los contratistas: una
   persona es un sujeto, no una fila de un documento. Sus mandos —perfil, permiso de IA y baja—
   viajan en el hueco de accion del renglon, sin sacarlos a una columna propia. */
/* El renglon de una persona no tiene «cifra» ni «plazo» —no hay dinero ni fecha de entrega que
   poner—, asi que esas dos columnas se retiran y el espacio se lo queda la botonera, que aqui es
   ancha: perfil, permiso de IA y baja. */
.obra-fila.contra-fila.usr-fila { grid-template-columns: 6px 3.2rem 1fr 21rem; }
.usr-fila .obra-cifra, .usr-fila .obra-plazo { display: none; }
@media (max-width: 900px) { .obra-fila.contra-fila.usr-fila { grid-template-columns: 6px 1fr auto; } }
.usr-mandos { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
.usr-mandos select { max-width: 190px; }
/* El permiso de IA es un interruptor, no una casilla de formulario: se dibuja como los demas
   botones de la botonera para que la fila no mezcle dos lenguajes. */
.usr-ia { display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  padding: 4px 7px; border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-dim); }
.usr-ia:has(input:checked) { color: var(--accent); border-color: var(--accent); }
/* Una casilla cuya explicacion ocupa un parrafo no cabe en una linea: se alinea arriba y el
   texto respira, en vez de arrastrar el cuadrito hasta la mitad del bloque. */
.emp-chk-bloque { display: flex; gap: 8px; align-items: flex-start; cursor: pointer; }
.emp-chk-bloque > input { margin-top: 3px; flex: 0 0 auto; }
.emp-chk-bloque > span { display: flex; flex-direction: column; gap: 2px; max-width: 62ch; }

/* El rotulo de cada bloque de papeleria hablaba en negrita suelta; ahora usa la misma voz que los
   titulos de seccion del resto de la aplicacion: versalita, espaciada y en tinta apagada. */
.emp-tit { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim);
  font-weight: 600; margin-bottom: 8px; }
.emp-tit-sum { cursor: pointer; margin-bottom: 0; }

/* Un error de una version anterior no se borra —el registro es historico— pero deja de gritar:
   pierde el rojo y baja de intensidad, para que el que sigue vivo se vea primero. */
.uso-err-nombre { color: var(--red); }
.uso-err-viejo .uso-err-nombre { color: var(--text-dim); }
.uso-err-viejo { opacity: .72; }

/* ===== «LLÉVAME A…» ===== El cuadro no es un buscador de datos, es un mapa: por eso cada
   resultado enseña SU CAMINO COMPLETO debajo del nombre. Leer «Obras › la obra › Ejecución ›
   Avances de obra» tres veces enseña la ruta; a la cuarta ya no se abre esta ventana, que es
   justo el objetivo — una guía que crea dependencia está mal hecha. */
.guia-q { width: 100%; font-size: 16px; padding: 10px 12px; }
.guia-res { margin-top: 10px; }
.guia-tit { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim);
  font-weight: 600; margin: 12px 0 6px; }
.guia-lista { display: flex; flex-direction: column; gap: 1px; background: var(--border);
  border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.guia-item { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; text-align: left;
  background: var(--bg-panel); border: none; padding: 9px 12px; cursor: pointer; font: inherit; color: var(--text); }
.guia-item:hover, .guia-item:focus-visible { background: var(--bg-elev); }
.guia-item-tit { font-weight: 600; font-size: 14.5px; }
.guia-item-ruta { font-size: 12.5px; color: var(--text-dim); }
/* Los pasos de una faena van numerados y en fila: el ORDEN es la mitad de la ayuda. */
.guia-pasos { display: flex; flex-direction: column; gap: 6px; }
.guia-paso { display: flex; align-items: center; gap: 10px; text-align: left; width: 100%;
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 9px 12px; cursor: pointer; font: inherit; color: var(--text); }
.guia-paso:hover { background: var(--bg-elev); }
.guia-paso[disabled] { opacity: .5; cursor: default; }
.guia-paso-n { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%; background: var(--accent);
  color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 700; }
.guia-paso-txt { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.guia-paso-txt em { font-style: normal; font-size: 12.5px; color: var(--text-dim); }

/* ===== MIGAS ===== No son un adorno de «usted está aquí»: son ATAJOS. El tramo que tiene
   hermanos se despliega, y el de la obra cambia de obra SIN salir de la pestaña. Por eso se
   dibujan como botones y no como texto con barras. */
/* LAS MIGAS SON EL ATAJO, no un adorno: cada tramo abre un desplegable que salta a cualquier obra,
   espacio o pestaña sin pasar por el camino largo. Estaban en 13px, gris sobre gris y con una
   flechita al 70% de opacidad — o sea, invisibles. Quien no las descubre navega dando vueltas.
   Ahora se ven: mas cuerpo, la flecha marcada, y el tramo con desplegable se comporta como boton. */
.migas { max-width: 1240px; margin: 0 auto; padding: 12px 20px 0; display: flex; align-items: center;
  gap: 3px; flex-wrap: wrap; font-size: 14px; }
.migas-tramo { position: relative; display: inline-flex; }
.migas-btn { display: inline-flex; align-items: center; gap: 6px; background: none;
  border: 1px solid transparent;
  color: var(--text-dim); font: inherit; padding: 5px 10px; border-radius: var(--radius); cursor: pointer;
  transition: background .12s, border-color .12s, color .12s; }
/* Con desplegable: se anuncia con borde tenue para que se note que hay algo detras. */
.migas-btn:not([disabled]) { border-color: var(--border); background: var(--bg-panel); color: var(--text); }
.migas-btn:hover:not([disabled]) { background: var(--bg-elev); border-color: var(--accent); color: var(--accent); }
.migas-btn[disabled] { cursor: default; }
.migas-aqui { color: var(--text); font-weight: 600; }
.migas-sep { color: var(--text-dim); opacity: .55; font-size: 12px; }
.migas-flecha { font-size: 12px; opacity: 1; color: var(--accent); }
.migas-menu { position: absolute; top: 100%; left: 0; z-index: 40; min-width: 200px; max-height: 60vh;
  overflow-y: auto; background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 4px; }
.migas-op { display: block; width: 100%; text-align: left; background: none; border: none;
  color: var(--text); font: inherit; font-size: 13.5px; padding: 6px 9px; border-radius: var(--radius); cursor: pointer; }
.migas-op:hover { background: var(--bg-elev); }
.migas-op.sel { color: var(--accent); font-weight: 600; }
.migas-menu { font-size: 14px; }
.migas-op { font-size: 14px; padding: 7px 10px; }

/* SALIR DE LA OBRA. Era un texto gris de 12px que se confundia con el subtitulo: la accion mas
   frecuente de la pantalla no puede ser lo menos visible que hay en ella. */
.back-link {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 14px; color: var(--text); background: var(--bg-panel);
  border: 1px solid var(--border); border-radius: var(--radius); padding: 6px 12px;
  transition: background .12s, border-color .12s, color .12s;
}
.back-link:hover { background: var(--bg-elev); border-color: var(--accent); color: var(--accent); }
@media (max-width: 900px) { .migas { padding: 8px 12px 0; } }

/* Señalar: un parpadeo, no un estado. Marca lo que hay que mirar al llegar y se va solo. */
@keyframes senalar-pulso {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  15%, 65% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 55%, transparent); }
}
.senalado { animation: senalar-pulso 2.4s ease-in-out 1; border-radius: var(--radius); }

/* Anclas del riel y su botón en las migas. */
.ancla-btn { position: relative; }
.ancla-n { position: absolute; right: 8px; font-size: 10px; color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 3px; padding: 0 3px; }
.migas-anclar { margin-left: 6px; background: none; border: none; color: var(--text-dim);
  cursor: pointer; padding: 3px 6px; border-radius: var(--radius); font-size: 14px; }
.migas-anclar:hover { background: var(--bg-elev); color: var(--text); }
.migas-anclar.on { color: var(--accent); }

/* El hilo entre documentos: un enlace discreto dentro del renglón, no un botón más en la fila. */
.salto-doc { display: inline-flex; align-items: center; gap: 3px; color: var(--accent);
  background: none; border: none; padding: 0; font: inherit; font-size: 12.5px; cursor: pointer; }
.salto-doc:hover { text-decoration: underline; }

/* El contador de la pastilla: dice CUÁNTO hay dentro sin obligar a entrar. Ámbar, no rojo: es
   trabajo pendiente, no una avería. */
.espacio-cuenta { display: inline-grid; place-items: center; min-width: 17px; height: 17px;
  margin-left: 6px; padding: 0 4px; border-radius: 9px; background: var(--amber); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1; }
.espacio.active .espacio-cuenta { background: color-mix(in srgb, #fff 85%, transparent); color: var(--accent-2); }
/* [hidden] pierde contra display:inline-grid — la misma trampa que ya mordio en los paneles de
   Empresa. Se dice explicitamente o los espacios sin avisos ensenan un «0» que no significa nada. */
.espacio-cuenta[hidden] { display: none; }

/* La lista de arranque: se mira a sí misma y se va sola cuando los cuatro pasos están hechos. */
.primeravez { border: 1px solid var(--border); border-left: 3px solid var(--accent);
  background: var(--bg-panel); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 16px; }
.pv-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.pv-tit { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); font-weight: 600; }
.pv-pasos { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.pv-paso { display: flex; align-items: center; gap: 10px; text-align: left; width: 100%;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 8px 11px; cursor: pointer; font: inherit; color: var(--text); }
.pv-paso:hover:not([disabled]) { border-color: var(--accent); }
.pv-paso.hecho { opacity: .6; cursor: default; }
.pv-n { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%; background: var(--accent);
  color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 700; }
.pv-paso.hecho .pv-n { background: var(--green); }
.pv-txt { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.pv-txt em { font-style: normal; font-size: 12.5px; color: var(--text-dim); }

/* ===== CONFIGURAR LA FACTURA ===== Formulario a la izquierda, la hoja de verdad a la derecha.
   Ver dónde cae cada campo mientras se teclea es lo que evita imprimir diez pruebas. */
/* SIN MINIATURA: la hoja se mira a tamaño real, donde se lee. Quitarla de aquí deja los campos
   a todo el ancho, y con eso la configuración entera cabe de una sola pantalla — que es de lo
   que se trata: configurar es rellenar, no contemplar. */
.fact-cols { display: block; }
.fact-rejilla { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px 14px; }
.fact-rejilla .field { margin: 0; }
.fact-ancho { grid-column: 1 / -1; }
.fact-img { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.fact-img-prev { width: 84px; height: 62px; flex: none; display: grid; place-items: center;
  border: 1px dashed var(--border); border-radius: var(--radius); background: var(--bg-elev); overflow: hidden; }
.fact-img-prev img { max-width: 80px; max-height: 58px; }


/* La hoja: fondo blanco y tinta negra SIEMPRE, en cualquier tema. Es papel, no interfaz —
   configurar una factura contra un fondo oscuro engaña sobre cómo va a salir impresa. */
.fact-hoja { background: #fff; color: #111; border: 1px solid var(--border); padding: 16px;
  font-size: 11px; line-height: 1.35; }
.fact-hoja b { font-weight: 700; }
.fh-top { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
.fh-emp { max-width: 60%; }
.fh-logo { max-height: 46px; max-width: 150px; display: block; margin-bottom: 4px; }
/* EL NOMBRE DEL DOCUMENTO manda en la hoja: es lo primero que se busca al recibir un papel y lo
   que lo identifica de un vistazo en un archivador. Siempre en mayúscula (lo fuerza el código, no
   solo el CSS: `text-transform` no cambia lo que se copia) y siempre el elemento más grande —2.4
   veces la letra base—, por encima del nombre de la empresa y del total. */
.fh-titulo { font-size: 2.4em; font-weight: 800; letter-spacing: .06em; text-align: right;
  line-height: 1.05; text-transform: uppercase; }
.fh-n { text-align: right; font-size: 12px; }
.fh-cliente { display: flex; justify-content: space-between; gap: 12px; margin-top: 14px; }
.fh-cliente .sub { color: #555; }
.fh-fecha { text-align: right; }
.fh-tabla { width: 100%; border-collapse: collapse; margin-top: 12px; }
/* La cabecera de la tabla en INTENSO: en el original del propietario es una banda oscura con
   letra clara, y en gris claro se perdía al fotocopiar — que es lo que le pasa a una factura. */
.fh-tabla th { background: #3a3a3a; color: #fff; border: 1px solid #3a3a3a; padding: 5px 6px;
  font-size: 10px; text-align: left; font-weight: 700; letter-spacing: .02em; }
.fh-tabla th.num { text-align: right; }
.fh-tabla td { border: 1px solid #ddd; padding: 4px 5px; vertical-align: top; }
.fh-tabla .num { text-align: right; }
.fh-totales { margin-top: 8px; margin-left: auto; width: 240px; }
.fh-totales > div { display: flex; justify-content: space-between; padding: 3px 0; }
.fh-total { border-top: 1px solid #333; font-size: 1.15em; font-weight: 700; }
.fh-pie { margin-top: 14px; border-top: 1px solid #ddd; padding-top: 8px; }
.fh-legal { font-size: 10px; color: #333; }
.fh-abajo { display: flex; gap: 12px; align-items: flex-start; margin-top: 10px; }
.fh-qr { width: 62px; height: 62px; flex: none; }
.fh-qr-vacio { border: 1px dashed #bbb; display: grid; place-items: center; color: #999; font-size: 10px; }
.fh-cuentas { font-size: 10px; color: #333; }
.fh-muestra { margin-top: 10px; font-size: 9.5px; color: #999; text-align: center; }
.fx-anulada { opacity: .55; text-decoration: line-through; }
.fx-anulada .badge { text-decoration: none; }
.fh-anulada { margin-top: 8px; border: 2px solid #b00; color: #b00; font-weight: 800;
  text-align: center; padding: 3px; letter-spacing: .1em; }

/* ===== DISEÑAR EL CHEQUE ===== El lienzo ES la hoja a escala: el % de posición es el mm dividido
   por el lado, así que arrastrar en pantalla equivale a mover milímetros en el papel. */
/* La columna de la derecha tiene ancho FIJO: con `1fr` sus casillas numéricas imponían su
   ancho mínimo y estrujaban el lienzo a un tercio de lo que debía medir. El lienzo se queda con
   todo lo demás — es lo que hay que ver grande. */
.chq-cols { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 14px; align-items: start; }
@media (max-width: 900px) { .chq-cols { grid-template-columns: 1fr; } }
/* El dato es minúsculo a escala real (10 pt sobre 198 mm): el área de agarre se agranda sin
   agrandar la letra, para poder arrastrarlo sin mentir sobre cómo va a salir impreso. */
.chq-dato::after { content: ""; position: absolute; inset: -6px -4px; }
.chq-lienzo { position: relative; width: 100%; background: #fff center/100% 100% no-repeat;
  border: 1px solid var(--border); overflow: hidden; }
.chq-dato { position: absolute; white-space: nowrap; color: #111; font-family: "Courier New", monospace;
  background: rgba(255,235,150,.5); cursor: grab; touch-action: none; padding: 0 1px; line-height: 1; }
.chq-dato:active { cursor: grabbing; }
.chq-off { opacity: .28; }
.chq-campos { display: flex; flex-direction: column; gap: 5px; }
.chq-fila { display: grid; grid-template-columns: 1fr 62px 62px; gap: 5px; align-items: center; font-size: 13px; }
.chq-fila input { padding: 3px 5px; font-size: 12.5px; }
.chq-hoja { grid-template-columns: 1fr 62px 62px 62px; border-top: 1px solid var(--border); padding-top: 6px; margin-top: 4px; }

/* ===== LA CUENTA ===== Lo primero que se pregunta quien abre esto es cuánto paga: va arriba y
   en grande, con la IA aparte porque se cobra distinto (consumo, no licencia). */
.plan-cuenta { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1px;
  background: var(--border); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.plan-cuenta > div { background: var(--bg-panel); padding: 11px 14px; display: flex; flex-direction: column; gap: 2px; }
.plan-monto { font-size: 24px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.1; }
.plan-rejilla { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; }
.plan-caja { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; background: var(--bg-panel); }
.plan-caja.on { border-color: var(--accent); border-left-width: 3px; }
.plan-caja-tit { font-weight: 700; font-size: 15px; }
.plan-precio { font-family: "Oswald", sans-serif; font-size: 1.9rem; line-height: 1.1; margin: 2px 0; }
.plan-precio em { font-style: normal; font-size: 12px; color: var(--text-dim); }
.plan-inc { display: flex; flex-wrap: wrap; gap: 3px 10px; margin-top: 6px; font-size: 12px; color: var(--text-dim); }
.plan-modulo-der { display: flex; align-items: center; gap: 12px; }
.plan-modulo-precio { display: flex; flex-direction: column; text-align: right; font-size: 13px;
  font-weight: 600; white-space: nowrap; }
.plan-modulo-precio em { font-style: normal; font-size: 11px; font-weight: 400; color: var(--green); }
/* EL CHEQUE DIBUJADO. Antes era un rectángulo gris con rayas; ahora se parece a un cheque de
   verdad —el papel verdoso de seguridad con su trama, el borde y la línea MICR— porque calibrar y
   llenar sobre algo que no se reconoce como cheque es trabajar a ciegas. Sigue siendo una GUÍA:
   en cuanto se sube la foto del talonario, esta desaparece y manda la foto. */
.chq-dibujado .chq-ranura, .chq-dibujado:not(.chq-hoja) {
  background-color: #eef4ec;
  /* Trama de seguridad: dos juegos de líneas finas cruzadas, como el fondo guilloche del papel. */
  background-image:
    repeating-linear-gradient(58deg, rgba(120,160,120,.10) 0 1px, transparent 1px 7px),
    repeating-linear-gradient(-58deg, rgba(120,160,120,.09) 0 1px, transparent 1px 9px),
    linear-gradient(180deg, rgba(255,255,255,.55), rgba(255,255,255,0) 40%);
  border: 1px solid #c4d2c2;
  box-shadow: inset 0 0 22px rgba(90,130,90,.10);
}
/* La banda MICR: los caracteres de máquina que lleva todo cheque al pie. Decorativa a propósito. */
.chq-micr { position: absolute; font-family: "Courier New", monospace; font-size: 0.62em;
  letter-spacing: .12em; color: #2b2b2b; white-space: nowrap; }
.chq-raya { position: absolute; border-bottom: 1px solid #b9c3b9; height: 0; }
.chq-rotulo { position: absolute; font-style: normal; text-decoration: none; color: #8a9490;
  font-size: 0.45em; white-space: nowrap; }
.chq-logo { position: absolute; opacity: .9; }

/* ===== LLENAR EL CHEQUE ===== Las casillas van ENCIMA del cheque, en el tamaño que se van a
   imprimir. Sin marco ni fondo: lo que se ve es la tinta, no el formulario. */
.chq-llenar { cursor: text; }
.chq-campo { position: absolute; border: none; background: transparent; padding: 0;
  font-family: "Courier New", monospace; color: #111; line-height: 1.05; outline: none;
  border-bottom: 1px dashed transparent; }
.chq-campo { text-transform: uppercase; }
/* La referencia es la excepción: es una frase de uso interno y conserva sus minúsculas. */
.chq-campo[data-lc="referencia"] { text-transform: none; }
.chq-campo::placeholder { color: #b9c3b9; font-style: italic; text-transform: none; }
.chq-campo:hover { border-bottom-color: #c9d3c9; }
.chq-campo:focus { border-bottom-color: var(--accent); background: rgba(255,235,150,.35); }
/* Lo que ya trae impreso el banco: se ve, no se escribe. */
.chq-campo-fijo { color: #555; pointer-events: none; white-space: nowrap; }
/* La cantidad en letras se escribe sola: se marca para que nadie la busque para teclearla. */
.chq-campo-auto { color: #111; cursor: default; }
.chq-campo-auto:focus { background: none; border-bottom-color: transparent; }
/* La marca tipográfica del banco: su nombre en su color, cuando no se ha subido el logotipo. */
.chq-marca { position: absolute; font-weight: 800; font-size: 1.05em; letter-spacing: -.01em;
  white-space: nowrap; font-family: "IBM Plex Sans", Arial, sans-serif; }

/* Recortar: la imagen a la vista y un rectángulo que se arrastra encima. */
.rec-caja { position: relative; display: inline-block; max-width: 100%; cursor: crosshair;
  border: 1px solid var(--border); background: #fff; touch-action: none; }
.rec-caja img { display: block; max-width: 100%; max-height: 60vh; user-select: none; pointer-events: none; }
.rec-sel { position: absolute; border: 2px dashed var(--accent); background: rgba(255,235,150,.25); pointer-events: none; }

/* ===== LA HOJA DE LA CHEQUERA ===== Tres cheques por hoja, como el talonario de escritorio. El
   que se está llenando va nítido; los otros dos, apagados y con su número, para saber cuáles
   siguen y poder saltar a ellos. La perforación entre uno y otro es la línea punteada. */
/* La hoja va a ANCHO COMPLETO, no encogida para que quepan los tres: aquí se escribe, y un cheque
   del tamaño de un sello no se puede llenar. La hoja se desplaza dentro de su marco y al abrir
   salta sola al cheque en turno — se ve el pliego entero cuando hace falta, sin pagarlo con
   legibilidad el resto del tiempo. */
.chq-hoja { background: var(--bg-panel); box-shadow: var(--shadow); border: 1px solid var(--border);
  width: 100%; }
.chq-marco { max-height: 52vh; overflow-y: auto; overscroll-behavior: contain;
  border-radius: var(--radius); }
.chq-ranura { position: absolute; left: 0; right: 0; overflow: hidden; cursor: pointer;
  border-bottom: 1px dashed #c4d2c2; transition: opacity .15s ease; }
.chq-ranura:last-of-type { border-bottom: 0; }
/* Los que no se están llenando: se ven, no distraen. */
.chq-ranura:not(.chq-ranura-on) { opacity: .38; filter: saturate(.7); }
.chq-ranura:not(.chq-ranura-on):hover { opacity: .62; }
.chq-ranura-on { cursor: default; box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
.chq-ranura .chq-fondo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; }
/* El número va donde lo imprime el banco, con el consecutivo real de cada cheque de la hoja. */
.chq-num-real { color: #111; font-weight: 700; letter-spacing: .06em; }
.chq-ranura:not(.chq-ranura-on) .chq-num-real { color: #555; }
/* La capa de las casillas va encima del cheque activo, sin capturar el clic del resto de la hoja. */
.chq-capa { position: absolute; left: 0; right: 0; pointer-events: none; }
.chq-capa .chq-campo { pointer-events: auto; }
/* Un cheque girado no se vuelve a llenar: se ve, con su sello y a quién fue. */
.chq-ranura-usada { cursor: not-allowed; }
.chq-ranura-usada .chq-fondo, .chq-ranura-usada .chq-rotulo, .chq-ranura-usada .chq-raya { opacity: .5; }
.chq-sello { position: absolute; left: 50%; top: 45%; transform: translate(-50%,-50%) rotate(-12deg);
  border: 3px double var(--red); color: var(--red); font-weight: 800; letter-spacing: .18em;
  padding: 2px 14px; font-size: 1.4em; opacity: .75; border-radius: 3px; }
.chq-ranura-quien { position: absolute; left: 4%; bottom: 6%; font-size: .95em; color: var(--text-dim); }
/* Solo el número del cheque en turno se escribe; se marca con el mismo subrayado que los demás. */
.chq-num-turno { text-align: left; }
.chq-num-turno:hover { border-bottom-color: #c9d3c9; }
.chq-num-turno:focus { border-bottom-color: var(--accent); background: rgba(255,235,150,.35); }

/* La barra del cheque: la lectura a la izquierda, los ajustes de impresión a la derecha en
   iconos. Las dos acciones del momento viven abajo, en el pie del diálogo, y no compiten con
   estos — es la norma de la botonera compacta. */
.lc-barra { display: flex; align-items: center; gap: 12px; margin-top: 8px; flex-wrap: wrap; }
.lc-letras { flex: 1; min-width: 12rem; }
.lc-ajustes { gap: 6px; }
.lc-ajustes label { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; color: var(--text-dim); }
.lc-ajustes select { width: auto; padding: 3px 6px; font-size: 12.5px; }
/* La factura a tamaño real dentro del diálogo: se ve como el papel, con su ancho de carta. */
.fact-grande .fact-hoja { max-width: 216mm; margin: 0 auto; font-size: 13px; padding: 22px; }
/* Los dos filtros del tablero, en la misma barra que Actualizar. */
.page-head .acc-bar select { width: auto; max-width: 14rem; padding: 5px 8px; font-size: 13.5px; }

/* ===== PLANTILLAS DE LA FACTURA ===== Cambia el reparto del encabezado, no los datos. */
.fh-centrada { flex-direction: column; align-items: center; text-align: center; }
.fh-centrada .fh-emp { max-width: 100%; }
.fh-centrada .fh-titulo, .fh-centrada .fh-n { text-align: center; }
.fh-compacta { align-items: center; gap: 16px; padding-bottom: 6px; border-bottom: 1px solid #ddd; }
.fh-compacta .fh-emp { font-size: .92em; }
/* Ni siquiera en la compacta baja de ser el mayor: se reduce la hoja, no su jerarquía. */
.fh-compacta .fh-titulo { font-size: 1.9em; }
.fh-logo-centro { display: block; margin: 0 auto 6px; }
.fh-logo-derecha { display: block; margin-left: auto; margin-bottom: 4px; }
.fh-logo-pie { display: block; margin: 10px auto 0; opacity: .85; }
.fh-qr-cab { width: 46px; height: 46px; margin-left: auto; display: block; }
.fh-abajo-der { flex-direction: row-reverse; }

/* La papelería a tamaño real: una hoja de verdad, con sus milímetros y su margen. */
.pap-real { overflow: auto; max-height: 64vh; background: var(--bg-elev); padding: 14px; }
.pap-hoja { background: #fff; color: #111; margin: 0 auto; box-shadow: 0 2px 14px rgba(0,0,0,.25);
  box-sizing: border-box; font-size: 11px;
  /* La hoja es una COLUMNA: el encabezado arriba, el contenido estirándose y el pie apoyado en el
     borde de abajo. Sin esto, el pie se pegaba al encabezado en cuanto el contenido era corto. */
  display: flex; flex-direction: column; }
/* Se apunta a `.ep-scope` por su nombre y no al «primer hijo»: el primer hijo es el <style> que
   viaja con la muestra, así que el selector posicional no llegaba nunca a la hoja. */
.pap-hoja .ep-scope { display: flex; flex-direction: column; flex: 1 1 auto; }
/* El contenido empuja al pie hacia abajo desde dentro de la hoja. */
.pap-hoja .ep-cuerpo { display: flex; flex-direction: column; }
.pap-cuerpo { flex: 1 1 auto; }
.pap-cuerpo { margin-top: 14px; }
.pap-cuerpo table { width: 100%; border-collapse: collapse; margin-top: 10px; }
.pap-cuerpo th { background: #eee; border: 1px solid #ccc; padding: 4px 6px; text-align: left; font-size: 10px; }
.pap-cuerpo td { border: 1px solid #ddd; padding: 4px 6px; }
.pap-cuerpo .num { text-align: right; }

/* ===== FACTURACIÓN, COMPACTA ===== La pantalla se toca una vez al año: lo que se mira a diario
   es el aviso del CAI. Los campos van apretados y en rejilla, y lo que se ajusta una sola vez
   —leyendas, cuentas, plantilla— vive plegado. Ocupar pantalla no es informar. */
.fact-intro { margin: 0 0 10px; }
.fact-grupo-tit { margin: 12px 0 6px; }
.fact-grupo { margin: 8px 0; border-top: 1px solid var(--border); padding-top: 8px; }
.fact-grupo > summary { list-style: none; }
.fact-grupo > summary::-webkit-details-marker { display: none; }
.fact-grupo > summary::before { content: "▸ "; color: var(--text-dim); }
.fact-grupo[open] > summary::before { content: "▾ "; }
.fact-form .field { margin: 0; }
.fact-form .field label { font-size: 12px; margin-bottom: 2px; }
.fact-form .field input, .fact-form .field select, .fact-form .field textarea { padding: 5px 8px; font-size: 13.5px; }
.fact-form .field textarea { min-height: 44px; }
.fact-form .hint-sm { margin-top: 2px; line-height: 1.35; }

/* ===== PAPELERÍA, COMPACTA ===== Mismo criterio que Facturación: se configura una vez, así que
   los campos van apretados y la vista previa vive plegada — para revisarla de verdad está el
   botón de tamaño real, que es donde se lee. */
[data-emp-panel="papeleria"] .card { padding: 10px 12px; }
[data-emp-panel="papeleria"] .field { margin: 0 0 6px; }
[data-emp-panel="papeleria"] .field label { font-size: 12px; margin-bottom: 2px; }
[data-emp-panel="papeleria"] .field-row { gap: 8px; margin-bottom: 6px; }
[data-emp-panel="papeleria"] input, [data-emp-panel="papeleria"] select,
[data-emp-panel="papeleria"] textarea { padding: 4px 7px; font-size: 13px; }
[data-emp-panel="papeleria"] .hint { margin: 3px 0; line-height: 1.35; }
.pap-previa > summary { list-style: none; cursor: pointer; }
.pap-previa > summary::-webkit-details-marker { display: none; }
.pap-previa > summary::before { content: "▸ "; color: var(--text-dim); }
.pap-previa[open] > summary::before { content: "▾ "; }
.pap-previa > summary .sub { font-weight: 400; text-transform: none; letter-spacing: 0; margin-left: 8px; }
.fh-qr-caja { display: inline-flex; flex-direction: column; align-items: center; flex: none; }
.fh-qr-nota { font-style: normal; font-size: 8px; color: #999; margin-top: 2px; }

/* ===========================================================================
   DIRECTORIO, MOVIMIENTOS Y MENÚ CONTEXTUAL
   Todo esto usa los TOKENS DEL TEMA (--bg-panel, --border, --accent, --text…). Un color escrito a
   mano aquí se ve bien en el tema en que se escribió y se rompe en los otros cinco — y en modo
   oscuro deja texto claro sobre fondo claro, que es ilegible sin avisar.
   =========================================================================== */

/* ---------- Campo de directorio: alta sin salir del diálogo ---------- */
.dir-fila { display: flex; gap: 6px; align-items: center; }
.dir-fila select { flex: 1; min-width: 0; }
.dir-req { color: var(--accent); font-weight: 700; }
.dir-alta {
  margin-top: 8px; padding: 10px 12px 12px;
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius); background: var(--bg-elev);
}
.dir-alta-cab { font-weight: 600; font-size: 13px; margin-bottom: 8px; color: var(--accent); }
.dir-alta-pie { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 6px; flex-wrap: wrap; }
.dir-alta-pie .sub { font-size: 12px; }
.dir-roles { display: flex; gap: 8px; flex-wrap: wrap; }
.dir-chk { display: flex; gap: 8px; align-items: flex-start; flex: 1 1 170px; cursor: pointer;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius); color: var(--text); }
.dir-chk:has(input:checked) { border-color: var(--accent); background: var(--zebra); }
.dir-chk .sub { font-size: 11.5px; line-height: 1.25; }
.dir-rol { display: inline-block; font-size: 11px; letter-spacing: .02em; padding: 1px 7px;
  border-radius: 10px; border: 1px solid var(--border); color: var(--text-dim); text-transform: lowercase; }
.dir-rol-cliente   { border-color: var(--c3); color: var(--c3); }
.dir-rol-proveedor { border-color: var(--accent); color: var(--accent); }
.dir-rol-empleado  { border-color: var(--c1); color: var(--c1); }
.dir-off > td { opacity: .55; }

/* ---------- Movimientos: buscar, filtrar, marcar ---------- */
.mov-barra { display: flex; gap: 10px; align-items: center; margin-top: 14px; flex-wrap: wrap; }
.mov-buscador { flex: 1; min-width: 220px; display: flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); border-radius: var(--radius); padding: 4px 8px; background: var(--bg-panel); }
.mov-buscador input { flex: 1; border: 0; background: transparent; outline: none; font-size: 13.5px; min-width: 0; color: var(--text); }
.mov-buscador .ti { color: var(--text-dim); }
.mov-filtros { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 8px 0 4px; }
.mov-filtros select, .mov-filtros input[type=date] { font-size: 12.5px; padding: 3px 6px; }
.mov-resumen { margin-left: auto; font-size: 12.5px; color: var(--text-dim); }
.mov-lapso { font-weight: 600; }
.mov-lapso-eco { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
/* La cabecera se quedó con lo mínimo: buscar, ver qué está filtrado y el resumen. Todo lo demás
   —los cinco desplegables, las tres vistas y la barra de acciones en lote— vive en el clic derecho.
   Las etiquetas NO son un duplicado del menú: no ofrecen filtrar, dicen qué filtro está puesto, que
   es justo lo que un filtro escondido se lleva por delante. */
.mov-pista { font-size: 11.5px; color: var(--text-dim); display: flex; align-items: center; gap: 5px; white-space: nowrap; }
@media (max-width: 1200px) { .mov-pista { display: none; } }
.mov-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; padding: 2px 8px;
  border-radius: 11px; border: 1px solid var(--accent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent); cursor: pointer; }
.mov-chip:hover { background: var(--accent); color: var(--bg); }
.mov-chip .ti { font-size: 12px; }
.mov-chip-vista { border-color: var(--c1); color: var(--c1); background: color-mix(in srgb, var(--c1) 12%, transparent); }
.mov-chip-vista:hover { background: var(--c1); color: var(--bg); }
.mov-chip-sel { border-color: var(--c3); color: var(--c3); background: color-mix(in srgb, var(--c3) 12%, transparent); }
.mov-chip-sel:hover { background: var(--c3); color: var(--bg); }

/* Submenú y marcas del menú contextual */
.ctx-sub { z-index: 9001; }
.ctx-flecha { margin-left: auto; font-size: 13px; }
.ctx-it em { font-style: normal; font-size: 11px; color: var(--text-dim); margin-left: auto; }
.ctx-it:hover:not(:disabled) em { color: var(--bg); opacity: .85; }
.ctx-it.marcado { font-weight: 600; }
.ctx-it .ti-blank { visibility: hidden; }
.ctx-sep { position: relative; }
.ctx-sep span { position: absolute; left: 4px; top: -7px; font-size: 10px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--text-dim); background: var(--bg-elev); padding: 0 4px; }

/* El apagado se lee de un vistazo como «esto no cuenta»: además de desvanecido, el monto tachado.
   Un simple gris se lee como «viejo», que es otra cosa. */
.mov-apagado > td { opacity: .45; }
.mov-apagado .mov-monto { text-decoration: line-through; }
.mov-hijo > td { background: var(--zebra); }
.mov-rama { color: var(--text-dim); margin-right: 2px; }
.mov-chips { display: flex; gap: 5px; align-items: center; margin-top: 2px; flex-wrap: wrap; }
.mov-cat { font-size: 10.5px; padding: 1px 7px; border-radius: 10px; border: 1px solid currentColor; }
.mov-bandera { font-size: 11px; }
.mov-acc { white-space: nowrap; }
.mov-tabla table { table-layout: fixed; width: 100%; }
.mov-tabla td, .mov-tabla th { vertical-align: top; padding-left: 8px; padding-right: 8px; }
.mov-tabla tbody tr { cursor: pointer; }
/* Las cabeceras en versalitas y sin partirse: son etiquetas, no contenido. */
.mov-tabla thead th { font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* El texto largo ENVUELVE en su columna en vez de estirarla. Un concepto de banco viene con la
   nota entera pegada y sin esto se llevaba la tabla fuera de la pantalla. */
.mov-tabla td:nth-child(2), .mov-tabla td:nth-child(3), .mov-tabla td:nth-child(4) {
  overflow-wrap: anywhere; hyphens: auto;
}
/* Las cifras nunca se parten ni se desalinean: ancho de dígito fijo y una sola línea. */
.mov-tabla td.num, .mov-tabla th.num { text-align: right; white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.mov-tabla td:last-child, .mov-tabla th:last-child { text-align: center; padding-left: 2px; padding-right: 2px; }
.mov-tabla td:first-child, .mov-tabla th:first-child { padding-right: 2px; }
/* El documento (referencia, n.º de cheque) en monoespaciada: son códigos que se cotejan dígito a
   dígito contra el estado de cuenta, y en proporcional el 1 y el 7 se confunden. */
.mov-tabla td:nth-child(4) { font-family: var(--font-mono, ui-monospace, monospace); font-size: 11.5px; }

/* Los colores de categoría y bandera salen de la serie categórica del tema: están medidos para
   contraste y para daltonismo, cosa que un color elegido a ojo no garantiza. */
.mov-col-arena  { color: var(--amber); }
.mov-col-oxido  { color: var(--accent); }
.mov-col-verde  { color: var(--c3); }
.mov-col-azul   { color: var(--c1); }
.mov-col-morado { color: var(--c4); }
.mov-col-gris   { color: var(--text-dim); }
.mov-b-revisar   { color: var(--accent); }
.mov-b-pendiente { color: var(--amber); }
.mov-b-ojo       { color: var(--red); }
.mov-b-listo     { color: var(--green); }
.mov-fondo-arena  > td { background: color-mix(in srgb, var(--amber) 14%, transparent); }
.mov-fondo-oxido  > td { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.mov-fondo-verde  > td { background: color-mix(in srgb, var(--c3) 14%, transparent); }
.mov-fondo-azul   > td { background: color-mix(in srgb, var(--c1) 14%, transparent); }
.mov-fondo-morado > td { background: color-mix(in srgb, var(--c4) 14%, transparent); }
.mov-fondo-gris   > td { background: var(--zebra-strong); }
.mov-colores { display: flex; gap: 6px; }
.mov-color { width: 22px; height: 22px; border-radius: var(--radius); border: 1px solid var(--border); cursor: pointer; }
.mov-color.on { outline: 2px solid var(--accent); outline-offset: 1px; }
.mov-col-ninguno { background: repeating-linear-gradient(45deg, transparent, transparent 4px, var(--border) 4px, var(--border) 5px); }
.mov-color.mov-col-arena  { background: var(--amber); }
.mov-color.mov-col-oxido  { background: var(--accent); }
.mov-color.mov-col-verde  { background: var(--c3); }
.mov-color.mov-col-azul   { background: var(--c1); }
.mov-color.mov-col-morado { background: var(--c4); }
.mov-color.mov-col-gris   { background: var(--text-dim); }
.mov-barra-cat { height: 8px; border-radius: 4px; background: var(--zebra-strong); overflow: hidden; }
.mov-barra-cat > span { display: block; height: 100%; background: var(--accent); opacity: .65; }

/* ---------- Agrupador por día ---------- */
.mov-dia > td { background: var(--bg-elev); border-top: 1px solid var(--border);
  padding-top: 7px; padding-bottom: 7px; font-size: 12.5px; cursor: pointer; color: var(--text); }
.mov-dia:hover > td { background: color-mix(in srgb, var(--accent) 12%, var(--bg-elev)); }
.mov-dia .sub { font-size: 11px; }
.mov-dia-tog { background: none; border: 0; cursor: pointer; padding: 0 5px 0 0; color: var(--text-dim); }
.mov-dia.plegado .mov-dia-tog i { transform: rotate(-90deg); display: inline-block; }
.mov-dia-neto { font-variant-numeric: tabular-nums; font-weight: 600; }
.mov-dia-neto.neg { color: var(--red); }
.mov-dia-neto.pos { color: var(--green); }
.mov-dia-saldo { font-variant-numeric: tabular-nums; color: var(--text-dim); }

/* ---------- Reparto ---------- */
.fr-parte { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.fr-parte input, .fr-parte select { min-width: 0; }
.fr-parte .fr-c { flex: 2; }
.fr-parte .fr-k { flex: 1; }
.fr-parte .fr-m { width: 110px; text-align: right; }
.fr-cuadre { margin-top: 8px; font-size: 13px; }
.fr-ok  { color: var(--green); font-weight: 600; }
.fr-mal { color: var(--accent); font-weight: 600; }

/* ---------- Tres paneles: cuentas · lista · detalle ---------- */
.mov-marco { display: grid; grid-template-columns: 230px minmax(0, 1fr) 320px; gap: 14px; align-items: start; }
@media (max-width: 1400px) { .mov-marco { grid-template-columns: 210px minmax(0, 1fr); } .mov-detalle { grid-column: 1 / -1; } }
@media (max-width: 900px)  { .mov-marco { grid-template-columns: 1fr; } }
.mov-centro { min-width: 0; }
.mov-cuentas { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden;
  position: sticky; top: 8px; background: var(--bg-panel); }
.mov-cuentas-cab { padding: 8px 10px; font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim); border-bottom: 1px solid var(--border); }
/* EL NOMBRE DE LA CUENTA, ENTERO. Con el saldo a la derecha en un panel de 230 px, «Atlántida
   Principal» se leia «Atlanti…» y «Fondo Revolvente» «Fondo Revo…»: justo lo que hay que leer para
   saber en que cuenta se esta. El saldo baja a su propia linea y el nombre se queda con todo el
   ancho. */
.mov-cta { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 8px;
  align-items: center; padding: 8px 10px; cursor: pointer;
  border-bottom: 1px solid var(--border); color: var(--text); }
.mov-cta .mov-cta-s { grid-column: 2; justify-self: start; }
.mov-cta:hover { background: var(--zebra); }
.mov-cta.on { background: color-mix(in srgb, var(--accent) 14%, transparent); box-shadow: inset 3px 0 0 var(--accent); }
.mov-cta.fuera .mov-cta-txt, .mov-cta.fuera .mov-cta-s { opacity: .5; }
.mov-cta-chk { display: flex; }
.mov-cta-txt { flex: 1; min-width: 0; }
.mov-cta-n { display: flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 600; min-width: 0; }
.mov-cta-nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.mov-cta-b { font-size: 11px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mov-cta-s { font-size: 12.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.mov-cta-s.neg { color: var(--red); }
.mov-cta-total { display: flex; justify-content: space-between; align-items: center; gap: 8px;
  padding: 10px; background: var(--bg-elev); font-size: 13px; color: var(--text); }
.mov-cta-total .sub { font-size: 11px; display: block; }
.mov-aviso-moneda { padding: 8px 10px; font-size: 11.5px; color: var(--amber); border-top: 1px solid var(--border); }

.mov-detalle { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px;
  position: sticky; top: 8px; background: var(--bg-panel); }
.mov-det-vacio { text-align: center; color: var(--text-dim); padding: 28px 10px; font-size: 12.5px; }
.mov-det-vacio .ti { font-size: 28px; opacity: .4; display: block; margin-bottom: 8px; }
.mov-det-cab { display: flex; align-items: center; gap: 8px; margin-bottom: 10px;
  padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.mov-det-cab strong { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mov-det-cab > .ti { color: var(--text-dim); }
.mov-det-cab .acc-btn { margin-left: auto; }
.mov-det-tipo { font-size: 10.5px; padding: 2px 7px; border-radius: 10px; border: 1px solid currentColor; }
.mov-det-egreso  { color: var(--red); }
.mov-det-ingreso { color: var(--green); }
.mov-det-campos.off { opacity: .5; pointer-events: none; }
.mov-det-campos .field { margin-bottom: 7px; }
.mov-det-campos label { font-size: 11px; }
.mov-det-campos input, .mov-det-campos select { font-size: 12.5px; padding: 4px 6px; }
.mov-det-partes { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); }
.mov-det-sub { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); margin-bottom: 5px; }
.mov-det-parte { display: flex; justify-content: space-between; gap: 8px; font-size: 12.5px; padding: 2px 0; }
.mov-det-pie { display: flex; justify-content: space-between; gap: 8px; margin-top: 10px;
  padding-top: 8px; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--text-dim); }
.mov-det-off { display: flex; gap: 8px; align-items: flex-start; margin-top: 8px; padding: 7px 9px;
  border-radius: var(--radius); border: 1px solid var(--border); background: var(--bg-elev); font-size: 11.5px; }
.mov-det-off .ti { color: var(--text-dim); }

/* ---------- La fila elegida ----------
   Entera en el acento del tema y sin las líneas de celda que la cortan: el renglón se lee de un
   tirón, no como seis casillas.
   PERO TEÑIDA, NO SÓLIDA. Con el acento a fondo lleno el texto quedaba en 3.4-4.3:1 en los seis
   temas —por debajo del mínimo legible— porque el acento de Faena es un tono medio: ni el blanco
   ni el negro contrastan bien encima. Con el acento al 22 % sobre el panel, el texto conserva su
   color de siempre y el contraste queda garantizado por construcción, no por suerte. La barra
   sólida de la izquierda es la que hace inconfundible cuál está elegida. */
.mov-tabla tbody tr.mov-elegida > td {
  background: color-mix(in srgb, var(--accent) 22%, var(--bg-panel)) !important;
  border-color: transparent !important;
  box-shadow: none !important;
}
.mov-tabla tbody tr.mov-elegida > td:first-child {
  box-shadow: inset 3px 0 0 var(--accent) !important;
}
.mov-elegida .sub, .mov-elegida .mov-cta-b { color: var(--text) !important; opacity: .8; }
.mov-elegida input[type=checkbox] { accent-color: var(--accent); }
.mov-elegida.mov-apagado > td { opacity: .75; }
.mov-tabla tbody tr.mov-abierto:not(.mov-elegida) > td {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  box-shadow: inset 0 1px 0 var(--accent), inset 0 -1px 0 var(--accent);
}

/* ---------- Menú del clic derecho ----------
   Se dibuja sobre el panel elevado del tema y FIJA su color de texto: hereda del elemento donde se
   hizo clic, y sobre una fila seleccionada eso era texto casi blanco sobre menú casi blanco. */
.ctx-menu {
  position: fixed; z-index: 9000; min-width: 240px; padding: 5px;
  background: var(--bg-elev); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); font-size: 13.5px; line-height: 1.35;
}
.ctx-it {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 10px;
  background: none; border: 0; border-radius: var(--radius); cursor: pointer;
  text-align: left; color: var(--text); font: inherit;
}
.ctx-it:hover:not(:disabled), .ctx-it:focus-visible { background: var(--accent); color: var(--bg); outline: none; }
.ctx-it:hover:not(:disabled) .ti, .ctx-it:hover:not(:disabled) kbd { color: var(--bg); opacity: 1; }
.ctx-it:disabled { color: var(--text-dim); opacity: .55; cursor: default; }
.ctx-it .ti { color: var(--text-dim); width: 1.15em; font-size: 15px; }
.ctx-it span { flex: 1; }
.ctx-it kbd { font-size: 10.5px; color: var(--text-dim); }
.ctx-it.peligro { color: var(--red); }
.ctx-it.peligro .ti { color: var(--red); }
.ctx-it.peligro:hover:not(:disabled) { background: var(--red); color: var(--bg); }
.ctx-it.peligro:hover:not(:disabled) .ti { color: var(--bg); }
.ctx-sep { height: 1px; margin: 4px 6px; background: var(--border); }

/* El signo pegado al importe: rojo si sale, verde si entra. El color NO va solo — el signo y el
   pie de texto dicen lo mismo, porque uno de cada doce hombres no distingue el rojo del verde. */
/* Doble alto: 64 px contra los ~32 de un campo normal. La cifra se lee sin buscarla. */
.md-monto { display: flex; align-items: stretch; height: 64px;
  border: 2px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.md-monto input { flex: 1; min-width: 0; height: 100%; border: 0 !important; border-radius: 0 !important;
  text-align: right; font-variant-numeric: tabular-nums; font-size: 26px !important;
  font-weight: 700; padding: 0 10px !important; letter-spacing: -.01em; }
.md-signo { width: 46px; border: 0; cursor: pointer; font-size: 26px; font-weight: 700;
  line-height: 1; color: var(--bg); flex: 0 0 46px; }
/* El símbolo va junto al importe, no dentro del campo: así no se puede borrar al teclear. */
.md-cur { display: flex; align-items: center; padding: 0 0 0 10px; font-size: 15px;
  font-weight: 600; color: var(--text-dim); }
.md-signo:disabled { cursor: default; opacity: .55; }
.md-monto.sale  { border-color: var(--red); }
.md-monto.sale  .md-signo { background: var(--red); }
.md-monto.sale  input { color: var(--red); }
.md-monto.entra { border-color: var(--green); }
.md-monto.entra .md-signo { background: var(--green); }
.md-monto.entra input { color: var(--green); }
.md-signo-pie { font-size: 11px; color: var(--text-dim); margin-top: 3px; }
.md-campo-monto { margin-bottom: 10px !important; }

/* ---------- Contador de pendientes por cuenta ---------- */
.mov-cta-der { text-align: right; }
.mov-cta-pend { font-size: 10.5px; color: var(--amber); white-space: nowrap; }
.mov-cta-ok { font-size: 10.5px; color: var(--green); white-space: nowrap; }
.mov-cta-ok .ti { font-size: 11px; }

/* ---------- Distintivo de conciliado ----------
   La marca va en la fila, no solo en una casilla: al recorrer cincuenta renglones lo que se busca
   es «cuáles faltan», y para eso el ojo necesita un borde que se siga de arriba abajo. */
.mov-visto { display: inline-flex; width: 18px; height: 18px; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--green); color: var(--bg); font-size: 12px; }
.mov-pend { color: var(--text-dim); opacity: .5; }


/* ---------- Cerrar la conciliación ---------- */
.conc-cierre { margin-bottom: 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); }
.conc-cab { padding: 8px 12px; border-bottom: 1px solid var(--border); font-size: 12px;
  text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); display: flex; gap: 6px; align-items: center; }
.conc-rejilla { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; padding: 12px; }
@media (max-width: 900px) { .conc-rejilla { grid-template-columns: repeat(2, 1fr); } }
.conc-k { font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); margin-bottom: 3px; }
.conc-v { font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums; }
.conc-ok  { color: var(--green); }
.conc-mal { color: var(--red); }
.conc-rejilla input { width: 100%; font-size: 15px; font-weight: 600; text-align: right;
  font-variant-numeric: tabular-nums; }
.conc-pie { display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 8px 12px; border-top: 1px solid var(--border); }

/* Insignia con el número de pendientes, junto al nombre de la cuenta (como iFinance): el número
   dice cuánto trabajo falta y va donde se mira el nombre, no escondido bajo el saldo. */
.mov-cta-badge { flex: 0 0 auto; min-width: 18px; padding: 0 5px;
  border-radius: 9px; background: var(--c1); color: var(--bg);
  font-size: 10.5px; font-weight: 700; text-align: center; line-height: 16px; }
.mov-cta-badge.ok { background: transparent; color: var(--green); min-width: 0; padding: 0; }
.mov-cta-badge.ok .ti { font-size: 13px; }
.mov-cta.on .mov-cta-badge { background: var(--accent); }
.mov-cta-total:first-child { border-bottom: 1px solid var(--border); }
/* Apertura ↘ cierre del día */
.mov-dia-saldos { color: var(--text-dim); font-size: 11.5px; white-space: nowrap; }
.mov-dia-saldos .ti { font-size: 12px; margin: 0 2px; vertical-align: -1px; }
/* Punto de color de la categoría, junto a su nombre */
.md-cat { display: flex; align-items: center; gap: 7px; }
.md-cat select { flex: 1; min-width: 0; }
.md-punto { width: 11px; height: 11px; border-radius: 50%; background: currentColor; flex: 0 0 11px; }
.md-conc-conciliado   { color: var(--green); font-weight: 600; }
.md-conc-pendiente    { color: var(--amber); font-weight: 600; }
.md-conc-sin_resolver { color: var(--text-dim); }
.mov-medio { display: inline-flex; width: 18px; height: 18px; align-items: center; justify-content: center;
  color: var(--amber); font-size: 14px; }
/* LA BARRA DEL CANTO: un solo indicador de conciliación, y además el mando.
   Verde conciliado, ámbar pendiente, gris tenue sin resolver. Se lee recorriendo la columna de
   arriba abajo —que es como se busca «cuáles faltan»— y se pulsa para cambiar el estado.
   Los tres estados también se distinguen por ALTURA: la de «sin resolver» es más corta y clara,
   porque el verde y el ámbar se parecen para quien no distingue esos dos colores. */
.mov-td1 { position: relative; padding-left: 12px !important; }
.mov-barra-est { position: absolute; left: 2px; top: 4px; bottom: 4px; width: 4px;
  border: 0; border-radius: 2px; padding: 0; cursor: pointer; background: currentColor; }
.mov-barra-est:hover { width: 6px; left: 1px; }
.mov-barra-est:disabled { cursor: not-allowed; opacity: .4; }
.mov-barra-est.mov-est-b-conciliado   { color: var(--green); }
.mov-barra-est.mov-est-b-pendiente    { color: var(--amber); }
.mov-barra-est.mov-est-b-sin_resolver { color: var(--text-dim); opacity: .3; top: 40%; bottom: 40%; }
.mov-barra-est.mov-est-b-sin_resolver:hover { opacity: .7; top: 4px; bottom: 4px; }
.mov-elegida .mov-barra-est { box-shadow: 0 0 0 1px var(--bg-panel); }
.mov-det-sep { margin: 12px 0 7px; padding-top: 8px; border-top: 1px solid var(--border);
  font-size: 10px; text-transform: uppercase; letter-spacing: .07em; color: var(--text-dim); }


/* ---------- CADA VISTA, SU COLOR ----------
   Los tonos salen de la serie categórica del tema (--c1..c4), que ya está medida para contraste y
   para daltonismo. Y el nombre de la vista va escrito al lado: el color ayuda a reconocerla de un
   vistazo, pero quien no distinga esos tonos tiene que poder saber dónde está igual. */
.mov-centro { --vista: var(--accent); }
.mov-centro[data-vista="lista"]      { --vista: var(--c1); }
.mov-centro[data-vista="conciliar"]  { --vista: var(--c3); }
.mov-centro[data-vista="categorias"] { --vista: var(--c4); }

.mov-vista-regla { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.mov-vista-regla::after { content: ""; flex: 1; height: 2px; border-radius: 1px;
  background: linear-gradient(to right, var(--vista), transparent); }
/* En qué cuenta estás. Se dice aquí porque el selector de arriba desapareció: el panel de la
   izquierda la resalta, pero el que trabaja mira la lista, no el panel. */
.mov-vista-cta { font-style: normal; font-size: 12px; font-weight: 600; color: var(--text);
  order: 3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40%; }
.mov-vista-regla span { display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; text-transform: uppercase; letter-spacing: .07em; font-weight: 600;
  color: var(--vista); }

/* La cabecera de la tabla y el agrupador del día llevan el tinte de la vista, muy suave: se nota
   al cambiar de pantalla y no compite con el resaltado de la fila elegida. */
.mov-centro .mov-tabla thead th {
  background: color-mix(in srgb, var(--vista) 14%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--vista) 45%, transparent);
  color: var(--text);
}
.mov-centro .mov-dia > td {
  background: color-mix(in srgb, var(--vista) 8%, var(--bg-elev));
  border-top-color: color-mix(in srgb, var(--vista) 30%, var(--border));
}
.mov-centro .mov-dia:hover > td { background: color-mix(in srgb, var(--vista) 18%, var(--bg-elev)); }
.mov-centro .cifras-fila { border-left: 3px solid var(--vista); padding-left: 10px; }
.mov-centro .conc-cierre { border-color: color-mix(in srgb, var(--vista) 55%, var(--border)); }
.mov-centro .conc-cab { color: var(--vista); background: color-mix(in srgb, var(--vista) 8%, transparent); }
.mov-centro .mov-buscador:focus-within { border-color: var(--vista); }
.mov-centro .mov-barra-cat > span { background: var(--vista); }
/* Elegir columnas antes de imprimir */
.ir-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 3px 10px; }
@media (max-width: 640px) { .ir-cols { grid-template-columns: 1fr; } }
.ir-col { display: flex; gap: 7px; align-items: center; font-size: 12.5px; padding: 2px 0; cursor: pointer; }
.ir-col.fijo { opacity: .6; cursor: default; }
/* Meses cerrados */
.conc-meses { display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  padding: 8px 12px; border-top: 1px solid var(--border); }
.conc-meses-k { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); }
.conc-mes { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; padding: 2px 8px;
  border-radius: 11px; border: 1px solid var(--green); color: var(--green);
  background: color-mix(in srgb, var(--green) 12%, transparent); cursor: pointer; }
.conc-mes:hover { background: var(--green); color: var(--bg); }
/* Una fila de mes cerrado se ve cerrada: sin botón de estado y con el candado en la primera celda. */
.mov-tabla tbody tr.mov-cerrado > td:first-child::after {
  content: "\\ea78"; font-family: "tabler-icons"; font-size: 10px; color: var(--text-dim); margin-left: 2px; }
.mov-cerrado .mov-est { opacity: .35; cursor: not-allowed; }
/* Comprobante del movimiento */
.md-adj { display: flex; align-items: center; gap: 7px; padding: 6px 8px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-elev); }
.md-adj .ti { color: var(--text-dim); }
.md-adj-n { flex: 1; min-width: 0; background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--accent); text-align: left; font: inherit; font-size: 12.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-decoration: underline; }
.md-adj-prev { display: block; max-width: 100%; max-height: 160px; margin-top: 6px;
  border: 1px solid var(--border); border-radius: var(--radius); object-fit: contain; }
.mov-clip { color: var(--text-dim); font-size: 11px; }

/* ---------- Buscador predictivo del directorio ---------- */
.dir-buscador { position: relative; flex: 1; min-width: 0; display: flex; align-items: center; }
.dir-buscador .dir-q { width: 100%; padding-right: 26px; }
.dir-x { position: absolute; right: 4px; background: none; border: 0; cursor: pointer;
  color: var(--text-dim); padding: 2px; line-height: 1; }
.dir-x:hover { color: var(--red); }
.dir-lista { position: absolute; top: calc(100% + 3px); left: 0; right: 0; z-index: 60;
  max-height: 260px; overflow: auto; padding: 4px;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); }
.dir-op { display: grid; grid-template-columns: 1fr auto; gap: 0 8px; width: 100%; padding: 5px 8px;
  background: none; border: 0; border-radius: var(--radius); cursor: pointer; text-align: left;
  color: var(--text); font: inherit; font-size: 12.5px; }
.dir-op:hover, .dir-op.on { background: var(--accent); color: var(--bg); }
.dir-op:hover .dir-op-r, .dir-op.on .dir-op-r,
.dir-op:hover .dir-op-roles, .dir-op.on .dir-op-roles { color: var(--bg); opacity: .85; }
.dir-op-n { font-weight: 600; }
.dir-op-r { font-size: 11px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.dir-op-roles { grid-column: 1 / -1; font-size: 10.5px; color: var(--text-dim); text-transform: lowercase; }
.dir-op-nuevo { color: var(--accent); font-weight: 600; border-top: 1px solid var(--border);
  border-radius: 0; margin-top: 3px; padding-top: 7px; display: flex; align-items: center; gap: 6px; }
.dir-op-nuevo:hover { background: var(--accent); color: var(--bg); }
.dir-vacio { padding: 8px; font-size: 12px; color: var(--text-dim); }
/* Categorías: rejilla con icono y color */
.cm-rejilla { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
.cm-item { display: grid; grid-template-columns: auto 1fr; gap: 2px 8px; align-items: center;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); cursor: pointer; text-align: left; font: inherit; }
.cm-item:hover { border-color: currentColor; }
.cm-item > .ti { grid-row: 1 / 3; font-size: 20px; }
.cm-n { font-size: 12.5px; font-weight: 600; color: var(--text); }
.cm-t { font-size: 10.5px; color: var(--text-dim); }
.ce-iconos { display: grid; grid-template-columns: repeat(auto-fill, minmax(34px, 1fr)); gap: 4px;
  max-height: 150px; overflow: auto; padding: 2px; }
.ce-icono { display: flex; align-items: center; justify-content: center; height: 32px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-panel);
  color: var(--text-dim); cursor: pointer; font-size: 17px; }
.ce-icono:hover { color: var(--text); }
.ce-icono.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.mov-cat .ti { font-size: 11px; vertical-align: -1px; }
.md-punto-i { font-size: 15px; }
/* El detalle de la cuenta ACTIVA, en el panel: lo que antes ocupaba una franja entera arriba. */
.mov-cta-det { padding: 6px 10px 8px; background: var(--zebra); border-bottom: 1px solid var(--border); }
/* El rótulo no se parte y la cifra no se separa de su signo: en una columna de 230 px un texto
   largo se envuelve y deja el «−» solo en la línea de arriba, que se lee como un guion. */
.mov-cta-det > div { display: flex; justify-content: space-between; gap: 8px; font-size: 11.5px;
  color: var(--text-dim); padding: 1px 0; white-space: nowrap; }
.mov-cta-det > div > span { overflow: hidden; text-overflow: ellipsis; }
.mov-cta-det b { color: var(--text); font-variant-numeric: tabular-nums; }
.mov-cta-det b.pend { color: var(--amber); }
.mov-cta-nota { display: block !important; font-size: 10px; opacity: .8; margin-top: 2px; }
.mov-aviso-apagados { display: flex; align-items: center; gap: 6px; margin-bottom: 8px;
  padding: 5px 9px; border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--bg-elev); font-size: 11.5px; color: var(--text-dim); }

/* ---------- RIEL PLEGABLE ----------
   Plegado el riel deja los ICONOS, no desaparece: navegar sigue costando un clic. Un riel que se
   esconde entero obliga a sacarlo cada vez que se cambia de pantalla, y entonces nadie lo pliega. */
/* Arriba del todo y separado: plegar el riel es una acción de la VENTANA, no un destino. Estar
   arriba lo aleja además de «Salir», que vive abajo — dos cosas que no deben confundirse nunca. */
.riel-plegar { position: absolute; top: 10px; right: 6px; background: none; border: 0;
  color: var(--text-dim); cursor: pointer; padding: 3px; border-radius: var(--radius); line-height: 1;
  opacity: .6; }
.riel-plegar:hover { opacity: 1; }
.riel-plegar:hover { background: var(--bg-elev); color: var(--text); }
.riel-plegar i { font-size: 18px; }

body.riel-plegado { padding-left: 56px; }
.riel-plegado .riel { width: 56px; padding-left: 6px; padding-right: 6px; }
/* Los textos se van; los iconos se centran y crecen un punto para compensar. */
.riel-plegado .riel-btn span:not(.notif-badge), .riel-plegado .riel .navbtn span:not(.notif-badge),
.riel-plegado #brand-text, .riel-plegado .riel-rotulo { display: none; }
.riel-plegado .riel-btn, .riel-plegado .riel .navbtn { justify-content: center; padding: 9px 0; }
.riel-plegado .riel-btn i, .riel-plegado .riel .navbtn i { font-size: 21px; }
.riel-plegado .riel-marca { padding: 4px 0 10px; }
.riel-plegado .riel-marca .logo { min-height: 30px; }
.riel-plegado .riel-marca .logo svg { width: 26px; height: 26px; }
.riel-plegado .riel-plegar { position: static; align-self: center; margin-bottom: 4px; }
.riel-plegado .notif-badge { top: 4px; right: 6px; }
/* El menú desplegable no puede salir dentro de 56 px: se ancla al borde y crece hacia afuera. */
.riel-plegado .dropdown-menu { left: 100%; margin-left: 6px; }
@media (max-width: 900px) { body.riel-plegado { padding-left: 0; } .riel-plegado .riel { width: auto; } }
/* El mando del reparto: el chip ÷N es el botón, no un adorno al lado. */
.mov-frac { display: inline-flex; align-items: center; gap: 3px; font-size: 10.5px; padding: 1px 7px;
  border-radius: 10px; border: 1px solid var(--c1); color: var(--c1); background: none;
  cursor: pointer; font-family: inherit; line-height: 1.5; }
.mov-frac:hover { background: var(--c1); color: var(--bg); }
.mov-frac.on { background: color-mix(in srgb, var(--c1) 18%, transparent); }
.mov-frac .ti { font-size: 11px; }
.mov-elegida .mov-frac { border-color: var(--text); color: var(--text); }

/* ---------- La pestaña de movimientos, vestida como el resto ---------- */
/* La obra a la que se carga, junto a la categoría: mismo tamaño de etiqueta, distinto color, para
   que se distingan de un vistazo sin leerlas. */
.mov-obra { display: inline-flex; align-items: center; gap: 4px; font-size: 10.5px; padding: 1px 7px;
  border-radius: 10px; border: 1px solid var(--text-dim); color: var(--text-dim); }
.mov-obra .ti { font-size: 11px; }
.mov-elegida .mov-obra { border-color: var(--text); color: var(--text); }
/* Zebra del tema, no un gris inventado: se ajusta sola en los seis temas y en modo oscuro. */
.mov-tabla tbody tr:not(.mov-dia):not(.mov-hijo):nth-of-type(even) > td { background: var(--zebra); }
.mov-tabla tbody tr.mov-elegida > td, .mov-tabla tbody tr.mov-abierto > td { background-image: none; }
/* Vacío con salida: un texto suelto deja al usuario mirando la pantalla sin saber qué hacer. */
.mov-vacio { display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 34px 16px; text-align: center; color: var(--text-dim); }
.mov-vacio > .ti { font-size: 30px; opacity: .35; }
.mov-vacio strong { color: var(--text); font-size: 14px; }
.mov-vacio .sub { max-width: 42ch; }
.mov-vacio .btn { margin-top: 6px; }
/* Saldo corrido, quién lo registró, comprobante que falta */
.mov-saldo { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.mov-elegida .mov-saldo { color: var(--text); }
.mov-quien { font-size: 10.5px; color: var(--text-dim); padding: 1px 6px; border-radius: 10px;
  border: 1px dashed var(--border); }
.mov-falta { display: inline-flex; align-items: center; gap: 4px; font-size: 10.5px; padding: 1px 7px;
  border-radius: 10px; border: 1px solid var(--amber); color: var(--amber);
  background: color-mix(in srgb, var(--amber) 12%, transparent); }
.mov-falta .ti { font-size: 11px; }
.mov-repe { color: var(--text-dim); opacity: .5; cursor: help; }
/* Presupuesto por categoría: la barra dice cuánto queda, no cuánto pesa. */
.mov-barra-cat.pres-bien   > span { background: var(--green); }
.mov-barra-cat.pres-aviso  > span { background: var(--amber); }
.mov-barra-cat.pres-pasado > span { background: var(--red); }
.pres-pie { font-size: 10.5px; color: var(--text-dim); margin-top: 3px; }
.pres-pie strong { color: var(--red); }
/* En la proyección por mes, lo que pasa ANTES del mes preguntado se atenúa: hace falta para que el
   saldo llegue bien, pero no es lo que se preguntó. */
.pl-fuera > td { opacity: .45; }
/* Cabecera compacta en las pestañas de trabajo: el título en su renglón y las acciones a la par,
   sin subtítulo ni franja de cifras. Lo que se gana en alto son tres o cuatro renglones de datos. */
.page-head-compacta { margin-bottom: 6px; align-items: center; }
.page-head-compacta h1 { font-size: 20px; margin: 0; }
/* «¿Qué es esto?» — la explicación de la pestaña, plegada. */
.fin-ayuda { margin: 0 0 10px; border-left: 3px solid var(--c1); background: var(--zebra);
  border-radius: var(--radius); }
.fin-ayuda summary { cursor: pointer; padding: 5px 10px; font-size: 12px; color: var(--c1);
  display: flex; align-items: center; gap: 5px; list-style: none; }
.fin-ayuda summary::-webkit-details-marker { display: none; }
.fin-ayuda summary:hover { color: var(--text); }
.fin-ayuda p { margin: 0; padding: 0 12px 10px 30px; font-size: 12.5px; line-height: 1.5;
  color: var(--text-dim); max-width: 90ch; }

/* El aviso de que la lista está cortada. Un tope invisible es lo que hacía que el filtro mintiera:
   si hay más de los que caben, se dice — y se dice que el filtro YA se aplicó en el servidor, para
   que nadie crea que está viendo el total. */
.mov-tope {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  color: var(--oxido, #b4541f); border: 1px solid currentColor; border-radius: 10px;
  padding: 1px 9px; margin-left: 6px;
}

/* Reglas de clasificación automática */
.rg-tabla code { font-family: var(--font-mono, monospace); font-size: 12.5px;
  background: var(--fondo-hundido, rgba(0,0,0,.04)); padding: 1px 5px; border-radius: 4px; }
.rg-off > td { opacity: .5; }

/* ---------- EL SEMÁFORO DE CAJA ---------- */
/* Arriba de todo y en todas las pestañas: para quien no es de finanzas, la única pregunta es
   «¿puedo comprometer esta compra?». La cifra grande es lo más bajo que llega la caja en 30 días
   sin contar los cobros del cliente — el saldo de hoy es justo lo que engaña. */
.semaforo {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  border: 1px solid var(--border); border-left: 5px solid var(--verde, #6b8f4e);
  border-radius: var(--radius); padding: 10px 14px; margin: 10px 0 4px;
  background: var(--bg-panel);
}
.semaforo.sem-ambar { border-left-color: var(--amber, #c98a2b); }
.semaforo.sem-rojo  { border-left-color: var(--red, #b4442f); }
.sem-luz { width: 11px; height: 11px; border-radius: 50%; background: var(--verde, #6b8f4e); flex: none; }
.sem-ambar .sem-luz { background: var(--amber, #c98a2b); }
.sem-rojo  .sem-luz { background: var(--red, #b4442f); }
.sem-cifras { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; flex: 1; min-width: 0; }
.sem-principal { display: flex; flex-direction: column; }
.sem-k { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-dim); }
.sem-v { font-size: 22px; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1.1; }
.sem-rojo .sem-v { color: var(--red, #b4442f); }
.sem-frase { font-size: 13px; min-width: 0; }
.sem-frase .sub { display: block; font-size: 11.5px; }
.sem-avisos { display: flex; gap: 6px; flex-wrap: wrap; }
.sem-aviso {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12px; cursor: pointer;
  border: 1px solid var(--border); border-radius: 12px; padding: 3px 10px;
  background: var(--bg-elev); color: var(--text);
}
.sem-aviso:hover { border-color: var(--accent); color: var(--accent); }

/* Formatos de banco aprendidos: se distingue el que costó IA del que salió solo, porque el
   usuario tiene derecho a saber en qué se le fue el dinero. */
.fmt-ia { display: inline-flex; align-items: center; gap: 4px; font-size: 12px;
  color: var(--oxido, #b4541f); }

/* La barra de lote: aparece solo cuando hay algo elegido, y lleva las dos decisiones que se toman
   de a muchos —la obra y la categoría—. Cargar a la obra era el caso peor: el único camino era el
   panel de la derecha, movimiento por movimiento. */
.mov-lote {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  border: 1px solid var(--accent); border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  padding: 8px 12px; margin: 8px 0;
}
.mov-lote-n { font-weight: 600; font-size: 13px; display: inline-flex; align-items: center; gap: 6px; }
.mov-lote-c { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; }
.mov-lote-c select { max-width: 15rem; }

/* ---------- INDIRECTOS Y SOBRECOSTO ---------- */
/* Las barras NO se recortan al 100%: el exceso se ve, porque el exceso es justo el dato. Una barra
   llena y una barra pasada de rosca tienen que distinguirse de un vistazo. */
.ind-barra { position: relative; height: 8px; border-radius: 4px; overflow: hidden;
  background: var(--bg-elev, rgba(0,0,0,.06)); display: flex; }
.ind-barra > span { display: block; height: 100%; background: var(--verde, #6b8f4e); }
.ind-ojo > span { background: var(--amber, #c98a2b); }
.ind-mal > span { background: var(--red, #b4442f); }
.ind-exceso { background: repeating-linear-gradient(45deg,
  var(--red, #b4442f), var(--red, #b4442f) 3px, transparent 3px, transparent 6px) !important; }
.ind-oficina { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px;
  border: 1px solid var(--border); border-left: 5px solid var(--verde, #6b8f4e);
  border-radius: var(--radius); padding: 12px 16px; background: var(--bg-panel); }
.ind-oficina.ind-mal { border-left-color: var(--red, #b4442f); }
.ind-rojo { color: var(--red, #b4442f); }

/* ---------- LAS TRES CAPAS Y LOS INSUMOS VIGILADOS ---------- */
/* La franja dice contra QUÉ se está comparando el gasto. Sin ella el usuario ve una desviación y
   no sabe si es respecto al contrato o respecto a lo que decidió ejecutar — que son dos cosas
   distintas y solo una es culpa de la obra. */
.capas-franja {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  border: 1px solid var(--border); border-left: 4px solid var(--verde, #6b8f4e);
  border-radius: 0 var(--radius) var(--radius) 0; padding: 10px 14px; margin-bottom: 12px;
  background: var(--bg-panel);
}
.capas-franja > div:first-child { flex: 1; min-width: 240px; }
.capas-franja .sub { display: block; font-size: 12px; }
.capas-pendiente { border-left-color: var(--amber, #c98a2b); }
.capas-cambio { text-align: right; }
.capas-cambio strong { display: block; font-size: 18px; font-variant-numeric: tabular-nums; }

.vig-ctl { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; margin: 10px 0; }
.vig-ctl input[type=range] { flex: 1; min-width: 120px; accent-color: var(--oxido, #b4541f); }
.vig-cab { margin: 10px 0 4px; }
.vig-fila { display: grid; grid-template-columns: 22px 1fr 130px 48px; gap: 10px; align-items: center;
  width: 100%; text-align: left; padding: 6px 4px; border: 0; border-bottom: 1px solid var(--border);
  background: none; color: var(--text); cursor: pointer; font-size: 13px; }
.vig-fila:hover { background: var(--zebra); }
.vig-fila.on i { color: var(--oxido, #b4541f); }
.vig-fila.off { opacity: .5; }
.vig-barra { height: 7px; border-radius: 4px; background: var(--bg-elev); overflow: hidden; }
.vig-barra > span { display: block; height: 100%; background: var(--oxido, #b4541f); }
.vig-fila.off .vig-barra > span { background: var(--text-dim); }
.vig-pct { text-align: right; font-size: 12px; font-variant-numeric: tabular-nums; }

/* La estructura de ejecución de una partida: las dos capas lado a lado. La diferencia entre ellas
   no es un error — es la decisión de cómo atacar la obra, y por eso tiene su propia columna. */
.ee-cab { margin-bottom: 10px; }
.ee-capas { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 12px; }
.ee-capa { padding: 10px 12px; border: 1px solid var(--border); border-radius: 12px; }
.ee-capa.ee-viva { border-left: 4px solid var(--oxido, #b4541f); border-radius: 0 12px 12px 0; }
.ee-ojo i { color: var(--oxido, #b4541f); }

/* El rendimiento de la cuadrilla: verde si produce más de lo que cuesta. */
.rend-bien { border-left: 4px solid var(--verde, #6b8f4e); padding-left: 10px; }
.rend-mal { border-left: 4px solid var(--red, #b4442f); padding-left: 10px; }
.rend-mal .ia-v { color: var(--red, #b4442f); }

/* Partidas del presupuesto que se quedaron fuera del programa. Va en franja fija y no escondida
   detrás del botón de avisos: con la obra en marcha, 21 partidas fuera del cronograma tampoco están
   en la curva ni en el control de costos, y eso no se puede descubrir por casualidad. */
.hint-bar.sin-programar { border-left: 4px solid var(--amber, #c98a2b); border-radius: 0 var(--radius) var(--radius) 0; }

/* ---------- CALENDARIO PARA ELEGIR FECHA ---------- */
/* Va en <body> y posicionado a mano, no dentro de la celda: dentro de una tabla con overflow se
   recortaba contra el borde del panel. El salto de AÑO va con flechas propias y a la vista porque
   en un cronograma de obra se salta de año constantemente. */
.cal-pop {
  position: fixed; z-index: 90; width: 246px; padding: 8px;
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0,0,0,.16); font-size: 13px;
}
.cal-cab { display: flex; align-items: center; gap: 2px; margin-bottom: 6px; }
.cal-tit { flex: 1; text-align: center; text-transform: capitalize; font-size: 13px; }
.cal-nav { border: 0; background: none; color: var(--text-dim); cursor: pointer;
  padding: 3px 5px; border-radius: var(--radius); line-height: 1; }
.cal-nav:hover { background: var(--zebra); color: var(--accent); }
.cal-sem, .cal-rej { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-sem span { text-align: center; font-size: 11px; color: var(--text-dim); padding-bottom: 2px; }
.cal-d { border: 0; background: none; color: var(--text); cursor: pointer; font-size: 12.5px;
  padding: 5px 0; border-radius: var(--radius); font-variant-numeric: tabular-nums; }
.cal-d:hover { background: var(--zebra); }
.cal-d.dom { color: var(--text-dim); }
.cal-d.hoy { box-shadow: inset 0 0 0 1px var(--accent); }
.cal-d.on { background: var(--accent); color: #fff; }
.cal-pie { display: flex; gap: 6px; margin-top: 8px; border-top: 1px solid var(--border); padding-top: 8px; }
.cal-pie .btn { flex: 1; }

/* La estructura de ejecución, agrupada por naturaleza. El renglón de la naturaleza lleva su
   subtotal a la derecha: la pregunta al adaptar una partida es «¿cuánto de esto es gente y cuánto
   material?», y es la que decide si conviene subcontratarla. */
.ee-tabla tbody.ee-grupo + tbody.ee-grupo { border-top: 8px solid transparent; }
.ee-nat > td { background: var(--bg-elev); border-top: 1px solid var(--border); padding-top: 7px; padding-bottom: 7px; }
.ee-nat .sub { margin-left: 8px; font-size: 11.5px; }
.ee-tabla tfoot td { border-top: 2px solid var(--border); padding-top: 8px; }

/* Filtros del control por actividad. Con 79 partidas en una lista, desplazarse a ciegas no es
   navegar. El filtro que más se usa es «van perdiendo»: es a lo que se entra a esta pantalla. */
.ctrl-filtros { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); margin-bottom: 8px; }
.ctrl-q { flex: 1 1 220px; min-width: 160px; }
.ctrl-filtros select { max-width: 12rem; }
.ctrl-chk { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.ctrl-filtros .btn .sub { font-size: 11px; opacity: .75; }
.ctrl-filtros .btn.primary .sub { opacity: .9; }
.ctrl-cuenta { margin-bottom: 8px; }

/* Quién ejecuta y quién lo lleva, en la estructura de ejecución. */
.ee-quien { display: flex; gap: 12px; flex-wrap: wrap; margin: 10px 0 4px; }
.ee-quien > .field { flex: 1 1 260px; }
/* ASIGNAR NO ES CONTRATAR: mientras no haya contrato vigente esto es una intención, y se dice.
   Si las dos cosas se vieran igual, alguien miraría el control, vería cuarenta partidas con
   contratista y creería la obra contratada sin un solo papel firmado. */
.ee-asig { display: flex; align-items: center; gap: 8px; font-size: 13px;
  border-left: 3px solid var(--amber, #c98a2b); padding: 7px 10px; border-radius: 0 6px 6px 0;
  background: color-mix(in srgb, var(--amber, #c98a2b) 8%, transparent); }
.ee-asig.ok { border-left-color: var(--verde, #6b8f4e);
  background: color-mix(in srgb, var(--verde, #6b8f4e) 8%, transparent); }

/* ---------- PAQUETES DE TRABAJO: cómo se reparte una partida entre oficios ---------- */
/* La cuenta de arriba es lo que manda: lo pactado más lo que queda al día tiene que caber en la
   mano de obra de la ficha. Se ve ANTES de firmar, no en el corte. */
.pq-cab { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px;
  flex-wrap: wrap; margin-bottom: 12px; }
.pq-cuenta { display: flex; gap: 18px; flex-wrap: wrap; padding: 8px 14px;
  border: 1px solid var(--border); border-left: 4px solid var(--verde, #6b8f4e); border-radius: 0 12px 12px 0; }
.pq-cuenta.mal { border-left-color: var(--red, #b4442f); }
.pq-cuenta > div { display: flex; flex-direction: column; }
.pq-cuenta strong { font-size: 17px; font-variant-numeric: tabular-nums; }
.pq-cuenta .sub { font-size: 11px; }
.pq-caja { border: 1px solid var(--border); border-left: 4px solid var(--oxido, #b4541f);
  border-radius: 0 8px 8px 0; padding: 8px 12px; margin-bottom: 8px; }
.pq-caja.pq-dia { border-left-color: var(--text-dim); }
.pq-tit { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pq-modo { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-dim);
  border: 1px solid var(--border); border-radius: 10px; padding: 0 8px; }
.pq-acc { margin-left: auto; }
.pq-nums { display: flex; gap: 16px; flex-wrap: wrap; font-size: 13px; margin: 4px 0; }
.pq-ok { color: var(--verde, #6b8f4e); }
.pq-reng { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.pq-chip { display: inline-flex; align-items: center; gap: 6px; font-size: 12px;
  border: 1px solid var(--border); border-radius: 12px; padding: 2px 10px; }
.pq-chip em { font-style: normal; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.pq-sel { cursor: pointer; }
.pq-sel.on { border-color: var(--oxido, #b4541f); background: color-mix(in srgb, var(--oxido, #b4541f) 8%, transparent); }
.pq-libres { border-top: 1px solid var(--border); padding-top: 10px; margin-top: 10px; }
.pq-nuevo { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 10px; }
.pq-nuevo input, .pq-nuevo select { flex: 1 1 150px; min-width: 120px; }

/* «Qué me falta» en el presupuesto: los mismos botones-con-cuenta que en Control por actividad,
   para que las dos pantallas se lean igual. Apagados cuando no hay nada que ver. */
.presu-faltas .btn .sub { font-size: 11px; opacity: .75; }
.presu-faltas .btn.primary .sub { opacity: .9; }
.presu-faltas .btn[disabled] { opacity: .4; }

/* El capítulo pasó de panel lateral a filtro. 340 px recuperados para las partidas, que es lo que
   se viene a leer. El índice sigue existiendo dentro del Análisis P.U., donde su trabajo es otro:
   saltar de una ficha a otra sin salir. */
.presu-cap { max-width: 16rem; }

/* La clave sin etiqueta: se identifica sola por formato, como el código en Control por actividad. */
.presu-clave .b-edit { font-weight: 700; font-size: 16px; }

/* El rótulo Uniformat va con el MISMO tipo y tamaño que su código: son una sola cosa —«G1010
   Preliminares»— y ponerle al texto una letra menor lo convertía en una nota al pie de un dato que
   en realidad se lee junto. El rótulo estaba y solo salía en el tooltip: había que apuntar con el
   ratón para saber qué significa el código. */
.presu-uni-btn { font-size: 16px; font-weight: 400; gap: 6px; white-space: nowrap;
  max-width: 26rem; overflow: hidden; text-overflow: ellipsis; }
.presu-uniformat-chip { font-size: 15px; }

/* ---------- Destinos del modal de imprimir ----------
   Cada destino es una fila entera y pulsable, no un radio que hay que confirmar con otro boton:
   el modal tenia dos pasos para lo mismo. La flecha de la derecha dice que el clic lleva a algun
   lado (el APU todavia pregunta que fichas). */
.print-opts { display: flex; flex-direction: column; gap: 6px; }
.print-opt {
  display: flex; align-items: flex-start; gap: 10px; width: 100%; text-align: left;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); color: var(--text); cursor: pointer; font: inherit;
  transition: border-color .12s, background .12s;
}
.print-opt:hover, .print-opt:focus-visible { border-color: var(--accent); background: var(--bg-elev); }
.print-opt > .ti:first-child { font-size: 20px; color: var(--accent); line-height: 1.3; flex-shrink: 0; }
.print-opt > span { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* .hint global es una CAJA (fondo, borde, padding) pensada para avisos sueltos. Dentro de una
   fila pulsable eso pinta un recuadro gris dentro de otro recuadro: aqui es solo texto al pie. */
.print-opt .hint, .chk .hint {
  font-size: 12.5px; color: var(--text-dim);
  background: none; border: 0; border-radius: 0; padding: 0; margin: 0;
}
.print-opt-ir { color: var(--text-dim); align-self: center; flex-shrink: 0; }

/* Unidad, Cantidad y P.U. arrancan a la IZQUIERDA de su celda, rotulo incluido. Iban pegadas a la
   derecha por llevar .num, que existe para que los IMPORTES alineen su ultima cifra y se puedan
   comparar de un vistazo en columna. Ese argumento no vale aqui: la unidad es una palabra, la
   cantidad y el P.U. no se suman entre partidas, y con el rotulo a un lado y el dato al otro el ojo
   hacia el viaje dos veces por columna. Conservan tabular-nums, que es lo util de .num. */
.presu-stat.izq { align-items: flex-start; }
.presu-stat.izq label,
.presu-stat.izq strong,
.presu-stat.izq .b-edit { text-align: left; }

/* Botón que existe pero el presupuesto cerrado detiene. Antes se BORRABA: la función desaparecía
   de la pantalla y no había forma de saber que estaba ahí ni por qué no aparecía. Apagado se ve
   que existe, el cursor dice que no responde y el título explica el motivo. */
.bloqueado-cerrado {
  opacity: .38;
  cursor: not-allowed !important;
  pointer-events: auto;   /* hace falta para que el título salga al pasar por encima */
  filter: grayscale(1);
}
.bloqueado-cerrado:hover { background: inherit !important; border-color: inherit !important; }

/* El contacto que ejecuta obra se distingue del que vende material: son dos cosas distintas y en
   una lista de doscientos hay que poder verlo sin abrir la ficha. */
.dir-rol-sub { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); }
.dir-prov { border-left: 3px solid var(--border); padding-left: 12px; margin: 10px 0; }

/* ---------------------------------------------------------------------------
   MENU «MAS ACCIONES» DE LA CABECERA DE OBRA (ago 2026)
   Lo destructivo —reiniciar y eliminar la obra— vivia en dos botones rojos en la
   misma fila que «Editar proyecto». Ahora vive aqui: hay que abrir el menu a
   proposito, y dentro va en rojo para que no se confunda con lo demas.
   --------------------------------------------------------------------------- */
.head-mas { position: relative; }
.head-mas-menu { right: 0; left: auto; min-width: 220px; }
.migas-op.peligro { color: var(--red); }
.migas-op.peligro:hover { background: color-mix(in srgb, var(--red) 12%, transparent); }

/* ---------------------------------------------------------------------------
   VOZ (ago 2026) — dictado y lectura.
   El microfono va DENTRO del campo, arriba a la derecha: en una descripcion de
   varias lineas es donde no estorba al texto. `.voz-wrap` existe solo para
   poder posicionarlo sin tocar el ancho del campo que envuelve.
   --------------------------------------------------------------------------- */
.voz-wrap { position: relative; display: block; }
.voz-wrap > textarea, .voz-wrap > input { width: 100%; }
.voz-mic { position: absolute; top: 6px; right: 6px; z-index: 2;
  width: 26px; height: 26px; border: 1px solid var(--border); border-radius: 7px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-panel); color: var(--text-dim); cursor: pointer; opacity: .55;
  transition: opacity .12s, color .12s, border-color .12s; }
.voz-wrap:hover .voz-mic, .voz-mic:focus-visible { opacity: 1; }
.voz-mic:hover { color: var(--accent); border-color: var(--accent); }
.voz-mic i { font-size: 15px; }
/* Grabando: el punto rojo late para que no quede duda de que el microfono esta abierto. */
.voz-mic.grabando { opacity: 1; color: #fff; background: var(--red); border-color: var(--red);
  animation: voz-late 1.1s ease-in-out infinite; }
@keyframes voz-late { 0%,100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 55%, transparent); }
                      50%     { box-shadow: 0 0 0 5px color-mix(in srgb, var(--red) 0%, transparent); } }
.voz-bloque { padding: 10px 0; border-top: 1px solid var(--border); }
.voz-bloque:first-of-type { border-top: 0; }
.voz-bloque > b { display: block; margin-bottom: 4px; }
.voz-genero { display: flex; gap: 6px; margin: 6px 0; }
.voz-aviso { color: var(--red); }
.voz-ok { color: var(--green, var(--accent)); }
.voz-lex { display: flex; flex-direction: column; gap: 4px; max-height: 190px; overflow-y: auto; }
.voz-lex-fila { display: flex; align-items: center; gap: 6px; padding: 3px 0; }
.voz-lex-par { flex: 1; min-width: 0; font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.voz-lex-par i { color: var(--text-dim); font-style: normal; }
/* Lo que aun no se aplica se ve distinto: es una propuesta, no una regla de la casa. */
.voz-lex-fila.por-aprobar { border-left: 2px solid var(--accent); padding-left: 6px; }
