:root{
  --ground:#D3D3D3; --paper:#FFFFFF; --sunk:#EEF0F3; --line:#D2D6DD; --line-2:#A9B0BC;
  --ink:#0E101C; --ink-2:#394055; --ink-3:#5A6174;
  --navy:#071D49; --slate:#214B4E; --slate-soft:#DFEAEA; --blue:#2a78d6;
  --ok:#2F7D3B; --ok-soft:#E1F1E2; --warn:#8F5B00; --warn-soft:#FBEFD7; --bad:#B3261E; --bad-soft:#F9E1DF;
  --note:#F4F1E8; --note-ink:#4C4631; --auto:#E3EBF6; --auto-ink:#1F4B8A;
  /* Los dos colores de las series de las gráficas. NO se escogieron a ojo:
     se midieron contra el fondo y entre sí, también como los ve alguien que
     no distingue el rojo del verde. Aquí van dos y no ocho a propósito: una
     gráfica de esta aplicación que necesite tres colores es una gráfica que
     hay que partir en dos. El amarillo, el verde y el rojo NO se usan como
     series: significan bien, cuidado y mal en toda la plataforma, y una
     línea verde que solo quisiera decir «pagado» mentiría. */
  --serie-1:#2a78d6; --serie-2:#0F9B8E;
  --display:"Lexend Giga","Arial Black",system-ui,sans-serif;
  --sub:"Sora","Segoe UI",system-ui,sans-serif;
  --body:"Roboto",system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:"Roboto Mono",ui-monospace,Menlo,Consolas,monospace;
  color-scheme:light;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --ground:#0E101C; --paper:#171B2B; --sunk:#11141F; --line:#2A3247; --line-2:#3E4863;
    --ink:#EDEFF3; --ink-2:#B9BFCC; --ink-3:#8F96A7;
    --navy:#9DB4E6; --slate:#6FB0B4; --slate-soft:#18302F; --blue:#3987e5;
    --ok:#6CC27A; --ok-soft:#173022; --warn:#E3AA45; --warn-soft:#33280F; --bad:#F08079; --bad-soft:#3A1C1A;
    --note:#24221B; --note-ink:#D8D0B6; --auto:#1A2742; --auto-ink:#9DB4E6;
  --serie-1:#3F8AD9; --serie-2:#12A896;
    color-scheme:dark;
  }
}
:root[data-theme="dark"]{
  --ground:#0E101C; --paper:#171B2B; --sunk:#11141F; --line:#2A3247; --line-2:#3E4863;
  --ink:#EDEFF3; --ink-2:#B9BFCC; --ink-3:#8F96A7;
  --navy:#9DB4E6; --slate:#6FB0B4; --slate-soft:#18302F; --blue:#3987e5;
  --ok:#6CC27A; --ok-soft:#173022; --warn:#E3AA45; --warn-soft:#33280F; --bad:#F08079; --bad-soft:#3A1C1A;
  --note:#24221B; --note-ink:#D8D0B6; --auto:#1A2742; --auto-ink:#9DB4E6;
  --serie-1:#3F8AD9; --serie-2:#12A896;
  color-scheme:dark;
}
*{box-sizing:border-box}
body{background:var(--ground);color:var(--ink);font-family:var(--body);font-size:14px;line-height:1.5}

/* ─── Estructura de la aplicación ─────────────────────────────────── */
body{margin:0;min-height:100vh}
.centro{min-height:100vh;display:grid;place-items:center;padding:24px}
.tarjeta{background:var(--paper);border-radius:12px;box-shadow:0 1px 2px rgba(7,29,73,.06),0 10px 30px rgba(7,29,73,.10);width:100%;max-width:420px;overflow:hidden}
.tarjeta .cab{background:var(--navy);color:#fff;padding:22px;border-bottom:4px solid var(--slate)}
.tarjeta .cab b{font-family:var(--display);font-size:17px;letter-spacing:.04em;display:block}
.tarjeta .cab span{color:#D3D3D3;font-size:12.5px}
.tarjeta form{padding:22px;display:grid;gap:14px}
label{display:grid;gap:5px;font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-3);font-weight:600}
input{font:inherit;font-size:15px;padding:10px 12px;border:1px solid var(--line-2);border-radius:8px;background:var(--paper);color:var(--ink);width:100%}
input:focus-visible{outline:2px solid var(--navy);outline-offset:1px}
.btn{font:inherit;font-weight:600;padding:11px 16px;border-radius:8px;border:1px solid var(--navy);background:var(--navy);color:#fff;cursor:pointer}
.btn:disabled{opacity:.55;cursor:progress}
.btn.plano{background:transparent;color:var(--ink-2);border-color:var(--line-2)}
.aviso{border-radius:8px;padding:10px 12px;font-size:13px;background:var(--bad-soft);color:var(--bad);border:1px solid var(--bad)}
.aviso.nota{background:var(--note);color:var(--note-ink);border-color:var(--line-2)}

.barra{background:var(--navy);color:#fff;padding:12px 20px;display:flex;align-items:center;gap:14px;flex-wrap:wrap;border-bottom:4px solid var(--slate)}
.barra b{font-family:var(--display);font-size:15px;letter-spacing:.04em}
.barra .yo{margin-left:auto;display:flex;align-items:center;gap:10px;font-size:13px}
.rol{font:600 10.5px var(--body);letter-spacing:.06em;text-transform:uppercase;background:rgba(255,255,255,.15);padding:2px 9px;border-radius:999px}

/* A qué base está conectada esta copia. Hay dos instalaciones —la de
   trabajo y la de demostración— y la pantalla tiene que decir cuál es:
   lo grave no es equivocarse al instalar, es enseñar la base real
   creyendo que es la de mentira.
   Sin rótulo en config.js sale discreto, con la referencia del proyecto
   de Supabase, que ya distingue las dos. Con rótulo sale en ámbar, que
   es lo que hace falta cuando esta copia NO es la de trabajo.
   Van los dos sitios nombrados porque «.tarjeta .cab span» pinta de
   gris claro cualquier span de dentro y le ganaría a una clase sola. */
.barra .yo .rotulo,
.tarjeta .cab .rotulo{
  font:500 10.5px var(--mono);letter-spacing:.04em;
  background:rgba(255,255,255,.12);color:#D3D3D3;
  padding:2px 8px;border-radius:999px;align-self:center;
}
.barra .yo .rotulo.marcado,
.tarjeta .cab .rotulo.marcado{
  font:700 10.5px var(--body);letter-spacing:.08em;text-transform:uppercase;
  background:var(--warn);color:#fff;
}
/* En la tarjeta de ingreso el rótulo va debajo del lema, no pegado a
   él: la cabecera apila «PUCOM» y el lema en bloque. */
.tarjeta .cab .rotulo{display:block;width:fit-content;margin-top:10px}
main{max-width:1100px;margin:0 auto;padding:22px 16px 60px}
h1{font-family:var(--sub);font-weight:600;font-size:24px;margin:0 0 4px;color:var(--navy)}
.sub{color:var(--ink-3);font-size:13.5px;margin:0 0 20px}
h2{font-family:var(--sub);font-weight:600;font-size:16px;color:var(--navy);margin:26px 0 10px;padding-bottom:6px;border-bottom:2px solid var(--navy)}
.rejilla{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:12px}
/* Una celda de rejilla no se encoge por debajo de su contenido a menos que
   se le diga: «min-width» vale «auto» por omisión en una cuadrícula. Sin
   esto, una tabla ancha dentro de una tarjeta empuja la página entera y en
   un teléfono aparece el desplazamiento horizontal — aunque la tabla ya
   venga envuelta en un «.tw» que sabe desplazarse sola. Lo cazó el banco
   de pruebas del programa a 390 px. */
.rejilla>*{min-width:0}
.cifras>*{min-width:0}
.caja{background:var(--paper);border:1px solid var(--line);border-radius:10px;padding:14px 16px}
.caja h3{font-family:var(--sub);font-weight:600;font-size:15px;margin:0 0 4px}
.caja p{margin:0;font-size:12.5px;color:var(--ink-3)}
.caja .cod{font-family:var(--mono);font-size:11.5px;color:var(--ink-3);letter-spacing:.06em}
.cifras{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px}
.cifra{background:var(--paper);border:1px solid var(--line);border-radius:10px;padding:12px 14px}
.cifra small{display:block;color:var(--ink-3);font-size:11px;text-transform:uppercase;letter-spacing:.06em}
.cifra b{font-family:var(--sub);font-weight:600;font-size:26px;display:block;line-height:1.2}
/* Un dato con su etiqueta, para texto. .cifra es para números grandes; esto
   es para «Contratista: Sanitarios del Norte», que se leía pegado. */
.dato small{display:block;color:var(--ink-3);font-size:11px;text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px}
.dato b{display:block;font-family:var(--sub);font-weight:600;font-size:14px;line-height:1.35}
/* «.mini» es un BOTÓN —borde, fondo y «cursor:pointer»—, y los pies de
   las cifras y los datos lo llevaban sin serlo: salían con aspecto de
   botón y el ratón se volvía mano encima de un texto que no hace nada.
   Se vio al retratar el tablero, pero estaba igual en el resumen del
   corte de Programación desde que existe. Aquí se desarma: un pie es
   texto pequeño, no un control. */
.cifra .mini,.dato .mini{display:block;border:0;background:none;padding:0;
  margin-top:3px;cursor:default;font-weight:400;font-size:11.5px;
  color:var(--ink-3);line-height:1.35}
.vacio{background:var(--paper);border:1px dashed var(--line-2);border-radius:10px;padding:22px;text-align:center;color:var(--ink-3);font-size:13.5px}
.pie{margin-top:32px;padding-top:12px;border-top:1px solid var(--line);font-size:11.5px;color:var(--ink-3)}
.oculto{display:none !important}

/* ─── Navegación y administración ─────────────────────────────────── */
/* ─── El selector de obra ────────────────────────────────────────────
   Va antes del menú y se tiene que leer como parte de la barra, no
   como un campo de formulario: lo que escoja manda sobre todas las
   pestañas que tiene al lado. Por eso lleva el borde claro y no el
   fondo blanco de un <select> normal.                                */
.selobra{display:flex;align-items:center;gap:7px;background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.30);border-radius:7px;padding:3px 4px 3px 10px;
  max-width:min(320px,52vw)}
.selobra .et{font:600 10.5px var(--body);letter-spacing:.08em;text-transform:uppercase;
  color:#AFC0DD;white-space:nowrap}
.selobra select{font:500 13px var(--body);color:#fff;background:transparent;border:0;
  padding:3px 4px;cursor:pointer;max-width:100%;text-overflow:ellipsis}
.selobra select:focus-visible{outline:2px solid #fff;outline-offset:1px;border-radius:4px}
/* Las opciones las pinta el sistema, no la página: sin esto salen
   blancas sobre blanco en Windows. */
.selobra select option{color:var(--ink);background:var(--paper)}
/* Quien tiene UNA sola obra no escoge: se le enseña puesta. Ofrecer una
   lista de uno es ofrecer una decisión que no existe. */
.selobra.fija{background:transparent;border-style:dashed}
.selobra.fija select{pointer-events:none}

/* El filtro de una pantalla cuando ya NO manda ella: se enseña el
   alcance y de dónde viene, sin control. Una pantalla que filtra sin
   decir por qué es la que hace pensar que se perdió información. */
.filtro-fijo{display:flex;flex-direction:column;gap:1px}
.filtro-fijo .valor{font:500 13px var(--body);color:var(--ink);
  background:var(--sunk);border:1px solid var(--line);border-radius:7px;padding:6px 10px}
.filtro-fijo .pista{font:400 10.5px var(--body);color:var(--ink-3)}

.navi{display:flex;gap:4px;flex-wrap:wrap}
.navi button{font:600 13px var(--body);color:#C9D2E4;background:transparent;border:0;padding:6px 12px;border-radius:7px;cursor:pointer}
.navi button:hover{background:rgba(255,255,255,.10);color:#fff}
.navi button[aria-current="page"]{background:rgba(255,255,255,.18);color:#fff}
.btn.chico{padding:5px 11px;font-size:12.5px}
.seccion{margin-bottom:30px}
.enc{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin:26px 0 10px;padding-bottom:6px;border-bottom:2px solid var(--navy)}
.enc h2{margin:0;border:0;padding:0}
.enc .cuenta{font-size:12.5px;color:var(--ink-3)}
.enc .der{margin-left:auto}
.panel{background:var(--paper);border:1px solid var(--line);border-radius:10px;overflow:hidden}
/* Era «.panel .tw», y una tabla envuelta fuera de un panel —dentro de una
   tarjeta de rejilla, por ejemplo— se desbordaba sin desplazarse. El
   envoltorio de tabla tiene que saber desplazarse esté donde esté: que
   funcionara solo dentro de un panel era una coincidencia, no una regla. */
.tw{overflow-x:auto}
table.datos{width:100%;border-collapse:collapse;font-size:13.5px}
table.datos th{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-3);text-align:left;padding:9px 12px;border-bottom:1px solid var(--line-2);font-weight:600;white-space:nowrap;background:var(--sunk)}
table.datos td{padding:9px 12px;border-bottom:1px solid var(--line);vertical-align:middle}
table.datos tr:last-child td{border-bottom:0}
table.datos td.mono{font-family:var(--mono);font-size:12.5px}
table.datos select,table.datos input{font-size:13px;padding:5px 8px}
.forma{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px;padding:14px;background:var(--sunk);border-top:1px solid var(--line);align-items:end}
.forma label{font-size:11px}
.forma .ancho{grid-column:1/-1}
.forma .acc{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.pista{font-size:12px;color:var(--ink-3);padding:0 14px 12px;background:var(--sunk)}
.pista b{color:var(--ink-2)}
.malo{border-color:var(--bad) !important}
.campo-error{font-size:11.5px;color:var(--bad);font-weight:600}
.nada{padding:22px;text-align:center;color:var(--ink-3);font-size:13.5px}
.chip{display:inline-block;font-size:11px;font-weight:600;padding:2px 8px;border-radius:999px;white-space:nowrap}
.chip.on{background:var(--ok-soft);color:var(--ok)}
.chip.off{background:var(--bad-soft);color:var(--bad)}
.chip.gris{background:var(--sunk);color:var(--ink-3);border:1px solid var(--line)}
.exito{border-radius:8px;padding:10px 12px;font-size:13px;background:var(--ok-soft);color:var(--ok);border:1px solid var(--ok);margin:10px 0}
.candado{border:1px solid var(--line-2);background:var(--note);color:var(--note-ink);border-radius:8px;padding:11px 13px;font-size:12.5px;margin:10px 14px 14px}
.candado b{color:var(--ink)}

/* ─── Minutas ─────────────────────────────────────────────────────── */
.filtros{display:flex;gap:10px;flex-wrap:wrap;align-items:end;margin-bottom:12px}
.filtros label{font-size:11px}
.filtros select{font:inherit;font-size:13.5px;padding:7px 10px;border:1px solid var(--line-2);border-radius:8px;background:var(--paper);color:var(--ink)}
.filtros .der{margin-left:auto}
tr.clic{cursor:pointer}
tr.clic:hover td{background:var(--sunk)}
.est{display:inline-block;font-size:11px;font-weight:600;padding:2px 9px;border-radius:999px;white-space:nowrap}
.est.borrador{background:var(--sunk);color:var(--ink-3);border:1px solid var(--line-2)}
.est.preparada{background:var(--warn-soft);color:var(--warn)}
.est.cerrada{background:var(--ok-soft);color:var(--ok)}
/* Lo anulado y lo devuelto: estados que no son un paso adelante. Se usaban
   en los documentos de pago y de cheque sin tener píldora, y salían como
   texto suelto al lado de los que sí la tienen. */
.est.malo{background:var(--bad-soft);color:var(--bad)}
.doc{background:var(--paper);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.doc .cabdoc{background:var(--navy);color:#fff;padding:16px 20px;display:flex;gap:14px;align-items:center;flex-wrap:wrap;border-bottom:4px solid var(--slate)}
.doc .cabdoc b{font-family:var(--display);font-size:15px;letter-spacing:.04em}
.doc .cabdoc .num{font-family:var(--mono);font-size:12.5px;color:#C9D2E4;margin-left:auto}
.doc .cuerpo{padding:18px 20px}
.metadoc{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:8px;overflow:hidden;margin-bottom:16px}
.metadoc div{background:var(--paper);padding:9px 12px;min-width:0}
.metadoc small{display:block;color:var(--ink-3);font-size:11px;text-transform:uppercase;letter-spacing:.06em}
.metadoc b{font-family:var(--sub);font-weight:600;overflow-wrap:anywhere}
.apart{margin-top:20px}
.apart h3{font-family:var(--sub);font-weight:600;font-size:15px;color:var(--navy);margin:0 0 8px;padding-bottom:5px;border-bottom:1.5px solid var(--navy);display:flex;gap:9px;align-items:center}
.apart h3 .letra{font-family:var(--mono);font-size:11.5px;color:#fff;background:var(--slate);border-radius:4px;padding:1px 7px}
.punto{border:1px solid var(--line);border-left:3px solid var(--line-2);border-radius:7px;padding:10px 12px;margin-bottom:8px;background:var(--paper)}
.punto.bloqueado{border-left-color:var(--bad)}
.punto.terminado{border-left-color:var(--ok)}
.punto.en_proceso{border-left-color:var(--warn)}
.punto h4{margin:0 0 3px;font-family:var(--sub);font-weight:600;font-size:14px}
.punto p{margin:0;font-size:13px;color:var(--ink-2)}
.punto .mini{display:flex;gap:8px;flex-wrap:wrap;margin-top:7px;font-size:11.5px;color:var(--ink-3);align-items:center}
.gente{display:flex;gap:6px;flex-wrap:wrap}
.foto{margin:0;border:1px solid var(--line);border-radius:7px;overflow:hidden;background:var(--sunk)}
.foto img{width:100%;display:block;aspect-ratio:4/3;object-fit:cover}
.foto figcaption{padding:6px 8px;font-size:12px}
.galeria{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px}
dialog.modal{border:0;padding:0;border-radius:12px;background:var(--paper);color:var(--ink);max-width:min(460px,calc(100vw - 32px));width:100%}
dialog.modal::backdrop{background:rgba(7,15,30,.55)}
dialog.modal h3{margin:0;padding:16px 18px;font-family:var(--sub);font-size:16px;color:#fff;background:var(--navy);border-bottom:4px solid var(--slate)}
dialog.modal form{padding:18px;display:grid;gap:13px}
dialog.modal .acc{display:flex;gap:9px;justify-content:flex-end}

/* ─── Llenado de la minuta ────────────────────────────────────────── */
textarea{font:inherit;font-size:14px;padding:9px 11px;border:1px solid var(--line-2);border-radius:8px;background:var(--paper);color:var(--ink);width:100%;resize:vertical}
select{font:inherit;font-size:14px;padding:9px 11px;border:1px solid var(--line-2);border-radius:8px;background:var(--paper);color:var(--ink);width:100%}
textarea:focus-visible,select:focus-visible{outline:2px solid var(--navy);outline-offset:1px}
.forma.clara{background:var(--sunk);border:1px solid var(--line);border-radius:9px;margin:10px 0}
/* El texto de la etiqueta y su nota van en la misma línea, y los campos
   alineados abajo aunque una etiqueta ocupe dos renglones. */
.forma.clara{align-items:stretch}
.forma.clara label{font-size:10.5px;display:flex;flex-direction:column;justify-content:flex-end;gap:4px}
.forma.clara label.check{flex-direction:row}
.forma.clara input,.forma.clara select,.forma.clara textarea{font-size:13.5px;padding:7px 9px}
.opc,.obl{text-transform:none;letter-spacing:0;font-weight:400;font-size:11px}
.opc{color:var(--ink-3)}
.obl{color:var(--warn);font-weight:600}
label.check{display:flex;gap:9px;align-items:flex-start;text-transform:none;letter-spacing:0;font-size:13px;font-weight:400;color:var(--ink-2)}
label.check input{width:auto;margin-top:2px;flex:none}
label.check i{color:var(--ink-3);font-style:normal;font-size:12.5px}
.btn.peligro{border-color:var(--bad);color:var(--bad)}
.btn.peligro:not(.plano){background:var(--bad);color:#fff}
.cta{font-weight:400;font-size:12px;color:var(--ink-3);margin-left:auto}
.falta{color:var(--warn);font-weight:600}
.punto.abierto{border-left-width:3px;background:var(--paper);box-shadow:0 2px 10px rgba(7,29,73,.10)}
.punto.abierto .forma.clara{margin:0}
.chip.asis{display:inline-flex;align-items:center;gap:6px;padding:3px 5px 3px 4px;font-size:12px;font-weight:400;color:var(--ink-2)}
.chip.asis i.no{color:var(--bad);font-style:normal;font-size:11px;font-weight:600}
.chip.asis .tog,.chip.asis .qui{font:inherit;line-height:1;border:0;border-radius:999px;cursor:pointer;padding:2px 6px}
.chip.asis .tog{background:var(--ok-soft);color:var(--ok);font-weight:700}
.chip.asis .qui{background:transparent;color:var(--ink-3);font-size:15px;padding:0 4px}
.chip.asis .qui:hover{color:var(--bad)}
details.impacto summary{cursor:pointer;font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-3);font-weight:600}
dialog.modal.ancha{max-width:min(600px,calc(100vw - 32px))}
dialog.modal ul{margin:6px 0 0;padding-left:20px}
dialog.modal li{margin:3px 0}
dialog.modal .aviso b{display:block;margin-bottom:2px}
/* El aviso de guardado aparece en cada campo: tiene que ser discreto. */
.exito.leve{display:inline-block;margin:6px 0 0;padding:3px 10px;font-size:11.5px;border-radius:999px;background:var(--ok-soft);color:var(--ok);border:0}

/* ─── Fotos ───────────────────────────────────────────────────────── */
.galeria.chica{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
.foto .sinimg{aspect-ratio:4/3;display:grid;place-items:center;font-size:12px;color:var(--ink-3);background:var(--sunk)}
.foto figcaption input{font-size:12.5px;padding:5px 7px}
.foto figcaption .acc{display:flex;gap:5px;margin-top:6px;flex-wrap:wrap}
.mini{font:600 11.5px var(--body);border:1px solid var(--line-2);background:var(--paper);color:var(--ink-2);border-radius:6px;padding:3px 8px;cursor:pointer;line-height:1.3}
.mini:disabled{opacity:.35;cursor:default}
.mini.peligro{border-color:var(--bad);color:var(--bad);margin-left:auto}
.subir{display:block;margin-top:12px;border:1.5px dashed var(--line-2);border-radius:10px;padding:14px 16px;cursor:pointer;text-transform:none;letter-spacing:0;font-weight:400;background:var(--sunk)}
.subir:hover{border-color:var(--navy)}
.subir input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.subir span{display:block}
.subir b{display:block;font-family:var(--sub);font-size:14px;color:var(--navy)}
.subir i{display:block;font-style:normal;font-size:12px;color:var(--ink-3);margin-top:3px}
.subir.chica{padding:9px 12px;margin-top:8px}
.subir.chica b{font-size:13px}
.anexos{border-top:1px dashed var(--line-2);margin-top:6px;padding-top:11px}
.anexos>b{display:block;font-family:var(--sub);font-size:12.5px;color:var(--navy);margin-bottom:7px}
.anexos .cta{margin-left:6px}

/* ─── Licitación ──────────────────────────────────────────────────── */

/* Los cinco momentos, para no tener que acordarse de en qué va. */
.pasos{display:flex;gap:4px;flex-wrap:wrap;margin:0 0 14px}
.paso{font-size:11.5px;font-weight:600;padding:4px 11px;border-radius:999px;
  background:var(--sunk);color:var(--ink-3);border:1px solid var(--line)}
.paso.hecho{background:var(--ok-soft);color:var(--ok);border-color:transparent}
.paso.ahora{background:var(--navy);color:#fff;border-color:transparent}
.paso.malo{background:var(--bad-soft);color:var(--bad);border-color:transparent}

/* Cifras: verde cuando sobra, rojo cuando falta. Aparte de .ok y .malo,
   que en esta hoja son bordes de campo con error. */
.cifra-ok{color:var(--ok);font-weight:600}
.cifra-mala{color:var(--bad);font-weight:600}

h2.chico{font-family:var(--sub);font-weight:600;font-size:15px;color:var(--navy);margin:0 0 8px}
h4.grupo{font-family:var(--sub);font-weight:600;font-size:13px;color:var(--slate);
  margin:12px 0 2px;text-transform:uppercase;letter-spacing:.04em}

/* El cuadro comparativo: muchas columnas, letra más chica, y la celda
   entera es el botón de escoger. */
table.cuadro{font-size:12.5px}
table.cuadro td,table.cuadro th{padding:5px 6px}
/* EL NOMBRE DEL OFERENTE SE PARTE en varias líneas. «table.datos th»
   pone «nowrap», que está bien en una tabla de columnas fijas y es malo
   aquí: a este cuadro le crece una columna por cada oferente, y un
   nombre como «Aluminios y Vidrios Quetzal, Sociedad Anónima» mide casi
   300 px de una tirada. Con cuatro oferentes la tabla ya pedía 168 px
   de más, y con seis, 730 — y las columnas que había que arrastrar para
   ver eran las ofertas, que es justo por lo que uno abre el cuadro.
   Medido con revisa_cuadro.js el 21/10. */
table.cuadro th{white-space:normal;line-height:1.3;vertical-align:bottom;max-width:120px}
/* Y la descripción del renglón se queda con el ancho que sobre, pero
   sin bajar de lo que hace falta para leerla. */
table.cuadro td:first-child{min-width:170px}
/* El radio se esconde DENTRO de la etiqueta: sin position:relative aquí,
   un absolute sin ancestro posicionado se va al borde de la hoja y la
   estira a lo ancho. Pasó, y por eso queda escrito. */
.elige{position:relative;display:block;cursor:pointer;border-radius:5px;padding:2px 5px;margin:-2px -5px}
.elige input{position:absolute;inset:0;width:100%;height:100%;opacity:0;margin:0;cursor:pointer}
.elige:hover{background:var(--sunk)}
.elige.elegido{background:var(--slate-soft);color:var(--slate);font-weight:700;
  box-shadow:inset 0 0 0 1.5px var(--slate)}
tr.resaltada td{background:var(--ok-soft)}

.resumen-mezcla{margin-top:16px;padding:14px 16px;border:1px solid var(--line);border-radius:10px;
  background:var(--sunk)}
.resumen-mezcla h3{font-family:var(--sub);font-weight:600;font-size:14px;color:var(--navy);margin:0 0 8px}

/* ─── Órdenes de compra ───────────────────────────────────────────── */

/* Casillas de verdad, en vez de píldoras con una casilla adentro: la
   píldora no envuelve bien el texto y salía la caja vacía. */
.casillas{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.casilla{display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  border:1px solid var(--line);border-radius:8px;padding:7px 12px;min-height:38px;
  font-size:13px;color:var(--ink-2);background:var(--paper)}
.casilla:hover{border-color:var(--line-2)}
.casilla input{margin:0;width:15px;height:15px;accent-color:var(--slate)}
.casilla input:disabled{cursor:default}
.casilla.marcada{background:var(--ok-soft);border-color:transparent;color:var(--ok);font-weight:600}
.casilla:has(input:disabled){cursor:default;opacity:.85}

/* Un campo que no se puede tocar tiene que verse así. En un documento ya
   emitido, un campo con aspecto editable invita a teclear en vano. */
.forma input:disabled,.forma select:disabled,.forma textarea:disabled{
  background:var(--sunk);color:var(--ink-3);border-style:dashed;cursor:default}

/* Los porcentajes de la forma de pago, en una línea: son una sola cosa
   —cómo se reparte el pago— y verlos juntos es ver si cuadran. */
.pct-linea{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;
  background:var(--sunk);border:1px solid var(--line);border-radius:9px;padding:12px 14px}
.pct-campo{display:flex;flex-direction:column;gap:3px;min-width:104px;flex:1 1 104px}
.pct-campo label{font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3)}
.pct-campo input{width:100%;box-sizing:border-box;text-align:right;padding-right:22px;min-height:38px}
.pct-campo{position:relative}
.pct-signo{position:absolute;right:9px;bottom:10px;font-size:12.5px;color:var(--ink-3);pointer-events:none}
.pct-total{border-left:1px solid var(--line-2);padding-left:14px;min-width:92px;flex:0 0 auto}
.pct-total b{font-family:var(--mono);font-size:19px;line-height:38px;text-align:right;display:block;
  padding-right:22px}
.pct-total.cuadra b{color:var(--ok)}
.pct-total.no-cuadra b{color:var(--bad)}
.pct-total .pct-signo{bottom:9px}
@media (max-width:700px){.pct-campo{flex:1 1 44%}.pct-total{flex:1 1 100%;border-left:0;padding-left:0;
  border-top:1px solid var(--line-2);padding-top:8px}}

/* El aviso del diálogo puede traer varias líneas: cuando un pegado de mil
   filas falla por tres motivos distintos, meterlos en un párrafo seguido
   es devolver el problema sin decirlo. `textContent` no interpreta HTML
   —y así tiene que seguir, porque ahí dentro va texto que vino de fuera—
   así que el salto de línea lo respeta el estilo. */
#lError{white-space:pre-line}

/* ─── La tabla del programa ─────────────────────────────────────────
   Carlos, 07/10/2026: «debe caber todo en una línea, se debe ajustar el
   ancho de la columna para que eso pase, así también las filas son menos
   altas y caben más en la pantalla». Tenía razón: una fecha partida en
   dos renglones duplica el alto de la fila, y con mil doscientas
   actividades eso es la mitad de la pantalla desperdiciada.

   La regla general: lo que es un dato corto —una fecha, un número, un
   código— nunca se parte; lo único que se parte es el NOMBRE de la
   actividad, que es lo único que de verdad puede ser largo. */
.datos .f, .datos .n, .datos .mono{white-space:nowrap}
.datos .n{text-align:right}
.datos .f{text-align:center}
table.prg{table-layout:auto}
/* Más apretada que las demás tablas, y a propósito: esta llega a diez
   columnas —esquema, nombre, dos fechas, la barra, va, debía, desvío,
   cumple, estado— y a 1280 px se salía de su caja por ochenta píxeles,
   o sea que para ver el estado había que arrastrar de lado. Cuatro
   píxeles menos a cada lado de cada celda son ochenta de vuelta. La
   altura de fila no se toca: mil doscientas líneas ya van justas. */
table.prg td, table.prg th{padding-top:5px;padding-bottom:5px;
  padding-left:8px;padding-right:8px}
/* Y el encabezado de la barra se parte en dos líneas en vez de empujar
   su columna: «Avance vs. previsto» es más ancho que la barra que
   titula. Se parte el rótulo, no la tabla. El selector lleva el
   «table.prg» delante porque «table.datos th» pone «nowrap» y pesa más
   que un «th.bar» a secas: sin eso la regla se escribe y no hace nada. */
table.prg th.bar{white-space:normal;line-height:1.25}
/* El nombre es lo que se encoge y lo que se parte, si hace falta. */
table.prg td:nth-child(2){min-width:220px}
.aprox{color:var(--ink-3);font-weight:600;margin-left:2px;cursor:help}

/* ─── La tabla del programa de obra ─────────────────────────────────
   Un programa trae mil doscientas líneas y se mira por bloques. Esto es
   lo que hace que un bloque se distinga de una actividad de un vistazo,
   y que el avance contra lo previsto se vea sin leer dos columnas de
   números. */

.cabtabla{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;justify-content:space-between}
.niveles{display:flex;align-items:center;gap:5px;flex-wrap:wrap}
.nv{font:600 12px var(--body);min-width:26px;padding:3px 7px;border-radius:6px;
    border:1px solid var(--line-2);background:var(--paper);color:var(--ink-2);cursor:pointer}
.nv:hover{border-color:var(--navy)}
.nv.on{background:var(--navy);border-color:var(--navy);color:#fff}

/* La fila de resumen va entera en negrita, no solo el título: media fila
   en negrita y media normal se lee como un error de formato. El fondo la
   separa del detalle sin usar una línea más. */
table.prg tr.res{font-weight:600;cursor:pointer}
table.prg tr.res>td{background:var(--sunk)}
table.prg tr.res.n1>td{background:var(--slate-soft);color:var(--ink)}
table.prg tr.res:hover>td{background:var(--auto)}
/* Un número suelto no es un botón: «.mini» es la clase de los botones
   chicos, y usarla para una cuenta la pinta como una caja pulsable. */
.cuenta{font:400 11.5px var(--body);color:var(--ink-3);white-space:nowrap}
table.prg tr.res .cuenta{font-weight:400}
.caret{display:inline-block;width:13px;color:var(--ink-3);font-size:10px}
.caret.sin{visibility:hidden}

/* El medidor. Una sola serie —lo que va— y una marca donde debía ir: el
   hueco entre las dos ES el atraso, y se ve sin color. Eso importa:
   rojo y verde son el mismo color para quien no los distingue, así que
   el color nunca es lo único que lleva el dato. */
/* 120 y no 132: con la columna de cumplimiento la tabla se pasaba de su
   caja por tres píxeles, y doce menos de barra los devuelven. Por debajo
   de 100 el hueco entre la barra y la marca deja de leerse, que es para
   lo único que está ahí. */
td.bar{width:120px;min-width:120px}
th.bar{width:120px}
.medidor{position:relative;display:block;height:9px;border-radius:5px;
         background:var(--sunk);overflow:visible}
.medidor .va{position:absolute;left:0;top:0;bottom:0;background:var(--blue);
             border-radius:1px 4px 4px 1px;min-width:2px}
.medidor .meta{position:absolute;top:-3px;bottom:-3px;width:2px;background:var(--ink);
               transform:translateX(-1px);box-shadow:0 0 0 2px var(--paper)}
table.prg tr.res .medidor{background:var(--paper)}
table.prg tr.res .medidor .meta{box-shadow:0 0 0 2px var(--sunk)}

/* El desvío y lo vencido llevan su número y su signo: el color acompaña,
   no sustituye. */
.des{font-variant-numeric:tabular-nums;white-space:nowrap}
.des.malo{color:var(--bad);font-weight:600}
.des.bien{color:var(--ok)}
/* Todavía no está vencido, pero vence pronto. No es «malo» —no hay nada
   que reclamar— ni «bien»: es el aviso de que quedan días. */
.des.pronto{color:var(--warn);font-weight:600}
/* El cumplimiento. Mismo tratamiento que el desvío —cifras de ancho fijo,
   sin partir la línea—, pero el color lo HEREDA DEL ESTADO de la fila y no
   de un umbral propio: dos columnas del mismo renglón clasificando con
   criterios distintos es una contradicción puesta a la vista, y el usuario
   tendría razón en no creerle a ninguna de las dos. */
.cu{font-variant-numeric:tabular-nums;white-space:nowrap}
.cu.malo{color:var(--bad);font-weight:600}
.cu.bien{color:var(--ok)}

/* ─── Los cinco estados del programa ────────────────────────────────
   Cada uno lleva su palabra además de su color, y los que tienen días
   llevan el número. El rojo y el verde de aquí están a 3.7 de distancia
   para quien no los distingue —medido, no supuesto—, así que el color
   acompaña y nunca sustituye. */

.ea{display:inline-block;font:600 11px var(--body);padding:2px 8px;border-radius:999px;
    white-space:nowrap;letter-spacing:.01em}
.ea.terminada {background:var(--sunk);color:var(--ink-3)}
.ea.vencida   {background:var(--bad-soft);color:var(--bad)}
.ea.atrasada  {background:var(--warn-soft);color:var(--warn)}
.ea.en-tiempo {background:var(--ok-soft);color:var(--ok)}
.ea.adelantada{background:var(--auto);color:var(--auto-ink)}

.tira{display:flex;gap:6px;flex-wrap:wrap;margin:2px 0 10px}

/* Las casillas para marcar qué columnas del pegado se guardan como
   categorías. */
.etqs{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 4px}
/* «label» va en mayúsculas en toda la plataforma, y aquí no puede: lo que
   se enseña es el NOMBRE DE SU COLUMNA tal como viene del Excel, y quien
   la marca tiene que reconocerla. «UBICACIÓN» no es lo que él escribió. */
.etq{display:flex;align-items:baseline;gap:6px;border:1px solid var(--line-2);
     border-radius:8px;padding:6px 10px;background:var(--paper);cursor:pointer;font-size:13px;
     text-transform:none;letter-spacing:normal;color:var(--ink-2);font-weight:400}
.etq:hover{border-color:var(--navy)}
.etq input{margin:0;cursor:pointer}
/* La fila de lo que no trae esa categoría. Se ve distinta porque no es
   un valor más: es el hueco, y el hueco también se mira. */
table.prg tr.sinasig>td{color:var(--ink-3);font-style:italic}
/* Una columna con casi un valor por actividad: se puede marcar, pero se
   ve que no va a juntar nada. */
.etq.floja{border-style:dashed;color:var(--ink-3)}

/* Encabezados que ordenan. Se nota que se pueden pulsar antes de
   pulsarlos, y el que manda lleva su flecha. */
th.orde{cursor:pointer;user-select:none}
th.orde:hover{color:var(--navy);background:var(--auto)}
th.orde .fl{font-size:9px;letter-spacing:0}
th.orde.porEste{color:var(--navy)}
/* Los chips de estado también sirven de filtro: el que está puesto se
   marca con un borde, no con otro color — el color ya dice qué estado es. */
button.ea{border:1px solid transparent;cursor:pointer;font:600 11px var(--body)}
button.ea:hover{border-color:var(--ink-3)}
button.ea.puesta{border-color:var(--ink);box-shadow:0 0 0 1px var(--ink)}
button.ea.todas{background:var(--paper);color:var(--ink-2);border-color:var(--line-2)}

/* ─── El tablero ────────────────────────────────────────────────────
   Los semáforos. El color NUNCA va solo: cada uno lleva su palabra y
   su signo —⚠ o ✓—, porque el rojo y el verde de esta plataforma son
   el mismo color para quien no los distingue (regla 192). El tono
   «sin» es para cuando la ficha no fijó el umbral: ni bien ni mal,
   sino que no hay contra qué juzgar, y eso también se dice. */
.focos{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.foco{font:600 11.5px var(--body);border-radius:999px;padding:3px 10px;
      white-space:nowrap;border:1px solid transparent;cursor:help}
.foco.ok{background:var(--ok-soft);color:var(--ok);border-color:var(--ok)}
.foco.mal{background:var(--bad-soft);color:var(--bad);border-color:var(--bad)}
.foco.sin{background:var(--sunk);color:var(--ink-3);border-color:var(--line-2)}
/* En la cabecera de una obra los tres van más grandes: ahí son el
   titular de la pantalla, no una celda de tabla. */
.focos.grande{margin:0 0 18px}
.focos.grande .foco{font-size:13px;padding:5px 14px}

/* Las cuatro cajas de ámbito. Son «.caja» de la rejilla con sus datos
   apilados; el pie dice en qué pantalla está el detalle, para que el
   tablero no pretenda ser el sitio donde se trabaja. */
.caja.ambito{display:flex;flex-direction:column;gap:12px}
.caja.ambito h3{margin:0;color:var(--navy)}
.caja.ambito .dato{margin:0}
.caja.ambito .pie-ambito{margin:auto 0 0;padding-top:8px;
  border-top:1px solid var(--line);font-size:11.5px;color:var(--ink-3)}
/* Dos por dos, no tres y una suelta: son cuatro ámbitos y se leen como
   cuatro, no como «los tres de arriba y el otro». En un teléfono caen a
   una columna solas. */
/* El «min(...,100%)» no es adorno: un mínimo de 400 px en una pantalla
   de 390 no cede, y la página entera se desplazaba 26 px de lado. Lo
   cazó revisa_tablero.js a 390 px. */
.rejilla.ambitos{grid-template-columns:repeat(auto-fit,minmax(min(400px,100%),1fr))}

/* Lo que está abierto. Cada renglón dice en qué pantalla se atiende:
   una lista de pendientes sin la puerta al lado es una queja. */
ul.abierto{margin:0;padding:12px 16px 12px 32px;display:grid;gap:8px;
  font-size:13.5px;color:var(--ink-2)}
ul.abierto li{padding-left:2px}
/* El nombre de la obra en la cartera SÍ se parte en varias líneas. Iba
   con «.cuenta», que es «nowrap» porque está hecha para cuentas cortas:
   un nombre de obra largo pedía su columna en una sola línea y la tabla
   se desbordaba 8 px. Lo cazó revisa_ancho.js. */
.obra-nombre{font:400 11.5px var(--body);color:var(--ink-3)}
/* La oferta que no cotizó todo lo dice en su propia celda de totales.
   Su número es más bajo que el de las demás y no por ser más barata,
   sino por estar incompleta: puesto al lado de los otros sin decirlo,
   el cuadro comparativo invita justo a la conclusión equivocada. */
table.cuadro .incompleta{display:block;font:600 10px var(--body);
  text-transform:uppercase;letter-spacing:.04em;color:var(--warn);
  white-space:normal;margin-top:2px;cursor:help}
/* ─── Renglones que un oferente juntó en uno ─────────────────────────
   «No cotizó» y «su precio viene dentro de otro renglón» se parecen en
   la pantalla —las dos celdas están sin número— y son cosas opuestas:
   la primera es una oferta incompleta y la segunda una oferta completa
   escrita de otra manera. Por eso la anotada se ve distinta, dice de
   dónde sale al pasar el ratón, y no se puede confundir con un hueco. */
table.cuadro td.agrupada{background:var(--auto)}
table.cuadro .viene-en{font:600 11px var(--body);color:var(--auto-ink);
  letter-spacing:.02em;cursor:help}
table.cuadro .lleva-dentro{display:block;font:600 10px var(--body);
  text-transform:uppercase;letter-spacing:.04em;color:var(--auto-ink);
  white-space:normal;margin-top:2px;cursor:help}
/* Una oferta que juntó renglones NO está incompleta: cubre todo. Se
   dice en ámbar suave para que se note, no en rojo para que no asuste. */
table.cuadro .agrupo{display:block;font:600 10px var(--body);
  text-transform:uppercase;letter-spacing:.04em;color:var(--auto-ink);
  white-space:normal;margin-top:2px;cursor:help}
/* Los dos botoncitos de la celda: pequeños, y solo mientras la
   licitación siga abierta. */
table.cuadro .marca-agrup,table.cuadro .quitar-agrup{
  display:block;margin:3px 0 0 auto;font:600 10px var(--body);padding:1px 5px}
/* ─── Cantidades que no coinciden ────────────────────────────────────
   Cada oferente hace su propia cuantificación y lo que obliga son los
   planos, no la cantidad: el total es a suma alzada contra ellos. Así
   que la cantidad es información de CADA oferta, no una columna
   compartida —antes esa columna enseñaba la del primero que se leyera,
   como si fuera la de todos—. Cuando difieren, la columna da el rango
   y cada celda lleva la suya. */
table.cuadro .rango{font-variant-numeric:tabular-nums;color:var(--ink-3);cursor:help}
table.cuadro .su-cant{display:block;font:400 10.5px var(--mono);
  color:var(--ink-3);margin-top:1px;cursor:help}
/* Separarse mucho del grupo no descalifica —el precio sigue siendo por
   lo que digan los planos— pero abre una pregunta que se contesta mejor
   antes de adjudicar que en obra. */
table.cuadro .su-cant.lejos{color:var(--warn);font-weight:600}
table.cuadro .cuantifica{display:block;font:600 10px var(--body);
  text-transform:uppercase;letter-spacing:.04em;color:var(--warn);
  white-space:normal;margin-top:2px;cursor:help}
/* ─── Precios unitarios ──────────────────────────────────────────────
   En este cuadro el número grande es el UNITARIO —lo que se contrata—
   y debajo va el extendido con la cantidad del cuadro. Son dos cifras
   distintas y tienen que verse distintas: confundirlas es comparar un
   precio por metro con un total. */
table.cuadro .extendido{display:block;font:400 10.5px var(--mono);
  color:var(--ink-3);margin-top:1px;cursor:help}
table.cuadro .extendido-pie{display:block;font:600 9.5px var(--body);
  text-transform:uppercase;letter-spacing:.04em;color:var(--ink-3);margin-top:2px;cursor:help}
/* Una cantidad fijada por PUCOM no es lo mismo que una que vino en las
   bases ni que una en la que todos coincidieron: se marca. */
table.cuadro .cant-fijada{border-bottom:1px dashed var(--line-2);cursor:help}
/* Y un renglón sin cantidad común no se puede comparar. No se disimula
   con un número cualquiera: se dice, y se ofrece arreglarlo. */
table.cuadro .sin-cant{font:600 10.5px var(--body);text-transform:uppercase;
  letter-spacing:.03em;color:var(--bad);cursor:help}
table.cuadro .fija-cant{display:block;margin:3px 0 0 auto;
  font:600 10px var(--body);padding:1px 5px}

/* ════════════════════════════════════════════════════════════════════
   LAS GRÁFICAS

   Lo fino es la regla y lo grueso la excepción: la única cosa con
   permiso de llamar la atención es la línea de datos. La rejilla y los
   ejes tienen que verse MENOS que ella, o el dibujo se convierte en un
   enrejado con datos dentro.
   ════════════════════════════════════════════════════════════════════ */

.gr-caja{background:var(--paper);border:1px solid var(--line);border-radius:10px;
  padding:14px 16px 10px;margin:12px 0}
.gr-caja>h3{font-family:var(--sub);font-size:.95rem;margin:0 0 2px;color:var(--ink)}
.gr-caja>.explica{margin:0 0 10px}

/* El lienzo crece a lo ancho y guarda su proporción. El alto del
   viewBox YA incluye la banda de las fechas: una caja de alto fijo que
   solo da sitio al dibujo deja las fechas fuera y aparece una barra de
   desplazamiento diminuta dentro de la tarjeta. */
svg.gr{width:100%;height:auto;display:block;overflow:visible}

.gr-rejilla{stroke:var(--line);stroke-width:1;shape-rendering:crispEdges}
.gr-eje{fill:var(--ink-3);font-family:var(--body);font-size:11px;
  font-variant-numeric:tabular-nums}
/* Los rótulos que caen ENCIMA del dibujo llevan un halo del color del
   fondo. Sin él, el nombre de la raya del 100 % se montaba sobre la
   línea azul y no se leía ninguno de los dos; moverlo de sitio solo
   cambia sobre qué línea cae, porque el sitio libre depende de los
   datos y los datos cambian cada mes. El halo funciona caiga donde
   caiga. */
.gr-rotulo{fill:var(--ink-2);font-family:var(--body);font-size:12px;font-weight:600;
  paint-order:stroke fill;stroke:var(--paper);stroke-width:3.5;stroke-linejoin:round}

.gr-linea{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.gr-lleno{stroke:none;opacity:.10}
.gr-punto{stroke:var(--paper);stroke-width:2}
.gr-barra{stroke:none}

/* Los dos colores de serie, y la referencia.

   La referencia NO es una serie: es el techo —el presupuesto, lo que
   tocaba llevar— contra el que se miran las demás. Por eso es gris y a
   rayas, y por eso no gasta un color de identidad. */
.gr-s1{stroke:var(--serie-1)}  .gr-s1.gr-lleno,.gr-s1.gr-punto,.gr-s1.gr-barra{fill:var(--serie-1)}
.gr-s2{stroke:var(--serie-2)}  .gr-s2.gr-lleno,.gr-s2.gr-punto,.gr-s2.gr-barra{fill:var(--serie-2)}
.gr-ref{stroke:var(--ink-3);stroke-dasharray:5 4}
.gr-ref.gr-punto{fill:var(--ink-3);stroke-dasharray:none}
.gr-ref.gr-lleno{fill:var(--ink-3)}

/* Cuando una barra SIGNIFICA bien o mal —un reporte a tiempo, un
   pendiente que se cerró— lleva el color de bien o de mal. Es la única
   vez que estos tres colores entran en una gráfica, y nunca como
   identidad: una línea verde que solo quisiera decir «pagado» haría
   que una obra pareciera sana por el color de su línea. */
.gr-bien.gr-barra{fill:var(--ok)}
.gr-aviso.gr-barra{fill:var(--warn)}
.gr-mal.gr-barra{fill:var(--bad)}

.gr-cruz{stroke:var(--line-2);stroke-width:1;opacity:0}
.gr-toca:hover .gr-cruz,.gr-toca:focus-within .gr-cruz{opacity:1}
.gr-toca{cursor:crosshair}

.gr-mini{width:76px;height:22px;display:block;margin-top:4px;overflow:visible}

.gr-leyenda{display:flex;flex-wrap:wrap;gap:4px 16px;margin:0 0 8px}
.gr-clave{display:inline-flex;align-items:center;gap:7px;font-size:.78rem;color:var(--ink-2)}
.gr-muestra{width:14px;height:3px;border-radius:2px;flex:none}
.gr-muestra.gr-s1{background:var(--serie-1)}
.gr-muestra.gr-s2{background:var(--serie-2)}
.gr-muestra.gr-ref{background:repeating-linear-gradient(90deg,var(--ink-3) 0 5px,transparent 5px 9px)}
.gr-muestra.gr-bien{background:var(--ok);height:10px;border-radius:2px;width:10px}
.gr-muestra.gr-aviso{background:var(--warn);height:10px;border-radius:2px;width:10px}
.gr-muestra.gr-mal{background:var(--bad);height:10px;border-radius:2px;width:10px}

.gr-nota{font-size:.78rem;color:var(--ink-3);margin:8px 0 0;line-height:1.45}
.gr-vacia{font-size:.85rem;color:var(--ink-3);margin:18px 0;text-align:center;line-height:1.5}

/* La tabla de toda gráfica, plegada. Que esté plegada no la hace
   opcional: es el sitio donde el número está escrito, para quien no
   distingue los dos tonos, para quien imprime en blanco y negro y para
   quien lo necesita exacto. */
.gr-tabla{margin-top:10px;border-top:1px solid var(--line);padding-top:6px}
.gr-tabla>summary{font-size:.78rem;color:var(--ink-3);cursor:pointer;padding:2px 0}
.gr-tabla>summary:hover{color:var(--ink-2)}
.gr-tabla table{margin-top:8px}

/* La flecha de «mejoró o empeoró». Lleva el símbolo Y la palabra: el
   color solo no dice nada a quien no lo distingue, y una flecha hacia
   arriba no significa «bien» por sí sola. */
.gr-flecha{display:inline-flex;align-items:center;gap:4px;font-size:.76rem;
  font-weight:600;white-space:nowrap}
.gr-mejor{color:var(--ok)} .gr-peor{color:var(--bad)}
.gr-neutra{color:var(--ink-3)} .gr-igual{color:var(--ink-3);font-weight:400}

/* La cifra con tendencia: el número, lo que se movió, y la forma que
   traía. Más ancha que una cifra normal porque lleva tres cosas más, y
   a 390 px pasa a una sola columna — cuatro tarjetas de 150 px en un
   teléfono salen con el número partido en dos renglones. */
.cifras.cartera{grid-template-columns:repeat(auto-fit,minmax(min(230px,100%),1fr))}
.cifra.tend{display:flex;flex-direction:column;gap:2px}
.cifra.tend .gr-flecha{margin-top:2px}
.cifra.tend .gr-mini{margin-top:auto;padding-top:6px}

/* La raya de la referencia —el 100 % de lo programado— con su nombre.
   No es rejilla: es el número contra el que se mira todo lo demás, y
   por eso se ve un poco más que las otras y lleva rótulo. */
.gr-marca{stroke:var(--ink-3);stroke-width:1;stroke-dasharray:2 3;opacity:.75}
.gr-marca-rotulo{fill:var(--ink-3);font-size:10px;letter-spacing:.04em;
  paint-order:stroke fill;stroke:var(--paper);stroke-width:3;stroke-linejoin:round}

/* ─── Prosa chica ────────────────────────────────────────────────── */
/*
   «.metadoc» NO es un estilo de texto: es una REJILLA de etiquetas y
   valores, con su borde y su fondo. Usada en un párrafo, convierte una
   frase explicativa en una banda gris con marco — que es lo que estaba
   pasando debajo del título de cada gráfica y en la cabecera de cada
   respuesta.
   Es la tercera vez que una clase de esta hoja se usa por su nombre y
   no por lo que hace: ya pasó con «.cuenta» (que es nowrap) y con
   «.mini» (que es un botón). Esto es lo que faltaba: una clase para
   texto chico, que solo hace eso. */
.explica{font-size:.82rem;color:var(--ink-3);line-height:1.5;margin:0 0 10px}
.explica b{color:var(--ink-2);font-weight:600}
/* La misma letra, pero en línea: para la coletilla de una cabecera. */
.dicho{font-size:.78rem;color:var(--ink-3)}

/* ─── Solicitudes de información ─────────────────────────────────── */

/* Una pregunta y una respuesta son párrafos de verdad, no celdas: se
   leen enteros y llevan los saltos de línea que traían. */
.texto-largo{white-space:pre-wrap;line-height:1.55;margin:4px 0 12px;color:var(--ink)}

.respuesta{border-top:1px solid var(--line);padding:12px 0}
.respuesta:first-child{border-top:0;padding-top:2px}
.respuesta-cab{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;margin-bottom:4px}
.respuesta-cab .metadoc{margin:0}
/* La oficial se ve distinta porque es la que vale: lleva una barra a la
   izquierda, no solo un color de texto — el color solo no lo distingue
   quien no lo distingue (regla 192). */
.respuesta.oficial{border-left:3px solid var(--slate);padding-left:12px;
  background:var(--slate-soft);border-radius:0 8px 8px 0}

/* ── Lo mío ─────────────────────────────────────────────────────────
   En un teléfono la columna «Desde» parte cada fecha en tres renglones
   y le roba el ancho a lo único que hay que leer: de qué se trata y
   para cuándo. Se esconde — el dato sigue en la minuta y en la ficha,
   que es a donde lleva el renglón. */
.lomio .des{white-space:nowrap}
@media (max-width:620px){
  .lomio th:nth-child(4), .lomio td:nth-child(4){display:none}
}

/* ── Los adjuntos de una solicitud ──────────────────────────────────
   Una lista de archivos, no una galería: un PDF no tiene miniatura que
   valga la pena y el nombre del archivo es lo que la gente reconoce.
   El nombre es un botón porque la dirección se pide firmada en el
   momento del clic y dura quince minutos; si fuera un <a href> habría
   que pedir las direcciones de todos los archivos por adelantado, y
   quedarían escritas en la pantalla hasta que caducaran. */
.adjuntos{list-style:none;margin:10px 0 0;padding:0;display:flex;
  flex-direction:column;gap:5px}
.adjuntos li{display:flex;flex-wrap:wrap;align-items:center;gap:4px 9px;
  font-size:.88rem}
.adjuntos .enlace{font:inherit;background:none;border:0;padding:0;
  color:var(--navy);text-decoration:underline;text-underline-offset:2px;
  cursor:pointer;text-align:left}
.adjuntos .enlace:hover{color:var(--ink)}
/* El campo de archivo va escondido dentro de su rótulo: el rótulo es lo
   que se ve y se pulsa, y por eso tiene que verse como un botón. */
/* Es un <label>, y los rótulos de los formularios van en mayúsculas y
   espaciados. Este no es un rótulo: es un botón, y tiene que leerse
   como los de al lado. */
.adjuntar{display:inline-flex;align-items:center;margin-top:9px;
  width:max-content;text-transform:none;letter-spacing:normal;
  font-size:12.5px;font-weight:600;color:var(--ink-2)}

/* Una casilla con su texto al lado, que se lee como una frase. */
.caja-check{display:inline-flex;align-items:center;gap:8px;font-size:.85rem;
  color:var(--ink-2);text-transform:none;letter-spacing:normal;font-weight:400}
.caja-check input{width:auto;margin:0}
/* Dentro de la fila de filtros, la casilla se alinea con los
   desplegables —que llevan su rótulo encima— y no con el borde de
   abajo, que la dejaba flotando a media altura. */
.filtros .caja-check{font-size:13.5px;padding:7px 0}

/* La fila de una solicitud vencida. Tinte muy leve: la fila sigue
   siendo legible, y el dato que manda es el número de días, no el
   color. */
tr.fila-mala>td{background:var(--bad-soft)}

/* ════════════════════════════════════════════════════════════════════
   LA PANTALLA DE ENTRADA · tres columnas

   Todo va encerrado en `.entrada` a propósito. La aplicación ya tiene
   `.caja`, `.vacio`, `.chip` y `.cuenta` con otro significado, y cinco
   nombres repetidos en una hoja de 1.500 líneas es una colisión
   esperando a que alguien toque la de al lado. El semáforo se llama
   `.luz` y no `.punto` porque `.punto` ya es, aquí, la tarjeta de un
   punto de minuta — ese choque sí era de significado, no de estilo.
   ════════════════════════════════════════════════════════════════════ */

.entrada .hola{display:flex;gap:12px;align-items:baseline;flex-wrap:wrap;margin-bottom:4px}
.entrada .hola h1{font-size:25px;margin:0}
.entrada .hola .fecha{font:400 12.5px var(--sub);color:var(--ink-3)}

/* LA PRIMERA FRASE. Un tablero que enseña treinta cosas sin decir cuál
   es la primera deja la decisión más cara en manos de quien tenga menos
   tiempo. */
.entrada .primero{display:flex;gap:10px;align-items:flex-start;background:var(--bad-soft);
  border-left:4px solid var(--bad);border-radius:0 8px 8px 0;padding:10px 14px;margin:10px 0 20px}
.entrada .primero .et{font:700 10.5px var(--sub);letter-spacing:.1em;color:var(--bad);
  text-transform:uppercase;padding-top:2px;white-space:nowrap}
.entrada .primero p{margin:0;font-size:14px;color:var(--ink)}

.entrada .tres{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.08fr) minmax(0,1.3fr);
  gap:16px;align-items:start}
@media (max-width:1080px){.entrada .tres{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .entrada .col-3{grid-column:1/-1}}
@media (max-width:720px){.entrada .tres{grid-template-columns:minmax(0,1fr)}}
.entrada .col{display:flex;flex-direction:column;gap:12px;min-width:0}
.entrada .colcab{display:flex;align-items:baseline;gap:8px;padding:0 2px}
.entrada .colcab h2{font:700 13px var(--sub);letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-2);margin:0}
.entrada .colcab .cuenta{font-family:var(--mono);font-size:12px;color:var(--ink-3)}
.entrada .colcab .pista{font:400 11.5px var(--sub);color:var(--ink-3);margin-left:auto}

.entrada .caja{background:var(--paper);border:1px solid var(--line);border-radius:10px;
  overflow:hidden;padding:0}
.entrada .caja-cab{padding:9px 13px;border-bottom:1px solid var(--line);display:flex;
  align-items:center;gap:8px}
.entrada .caja-cab h3{font:700 12px var(--sub);letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-2);margin:0}
.entrada .caja-cab .n{margin-left:auto;font-family:var(--mono);font-size:12px;color:var(--ink-3)}

/* LA COLUMNA DE OBRA DE «LO MÍO» lleva el código y el nombre, uno
   encima del otro. Sin un ancho mínimo, «Centro Logístico Vista Clara»
   se parte en tres líneas y cada renglón de la tabla crece al triple.
   El ancho va en una clase propia y no en `nth-child`, porque con una
   obra escogida esta columna desaparece y el `nth-child` se lo
   aplicaría a la de al lado. */
table.lomio .obracol{min-width:152px}
table.lomio .obracol .dicho{display:inline-block;line-height:1.25;margin-top:1px}

/* EL SELECTOR DE AGRUPADO. Va pegado arriba de la lista que gobierna y
   no en la cabecera de la columna, para que no quede duda de cuál de
   las dos listas cambia. */
.entrada .agrupasel{display:flex;align-items:center;gap:6px;padding:7px 13px;
  border-bottom:1px solid var(--line);background:var(--sunk)}
.entrada .agrupasel .et{font:400 11px var(--sub);color:var(--ink-3);margin-right:auto}
.entrada .agrupasel button{font:600 11px var(--sub);letter-spacing:.02em;cursor:pointer;
  padding:3px 10px;border-radius:999px;border:1px solid var(--line);
  background:var(--paper);color:var(--ink-3)}
.entrada .agrupasel button:hover{color:var(--ink);border-color:var(--ink-3)}
.entrada .agrupasel button[aria-pressed="true"]{background:var(--navy);color:#fff;
  border-color:var(--navy)}

/* UN GRUPO. La cabecera dice UNA VEZ lo que todos los renglones de
   abajo comparten —la obra, o la persona— y lleva la cuenta de cuántos
   trae, incluidos los que no se alcanzan a dibujar. */
.entrada .grupo{border-bottom:1px solid var(--line)}
.entrada .grupo:last-child{border-bottom:0}
.entrada .grupo-cab{display:flex;align-items:center;gap:7px;padding:7px 13px;
  background:var(--sunk)}
.entrada .grupo-cab .gnom{font:600 12.5px var(--sub);color:var(--ink-2);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.entrada .grupo-cab .gn{margin-left:auto;font:500 11px var(--mono);color:var(--ink-3);
  background:var(--paper);border:1px solid var(--line);border-radius:999px;padding:0 7px}
.entrada .grupo .item:last-child{border-bottom:0}
.entrada .grupo-mas{padding:6px 13px;font:400 11px var(--sub);color:var(--ink-3);
  border-top:1px solid var(--line)}

/* UN RENGLÓN DE PENDIENTE, el mismo en las dos columnas. La raya de la
   izquierda lleva la gravedad, para que se vea sin leer. */
.entrada .item{display:block;text-decoration:none;color:inherit;padding:10px 13px 11px;
  border-bottom:1px solid var(--line);border-left:3px solid transparent}
.entrada .item:last-child{border-bottom:0}
.entrada .item:hover{background:var(--sunk)}
.entrada .item.rojo{border-left-color:var(--bad)}
.entrada .item.ambar{border-left-color:var(--warn)}
.entrada .item-top{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-bottom:3px}
.entrada .cod{font:500 11px var(--mono);background:var(--sunk);border:1px solid var(--line);
  color:var(--ink-2);padding:1px 6px;border-radius:4px;letter-spacing:0}
.entrada .obranom{font:400 11.5px var(--sub);color:var(--ink-3);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.entrada .chip{font:700 10px var(--sub);letter-spacing:.06em;text-transform:uppercase;
  padding:2px 6px;border-radius:4px;white-space:nowrap;display:inline-block}
.entrada .chip.rojo{background:var(--bad-soft);color:var(--bad)}
.entrada .chip.ambar{background:var(--warn-soft);color:var(--warn)}
.entrada .chip.gris{background:var(--sunk);color:var(--ink-3)}
.entrada .item .tit{font:500 13.5px var(--body);line-height:1.35;color:var(--ink)}
.entrada .item .pie{font-size:11.5px;color:var(--ink-3);margin-top:3px}
.entrada .item .pie .quien{color:var(--ink-2)}
.entrada .item .nota{font-size:11.5px;color:var(--ink-3);margin-top:4px;font-style:italic;
  border-left:2px solid var(--line);padding-left:7px}
.entrada .plata-firma{display:flex;align-items:baseline;gap:8px;margin-top:4px;flex-wrap:wrap}
.entrada .plata-firma .v{font:500 16px var(--mono);color:var(--ink)}
.entrada .plata-firma .et{font:400 10.5px var(--mono);color:var(--ink-3)}
/* El estado vacío NO es un error: es una buena noticia, y además
   enseña qué va a aparecer ahí cuando haya algo. */
.entrada .vacio{padding:16px 13px;display:flex;gap:9px;align-items:flex-start;
  background:transparent;border:0;text-align:left}
.entrada .vacio .tic{color:var(--ok);font-size:16px;line-height:1.1}
.entrada .vacio p{margin:0;font-size:12.5px;color:var(--ink-3)}
.entrada .vacio b{color:var(--ink-2)}
.entrada .mas{display:block;text-align:center;padding:8px;font:400 12px var(--sub);
  color:var(--blue);text-decoration:none;background:var(--sunk)}

/* ─── La tarjeta de obra: dos líneas, y se amplía ─── */
.entrada .obra{background:var(--paper);border:1px solid var(--line);border-radius:10px;
  overflow:hidden;margin-bottom:12px}
.entrada .obra.urgente{border-color:var(--bad);box-shadow:0 0 0 1px var(--bad) inset}
.entrada .obra-cab{display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  background:transparent;border:0;padding:11px 13px 9px;cursor:pointer;font:inherit;color:inherit}
.entrada .obra-cab:hover{background:var(--sunk)}
.entrada .obra-cab .cod{font-size:12.5px;font-weight:700;background:var(--navy);
  color:var(--paper);border-color:var(--navy)}
.entrada .obra-cab .nom{font:600 14px var(--sub);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.entrada .marcador{margin-left:auto;font:400 11px var(--sub);color:var(--ink-3);white-space:nowrap}
.entrada .marcador b{font-family:var(--mono);font-size:12.5px}
.entrada .marcador .rj{color:var(--bad)}
.entrada .marcador .vd{color:var(--ok)}
.entrada .flecha-abre{color:var(--ink-3);font-size:11px;transition:transform .15s}
.entrada .obra-cab[aria-expanded="true"] .flecha-abre{transform:rotate(180deg)}
@media (prefers-reduced-motion:reduce){.entrada .flecha-abre{transition:none}}

.entrada .luces{display:grid;grid-template-columns:repeat(8,1fr);gap:2px;padding:0 10px 9px}
@media (max-width:560px){.entrada .luces{grid-template-columns:repeat(4,1fr);gap:6px 2px}}
.entrada .ind{display:flex;flex-direction:column;align-items:center;gap:3px;min-width:0}
.entrada .luz{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  font:700 12px var(--sub);color:#fff}
.entrada .luz.v{background:var(--ok)}
.entrada .luz.r{background:var(--bad)}
/* EL GRIS NO ES UN COLOR MÁS: es «nadie miró». Va hueco a propósito,
   para que no se lea como un estado tranquilo. */
.entrada .luz.g{background:transparent;border:1.5px dashed var(--line-2);color:var(--ink-3)}
.entrada .iet{font:500 9.5px var(--sub);color:var(--ink-3);text-align:center;overflow:hidden;
  text-overflow:ellipsis;max-width:100%;white-space:nowrap}
.entrada .resumen{margin:0;padding:0 13px 12px;font-size:12px;color:var(--ink-2);line-height:1.4}
.entrada .detalle{border-top:1px solid var(--line);padding:12px 14px 10px;background:var(--sunk)}
.entrada .fila{border-top:1px solid var(--line);padding-top:10px;margin-bottom:10px}
.entrada .fila:first-child{border-top:0;padding-top:0}
.entrada .rot{font:700 10px var(--sub);letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:5px}
.entrada .minutas{display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap}
.entrada .mbal b{font:700 13px var(--sub);display:block;line-height:1.2}
.entrada .mbal span{font-size:10.5px;color:var(--ink-3)}
.entrada .mbal.mal b{color:var(--bad)}
.entrada .mbal.bien b{color:var(--ok)}
.entrada .mbal.neutro b{color:var(--ink-3)}
.entrada .oc-dicho{font-size:11.5px;color:var(--ink-3);line-height:1.5}
/* Lo que todavía no existe se enseña como hueco, no se esconde: así el
   tablero recuerda solo dónde falta trabajo. */
.entrada .hueco-kpi{border:1px dashed var(--line-2);background:var(--note);border-radius:7px;
  padding:7px 10px;margin-top:8px}
.entrada .hueco-kpi .et{font:700 10px var(--sub);letter-spacing:.08em;text-transform:uppercase;
  color:var(--note-ink)}
.entrada .hueco-kpi p{margin:2px 0 0;font-size:11.5px;color:var(--ink-2)}
.entrada .pie-obra{display:flex;gap:6px;flex-wrap:wrap;align-items:center;
  border-top:1px solid var(--line);padding-top:9px}
.entrada .pie-obra .entrar{margin-left:auto;font:600 12px var(--sub);color:var(--blue);
  text-decoration:none;white-space:nowrap}

/* El tablero de entrada es la única pantalla de tres columnas en
   paralelo; a 1.100 px cada una queda en 340 y las etiquetas de los
   semáforos se parten. Las demás se quedan como están: una línea de
   texto más ancha que 1.100 px se lee peor, no mejor. */
main.ancho{max-width:1420px}
