*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
.hidden { display: none !important; }

:root {
  --bg: #f5f6f8;
  --surface: #fff;
  --border: #e0e3e8;
  --text: #1a1d23;
  --text-muted: #6b7280;
  --accent: #3b82f6;
  --green: #16a34a;
  --red: #dc2626;
  --orange: #d97706;
  --blue: #2563eb;

  /* Color de MARCA (§12-bis): único punto de recoloreo entre Opi y contabilidad.
     Contabilidad lo tiene en ladrillo (var(--brand)); Opi en teal.

     ⚠️ §33A · EL TEAL ES EL ACENTO DE OPI, no sólo el nav y el botón primario.
     Hasta acá `--accent` (azul, herencia de contabilidad) pintaba 58 usos y
     `--brand` sólo 7: el azul genérico se veía NUEVE VECES MÁS que el color de
     la marca, y un texto en #3b82f6 sin subrayado se lee como un link de
     navegador sin estilar. Los 47 usos de identidad/acción pasaron a teal.

     LA REGLA, y no es estética — es CONTRASTE MEDIDO sobre blanco:
       · `color:` (el texto ES el color)      → var(--brand-strong)  5,47 ✅
       · background / border / box-shadow     → var(--brand)         (lleva
                                                 texto blanco encima)
     `--brand` como TEXTO da 3,74, tan ilegible como el azul que reemplaza
     (3,68), los dos por debajo del mínimo 4,5 de WCAG. Aplicarlo sin partir en
     dos tokens habría cambiado el color sin arreglar nada.

     LO QUE SIGUE EN AZUL, a propósito:
       · los anillos de `:focus` (11 usos) — es una affordance de accesibilidad
         estandarizada, no identidad, y acá sí vale «que se vea igual que en
         contabilidad»;
       · los badges semánticos (#dbeafe/#1d4ed8) y `--blue` — ahí el azul
         SIGNIFICA algo (manual, transferencia, oficial), no decora;
       · `.aviso-fuera` — es informativo: un aviso en teal se confunde con un
         elemento activo. */
  --brand: #0d9488;
  --brand-strong: #0f766e;
}

html, body { height: 100%; overflow: hidden; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
       font-size: 14px; color: var(--text); background: var(--bg); }

/* Header */
.header { display: flex; align-items: center; justify-content: space-between;
          padding: 0 20px; height: 52px; background: #1a1d23;
          border-bottom: none; position: sticky; top: 0; z-index: 100; }
.app-logo { color: #fff; font-size: 15px; font-weight: 700; }
.header-logo-wrap { display: flex; flex-direction: column; line-height: 1.2; }
.header-perfil-sub { color: #9ca3af; font-size: 11px; }

.nav { display: flex; gap: 2px; align-items: center; }
.nav-link { padding: 6px 9px; border-radius: 6px; text-decoration: none;
            color: #9ca3af; transition: background .15s; font-size: 13px; white-space: nowrap; }
.nav-link:hover { background: rgba(255,255,255,0.08); color: #fff; }
.nav-link.active { background: var(--brand); color: #fff; }
/* Separador visual entre grupos del nav (motor | estudio | config) */
.nav-link.nav-sep { margin-left: 7px; border-left: 1px solid #3d4149; padding-left: 12px; }

.selector-group { display: flex; gap: 8px; align-items: center; }

/* Perfil switcher — botones directos */
.perfil-btn { padding: 5px 12px; border-radius: 6px; text-decoration: none;
              font-size: 13px; color: var(--text-muted); border: 1px solid transparent;
              transition: all .15s; white-space: nowrap; }
.perfil-btn:hover { background: var(--bg); color: var(--text); }
.perfil-btn.active { background: var(--brand); color: #fff; border-color: var(--brand); font-weight: 600; }

/* Año — select nativo, clic directo */
.año-select { padding: 5px 10px; border: 1px solid var(--border); border-radius: 6px;
              background: var(--bg); font-size: 13px; cursor: pointer; }
.año-select:focus { outline: 2px solid var(--accent); }

/* §25.1 · Selector de MES (el período global), al lado del de año. Más ancho
   porque sus opciones son palabras («Septiembre», «Todo 2026») y no cuatro
   dígitos: con el ancho del de año, «Todo 2026» se recorta y el operador no
   puede leer en qué período está parado. */
.mes-select { padding: 5px 10px; border: 1px solid var(--border); border-radius: 6px;
              background: var(--bg); font-size: 13px; cursor: pointer; min-width: 118px; }
.mes-select:focus { outline: 2px solid var(--accent); }

/* Selects dentro del header sobre fondo oscuro */
header select { background: #2d3139; color: #fff; border: 1px solid #3d4149;
                border-radius: 6px; padding: 4px 10px; font-size: 13px; }
header .año-select { background: #2d3139; color: #fff; border: 1px solid #3d4149; }
header .mes-select { background: #2d3139; color: #fff; border: 1px solid #3d4149; }

/* Botón Nueva entrada */
.btn-nuevo { display: inline-flex; align-items: center; gap: 6px; padding: 7px 16px;
             background: var(--brand); color: #fff; border: none; border-radius: 6px;
             cursor: pointer; font-size: 13px; font-weight: 600; text-decoration: none; }
.btn-nuevo:hover { background: var(--brand-strong); color: #fff; }

/* §65.6.e · Exportar. SECUNDARIO por diseño: contorno y no relleno, para que no
   compita con el `.btn-nuevo` que está al lado — dos botones del color de marca
   en el mismo renglón se leen como dos acciones igual de importantes, y no lo
   son (una se usa cincuenta veces por sesión y la otra una).
   `flex: 0 0 auto` porque `.movs-cabecera` es `nowrap`: sin eso el botón se
   encoge antes que los chips y «Exportar» se parte en dos renglones. El que
   absorbe el ancho es `.chips-bar`, que para eso tiene `flex: 1 1 auto` con
   `min-width: 0` y su propio scroll. */
.btn-export { display: inline-flex; align-items: center; gap: 6px;
              padding: 7px 14px; background: var(--surface);
              color: var(--text-muted); border: 1px solid var(--border);
              border-radius: 6px; font-size: 13px; font-weight: 600;
              text-decoration: none; flex: 0 0 auto; white-space: nowrap; }
.btn-export:hover { border-color: var(--brand); color: var(--brand); }

/* Modal alta manual */
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 200;
                 display: flex; align-items: center; justify-content: center; }
.modal-overlay.hidden { display: none; }
/* §38 [a] · ⚠️ EL `max-height` VA ACÁ, EN EL CANON, Y NO EN CADA MODAL.
   El de Proyectos mide 618px y NO scrolleaba: `max-height:none`,
   `overflow:visible`. En un viewport de menos de ~620px el botón «Guardar»
   quedaba fuera del corte y era INALCANZABLE — no hay forma de llegar a él, ni
   con rueda ni con teclado, porque la app no scrollea la ventana
   (`html,body{overflow:hidden}`).
   Sólo `#modal-cli` y `#modal-vincular` lo tenían, cada uno con su propio
   override: dos parches puntuales sobre un problema que es de TODOS los modales
   —cualquiera que crezca lo suficiente lo tiene—, y que se descubre de a uno,
   en producción, cuando ya no se puede guardar. Puesto en `.modal-box` lo
   heredan los nueve, incluidos los que todavía no existen. */
.modal-box { background: #fff; border-radius: 12px; padding: 28px; width: 520px;
             max-width: 95vw; box-shadow: 0 8px 32px rgba(0,0,0,0.18);
             max-height: 92vh; overflow-y: auto; }
.modal-box h2 { font-size: 16px; font-weight: 700; margin-bottom: 20px; }
.modal-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.modal-grid .full { grid-column: 1 / -1; }
/* RONDA 2 · Media fila. Un `<input>` de texto largo —un nombre— no necesita
   las tres columnas, pero con una sola queda angosto: con dos llena su
   renglón junto a un campo corto y no deja el hueco que Dave marcó. */
.modal-grid .span2 { grid-column: span 2; }

/* ── RONDA 1 · EL MODAL ANCHO ────────────────────────────────────────────────
   Hallazgo de Dave: los modales de muchos campos quedaban angostos y ALTOS, con
   scroll, mientras sobraba pantalla a los costados. Son 520px sobre monitores de
   1366 y 1512: dos tercios del ancho sin usar, y a cambio el operador scrollea
   para llegar a «Guardar».

   La cura NO es subirle el `max-height` —eso deja el scroll donde está— sino
   darle COLUMNAS: con tres, los catorce campos de Proyecto entran en cinco
   renglones en vez de siete, y el modal deja de tocar el techo.

   ⚠️ SE APLICA POR CLASE Y NO AL CANON. `.modal-box` de 520px sigue siendo el
   default correcto para los modales de cuatro campos (Ítems, Familias): un modal
   de 900px para pedir un nombre se lee peor, no mejor. El ancho lo pide el que
   tiene los campos.

   ⚠️ Y BAJA A DOS Y A UNA COLUMNA por breakpoint. Sin esto, tres columnas de
   ~280px en un viewport de 900 dan campos de 90px donde no entra un importe.
   `width:auto` en el último tramo evita que 900px fijos desborden la pantalla. */
.modal-box.modal-ancho { width: 900px; }
.modal-ancho .modal-grid { grid-template-columns: 1fr 1fr 1fr; gap: 12px 18px; }

/* ⚠️⚠️ RONDA 2 · EL ANCHO NO ALCANZÓ: EL SCROLL SEGUÍA.
   La ronda 1 ensanchó a 900px y dio tres columnas, pero no tocó **una sola de
   las medidas verticales**: el modal seguía con 28px de padding, 20px bajo el
   título, 12px entre filas, 20px sobre los botones y campos de 7px+13px. A
   1080p de alto el viewport útil son ~940px y el modal de Proyecto medía ~1000.

   Lo que se compacta acá es TODO lo vertical, y en proporción — no un solo
   número grande, que es lo que deja una pantalla desbalanceada:
       padding      28 → 18px
       h2 margen    20 → 12px
       gap de filas 12 → 9px
       acciones     20 → 12px
       campos     7/13 → 5/12.5px
   Suman ~140px sobre un modal de catorce campos: entra sin scroll y sin que
   ningún control quede apretado contra otro.

   ⚠️ Y VA SOBRE `.modal-ancho`, NO SOBRE EL CANON: los modales de cuatro campos
   no tienen problema de altura, y apretarlos sería empeorarlos para arreglar
   algo que no les pasa. */
.modal-box.modal-ancho { padding: 18px 20px; }
.modal-ancho h2 { margin-bottom: 12px; }
.modal-ancho .modal-grid { gap: 9px 18px; }
.modal-ancho .modal-actions { margin-top: 12px; }
.modal-ancho .form-group { gap: 2px; }
.modal-ancho .form-group input,
.modal-ancho .form-group select,
.modal-ancho .form-group textarea { padding: 5px 9px; font-size: 12.5px; }
.modal-ancho .form-group label { font-size: 10px; }
/* Los `<small>` de ayuda debajo de un campo (la cuota en vivo, el «calculado =
   m²×valor») no ganan un renglón entero: se apoyan sobre el input. */
.modal-ancho .form-group small { font-size: 10px; line-height: 1.25; }
/* El separador de grupo, más fino. */
.modal-ancho .modal-grid .grupo-rot { padding-top: 7px; margin-top: 1px; }
/* Un separador con título dentro de la grilla: agrupa los campos que van juntos
   («Honorario fijo», «Honorario variable») sin sacarlos de la misma grilla. */
.modal-grid .grupo-rot { grid-column: 1 / -1; font-size: 11px; font-weight: 700;
    color: var(--brand-strong); text-transform: uppercase; letter-spacing: .04em;
    border-top: 1px solid #e5e7eb; padding-top: 10px; margin-top: 4px; }
.modal-grid .grupo-rot:first-child { border-top: none; padding-top: 0; margin-top: 0; }
/* El checkbox de «¿cobra?» ocupa su celda como un campo más, alineado con los
   de al lado y no colgado al pie del modal (que es donde estaba el del variable,
   a cinco campos de distancia del % con el que forma pareja). */
.form-group.chk-campo { justify-content: flex-end; }
.form-group.chk-campo label { display: flex; align-items: center; gap: 8px;
    text-transform: none; font-size: 13px; color: #374151; font-weight: 500;
    padding-bottom: 7px; }
.form-group.chk-campo input[type="checkbox"] { width: 16px; height: 16px;
    accent-color: var(--brand); }
@media (max-width: 1180px) {
  .modal-ancho .modal-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 760px) {
  .modal-box.modal-ancho { width: auto; }
  .modal-ancho .modal-grid { grid-template-columns: 1fr; }
}
.form-group { display: flex; flex-direction: column; gap: 4px; }
.form-group label { font-size: 11px; font-weight: 600; color: #6b7280; text-transform: uppercase; }
.form-group input, .form-group select, .form-group textarea {
  padding: 7px 10px; border: 1px solid #e0e3e8; border-radius: 6px; font-size: 13px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
.btn-cancel { padding: 7px 16px; background: #f3f4f6; border: none; border-radius: 6px;
              cursor: pointer; font-size: 13px; }

/* Importar — step flow */
.step-nav { display: flex; gap: 0; margin-bottom: 24px; }
.step-item { flex: 1; text-align: center; padding: 10px; background: var(--bg);
             border: 1px solid var(--border); font-size: 13px; color: var(--text-muted); }
.step-item:first-child { border-radius: 8px 0 0 8px; }
.step-item:last-child { border-radius: 0 8px 8px 0; }
.step-item.active { background: var(--brand); color: #fff; border-color: var(--brand); font-weight: 600; }
.step-item.done { background: #dcfce7; color: #15803d; border-color: #86efac; }

.dropzone { border: 2px dashed var(--border); border-radius: 10px; padding: 40px;
            text-align: center; color: var(--text-muted); cursor: pointer;
            transition: border-color .2s; }
.dropzone:hover, .dropzone.drag-over { border-color: var(--brand); color: var(--brand); }
.dropzone input[type=file] { display: none; }

.spinner { display: inline-block; width: 20px; height: 20px; border: 3px solid #e0e3e8;
           border-top-color: var(--brand); border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.preview-table { font-size: 12px; }
.preview-table select { font-size: 12px; padding: 2px 6px; border: 1px solid var(--border);
                        border-radius: 4px; background: var(--surface); max-width: 140px; }
.badge-src-ia { background: #dcfce7; color: #15803d; font-size: 10px; padding: 2px 6px;
                border-radius: 8px; font-weight: 600; }
.badge-src-regla { background: #dbeafe; color: #1d4ed8; font-size: 10px; padding: 2px 6px;
                   border-radius: 8px; font-weight: 600; }
.badge-src-manual { background: #f3f4f6; color: #6b7280; font-size: 10px; padding: 2px 6px;
                    border-radius: 8px; font-weight: 600; }

.page-header { display: flex; align-items: center; justify-content: space-between;
               margin-bottom: 16px; }

/* Sub-nav de los cuatro estados de cuenta.
   ⚠️ El rótulo decía «Resumen tabs» y quedó viejo: `.tab-bar`/`.tab-link` viven
   HOY sólo en `templates/estudio/_estados_macros.html`, en ninguna otra pantalla
   (§45 lo verificó por grep antes de tocarlos). Por eso se pueden ajustar sin
   colaterales — si algún día vuelven a otra pantalla, esto deja de ser cierto. */
.tab-bar { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 2px solid var(--border); }
/* §45 · 8px/14px -> 5px/13px: 35px -> 28px. Es una barra de navegación de cuatro
   palabras, no un bloque de lectura; el alto que tenía era aire. */
.tab-link { padding: 5px 16px; text-decoration: none; color: var(--text-muted); font-size: 13px;
            font-weight: 500; border-bottom: 2px solid transparent; margin-bottom: -2px; }
.tab-link:hover { color: var(--text); }
.tab-link.active { color: var(--brand-strong); border-bottom-color: var(--brand); font-weight: 600; }

/* Main — flex column con altura fija y scroll interno */
.main-content { height: calc(100vh - 52px); max-width: 1400px; margin: 0 auto;
                width: 100%; padding: 0; display: flex; flex-direction: column;
                overflow: hidden; }
.main-content > .flash { margin: 14px 24px 0; }

/* Wrapper estándar: contenido scrolleable de la página */
.page-scroll { flex: 1 1 auto; overflow-y: auto; padding: 20px 24px;
               min-height: 0; }

/* Wrapper especial /movimientos: filtros y stats fijos arriba, tabla scroll dentro */
.page-movs { flex: 1 1 auto; display: flex; flex-direction: column;
             padding: 20px 24px; min-height: 0; overflow: hidden; }
.page-movs > .table-wrapper { flex: 1 1 auto; overflow-y: auto;
                              min-height: 0; }

.page-header h1 { font-size: 20px; font-weight: 700; }

/* Stats bar */
.stats-bar { display: flex; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; align-items: stretch; }
.stat-sep { margin-left: 8px; border-left: 2px solid var(--border); padding-left: 20px; }
.stat { background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
        padding: 10px 16px; display: flex; flex-direction: column; gap: 2px; min-width: 110px; }
.stat-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: .05em; }
.stat-value { font-size: 18px; font-weight: 700; }
.stat-value.green { color: var(--green); }
.stat-value.red { color: var(--red); }
.stat-value.orange { color: var(--orange); }
.stat-value.blue { color: var(--blue); }

/* Filtros */
.filtros-form { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; align-items: center; }
.filtros-form select { padding: 6px 10px; border: 1px solid var(--border);
                       border-radius: 6px; background: var(--surface); font-size: 13px; }
.btn-clear { padding: 6px 12px; background: #fee2e2; color: var(--red); border-radius: 6px;
             text-decoration: none; font-size: 13px; }
.flash { padding: 10px 18px; border-radius: 8px; margin-bottom: 14px; font-size: 14px; font-weight: 600; }
.flash-ok { background: #dcfce7; color: #15803d; }
.flash-error { background: #fee2e2; color: #b91c1c; }
/* §20 · Aviso blando: ni error ni éxito. Mismo ámbar que los chips de "cerca
   del tope" del semáforo (§7.6), que es exactamente el mismo registro. */
.flash-aviso { background: #fef3c7; color: #92400e; }

/* Table */
.table-wrapper { overflow-x: auto; background: var(--surface); border: 1px solid var(--border);
                 border-radius: 10px; }
/* table-card: igual apariencia que table-wrapper pero SIN overflow propio.
   Permite que `thead position:sticky` se ancle al ancestro scrolleable
   (.page-scroll) en lugar de crear un sticky context interno inútil. */
.table-card { background: var(--surface); border: 1px solid var(--border);
              border-radius: 10px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }

/* `table-layout: fixed` SOLO donde las columnas declaran todos sus anchos y se
   quiere elipsis por celda. Era el default global, y ahí estaba el bug: en los
   ABM la columna de acciones no declara ancho, así que recibía apenas el % que
   sobraba (en Clientes 16% ≈ 208px) para unos botones que miden ~245px fijos;
   como además `td { overflow: hidden }`, en vez de ensancharse los recortaba y
   "Eliminar" quedaba cortado. Con el layout automático el ancho lo mide el
   navegador a partir del contenido, sin números mágicos.
   (.table-codif ya se salía de `fixed` con un table-layout:auto inline.) */
.table-movimientos, .table-resumen { table-layout: fixed; }

thead { position: sticky; top: 0; z-index: 5; }
thead tr { background: var(--bg); }
th { padding: 10px 8px; text-align: left; font-weight: 600; font-size: 11px;
     text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted);
     background: var(--bg);
     border-bottom: 1px solid var(--border);
     box-shadow: inset 0 -1px 0 var(--border);
     white-space: nowrap; overflow: hidden; }
td { padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: middle;
     overflow: hidden; }
tr:last-child td { border-bottom: none; }
th.num, td.num { text-align: right; }
.empty { text-align: center; color: var(--text-muted); padding: 32px; }

/* Column widths — tabla de movimientos
   Canal ensanchado (64→128) para mostrar "First Citizens U$S" en línea.
   Nueva col F. valor (56) extrae fecha valor desde referencia.
   Nota reducida (150→120). Rubro 192. col-actions: 70 con dos íconos.
*/
.table-movimientos .col-fecha   { width: 60px; }
.table-movimientos .col-canal   { width: 128px; }
.table-movimientos .col-moneda  { width: 34px; }
.table-movimientos .col-detalle { width: auto; }   /* flex: ocupa el resto */
.table-movimientos .col-fvalor  { width: 56px; }
.table-movimientos .col-nota    { width: 120px; }
.table-movimientos .col-num     { width: 82px; }
.table-movimientos .col-rubro   { width: 192px; }
.table-movimientos .col-origen  { width: 58px; }
.table-movimientos .col-saldo   { width: 82px; }
.table-movimientos .col-actions { width: 70px; }
.table-movimientos td.fvalor    { color: var(--text-muted); font-size: 12px;
                                  white-space: nowrap; }

.verde { color: var(--green); font-weight: 600; }
.rojo { color: var(--red); font-weight: 600; }

.detalle { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.detalle .ref-line { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ref { color: #9ca3af; font-size: 11px; }
td.canal { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fecha { white-space: nowrap; color: var(--text-muted); font-size: 12px; }
/* §65.6.b · La PREVISTA, medio tono por debajo de la fecha real: la real es un
   hecho contable y la prevista es una intención que ya caducó. Dibujarlas
   iguales pondría a competir dos fechas vecinas por la misma lectura. */
td.prev-cell { color: #9ca3af; }
/* El «+N» de la fila que cubre entregas de varias tandas: marca que hay más y
   manda al `title`, sin robarle ancho a la fecha. */
.prev-varias { font-size: 9px; color: #92400e; vertical-align: super;
               margin-left: 2px; }
.mon-badge { font-size: 10px; background: var(--bg); padding: 1px 4px; border-radius: 3px;
             color: var(--text-muted); }

/* Selects inline */
.sel-rubro { font-size: 12px; padding: 2px 4px; border: 1px solid var(--border);
             border-radius: 4px; background: transparent; width: 100%; max-width: 100%; }
.sel-rubro:focus { outline: 2px solid var(--accent); border-color: var(--accent); }

/* Input comentario (Nota) */
.nota-cell { padding: 4px 6px; }
.inp-comentario { font-size: 12px; padding: 3px 6px; border: 1px solid #d1d5db;
                  border-radius: 4px; background: #fff; width: 100%;
                  color: var(--text); }
.inp-comentario:focus { outline: 2px solid var(--accent); border-color: var(--accent); }

/* Badges */
.badge { font-size: 11px; padding: 2px 8px; border-radius: 10px; font-weight: 600; white-space: nowrap; }
.badge-ia { background: #dcfce7; color: #15803d; }
.badge-manual { background: #dbeafe; color: #1d4ed8; }
.badge-pendiente { background: #fef9c3; color: #a16207; }
.badge-regla { background: #ede9fe; color: #6d28d9; }
.badge-dup { background: #fde68a; color: #92400e; font-weight: 700; }

/* Action buttons en filas de tabla — íconos SVG uniformes */
.actions-cell { padding-right: 14px; text-align: right; white-space: nowrap; }
.actions-cell button { background: none; border: none; cursor: pointer;
                       padding: 4px; border-radius: 4px; line-height: 0;
                       color: var(--text-muted); transition: all .12s; }
.actions-cell button:hover { background: #f3f4f6; }
.actions-cell button svg { width: 16px; height: 16px; display: block; }
.btn-edit:hover { color: var(--brand); }
.btn-delete:hover { color: var(--red); background: #fee2e2; }
.btn-regla-inline { font-size: 14px !important; line-height: 1 !important; padding: 2px 6px !important; }

/* Cards */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
        padding: 20px 24px; margin-bottom: 20px; }
.card h2 { font-size: 16px; font-weight: 700; margin-bottom: 16px; }

/* TC grid */
.tc-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; margin-bottom: 14px; }
.tc-item { display: flex; flex-direction: column; gap: 4px; }
.tc-item label { font-size: 12px; color: var(--text-muted); font-weight: 600; }
.tc-item input { padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px;
                 font-size: 13px; width: 100%; }

/* Config table */
.table-config { width: 100%; }
.table-config td, .table-config th { padding: 8px 12px; }

/* Resumen table */
.table-resumen { font-size: 12px; }
.table-resumen th, .table-resumen td { padding: 6px 10px; }
.cel-neg { color: var(--red); }
.cel-pos { color: var(--green); }
.fila-total td { border-top: 2px solid var(--border); background: var(--bg); }

/* Saldo column */
.saldo-cell { color: var(--text); }

/* Buttons */
.btn-primary { padding: 8px 18px; background: var(--brand); color: #fff; border: none;
               border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; }
.btn-primary:hover { background: var(--brand-strong); }   /* §33A · era #2563eb: el hover de un botón teal no puede ser azul */
.btn-secondary { padding: 8px 18px; background: #f3f4f6; color: #374151; border: 1px solid #e0e3e8;
                 border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; }
.btn-secondary:hover { background: #e5e7eb; }

/* Filas especiales en resumen */
tr.fila-subtotal td {
    background: #1e3a5f;
    color: #fff;
    font-weight: 700;
}
tr.fila-subtotal td.cel-neg { color: #fca5a5; }
tr.fila-subtotal td.cel-pos { color: #86efac; }

tr.fila-especial td {
    background: #f0fdf4;
    font-style: italic;
}

tr.fila-no td {
    background: #f9fafb;
    color: #9ca3af;
    font-size: 11px;
}

/* ───────────────────────────────────────────────────────────────────────────
   Compartidos /auditoria, /reglas, /mover-a-empresa (tema claro unificado)
   ─────────────────────────────────────────────────────────────────────── */

/* Stat-chip: pill con conteo + label, fondo blanco con borde */
.stat-chip { background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
             padding: 7px 14px; font-size: 13px; color: var(--text-muted); }
.stat-chip span { font-weight: 700; font-size: 15px; color: var(--text); margin-right: 4px; }
.stat-chip.alta span     { color: var(--green); }
.stat-chip.media span    { color: #b45309; }
.stat-chip.baja span     { color: var(--orange); }
.stat-chip.aprobado span { color: var(--green); }
.stat-chip.rechazado span{ color: var(--red); }

/* Sub-nav tabs (paneles internos: /reglas Sugerencias / Activas) */
.subnav-tabs { display: flex; gap: 0; border-bottom: 2px solid var(--border); margin-bottom: 18px; }
.subnav-tab { background: none; border: none; padding: 9px 22px; font-size: 14px; font-weight: 600;
              color: var(--text-muted); cursor: pointer; border-bottom: 2px solid transparent;
              margin-bottom: -2px; }
.subnav-tab:hover { color: var(--text); }
.subnav-tab.active { color: var(--brand-strong); border-bottom-color: var(--brand); }
.subnav-tab .count-pill { background: var(--bg); color: var(--text-muted); border-radius: 10px;
                          padding: 1px 7px; font-size: 11px; margin-left: 6px; font-weight: 600; }
.subnav-tab.active .count-pill { background: var(--brand); color: #fff; }
.tab-pane { display: none; }
.tab-pane.active { display: block; }

/* Botones aprobar / rechazar inline (chips suaves) */
.btn-aprobar  { background: #dcfce7; color: #15803d; border: 1px solid #86efac;
                border-radius: 5px; padding: 4px 12px; font-size: 12px; font-weight: 600; cursor: pointer; }
.btn-aprobar:hover { background: #bbf7d0; }
.btn-rechazar { background: #fee2e2; color: #b91c1c; border: 1px solid #fecaca;
                border-radius: 5px; padding: 4px 12px; font-size: 12px; font-weight: 600; cursor: pointer; }
.btn-rechazar:hover { background: #fecaca; }
.btn-row { display: flex; gap: 6px; }
.btn-disabled { opacity: 0.4; cursor: default; pointer-events: none; }

/* Botón delete chico (eliminar regla en /reglas) */
.btn-del { background: none; border: 1px solid var(--border); color: var(--red);
           border-radius: 5px; padding: 2px 9px; font-size: 12px; cursor: pointer; }
.btn-del:hover { background: #fee2e2; border-color: #fecaca; }

/* Patrón monoespaciado (chip) */
.patron-mono { font-family: 'SFMono-Regular', Consolas, monospace; font-size: 12px;
               background: var(--bg); padding: 2px 7px; border-radius: 4px;
               color: var(--blue); border: 1px solid var(--border); }

/* Cobertura bar — barra de progreso fina */
.cob-bar { display: inline-flex; align-items: center; gap: 8px; }
.cob-n   { font-weight: 700; color: var(--text); min-width: 24px; }
.cob-bg  { width: 80px; height: 6px; background: var(--bg); border: 1px solid var(--border);
           border-radius: 3px; overflow: hidden; }
.cob-fill{ height: 100%; background: var(--brand); border-radius: 3px; }

/* Confianza % */
.conf-pct { font-size: 12px; font-weight: 600; }
.conf-hi  { color: var(--green); }
.conf-mid { color: #b45309; }
.conf-lo  { color: var(--orange); }

/* Badges de tipo (egreso/ingreso/transferencia/neutro/otro) — paleta soft del resto de la app */
.badge-tipo-egreso        { background: #fee2e2; color: #b91c1c; }
.badge-tipo-gasto         { background: #fee2e2; color: #b91c1c; }  /* alias legacy */
.badge-tipo-ingreso       { background: #dcfce7; color: #15803d; }
.badge-tipo-transferencia { background: #dbeafe; color: #1d4ed8; }
.badge-tipo-neutro        { background: #f3f4f6; color: #6b7280; }
.badge-tipo-otro          { background: #fef9c3; color: #a16207; }

/* Badges de confianza (alta/media/baja) */
.badge-confianza-alta  { background: #dcfce7; color: #15803d; }
.badge-confianza-media { background: #fef9c3; color: #a16207; }
.badge-confianza-baja  { background: #ffedd5; color: #c2410c; }

/* Badge de estado (pendiente/aprobado/rechazado) reusa .badge-pendiente etc. */
.badge-aprobado  { background: #dcfce7; color: #15803d; }
.badge-rechazado { background: #fee2e2; color: #b91c1c; }

/* Toggle real / oficial / consolidado de los estados de cuenta.
   ⚠️ El rótulo decía «/auditoria» y quedó viejo igual que el de `.tab-bar`: hoy
   sólo lo usa `_estados_macros.html` (§45, verificado por grep).
   §45 · padding 5px -> 3px: 26px -> 22px. Son tres palabras cortas. */
.filter-segmented { display: flex; gap: 4px; }
.filter-segmented a { padding: 3px 11px; border-radius: 6px; font-size: 12px; text-decoration: none;
                      background: var(--surface); color: var(--text-muted); border: 1px solid var(--border); }
.filter-segmented a.active, .filter-segmented a:hover {
  background: var(--brand); color: #fff; border-color: var(--brand); }

/* /auditoria — selector de rubro inline en la celda de acción */
.action-cell { display: flex; flex-direction: column; gap: 6px; min-width: 220px; }
.action-cell .rubro-select { background: var(--surface); color: var(--text);
                             border: 1px solid var(--border); border-radius: 5px;
                             padding: 5px 8px; font-size: 12px; width: 100%; }
.action-cell .rubro-select:focus { outline: none; border-color: var(--accent); }

/* Bloque descriptivo (texto explicativo arriba del contenido) */
.desc-block { background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
              padding: 14px 18px; margin-bottom: 18px; color: var(--text-muted);
              font-size: 13px; line-height: 1.55; max-width: 720px; }
.desc-block strong { color: var(--text); }
.desc-block-compact { padding: 7px 14px; margin-bottom: 12px; line-height: 1.4;
                      font-size: 12px; max-width: none; }

/* Empty state */
.empty-state { text-align: center; padding: 50px 20px; color: var(--text-muted); }
.empty-state h3 { color: var(--text); margin-bottom: 8px; font-size: 16px; font-weight: 600; }

/* Inputs / selects sobre fondo claro (auditoria, reglas search bar, etc.) */
.input-light, .select-light {
  background: var(--surface); color: var(--text); border: 1px solid var(--border);
  border-radius: 6px; padding: 6px 12px; font-size: 13px;
}
.input-light::placeholder { color: var(--text-muted); }
.input-light:focus, .select-light:focus { outline: 2px solid var(--accent); border-color: var(--accent); }

/* Umbral group (input numérico inline) */
.umbral-group { display: flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 13px; }
.umbral-group input { width: 56px; background: var(--surface); color: var(--text);
                      border: 1px solid var(--border); border-radius: 5px;
                      padding: 4px 8px; font-size: 13px; text-align: center; }

/* /mover-a-empresa — grid de selección de rubros */
.rubro-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
              gap: 8px; margin-bottom: 18px; }
.rubro-item { display: flex; align-items: center; gap: 8px; padding: 8px 12px;
              background: var(--surface); border-radius: 6px; border: 1px solid var(--border);
              cursor: pointer; user-select: none; transition: border-color .15s, background .15s; }
.rubro-item:hover { border-color: var(--brand); background: #f0fdfa; }  /* §33A · teal-50: era #eff6ff (azul-50) y el borde ya es teal */
.rubro-item input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--brand);
                                   cursor: pointer; flex-shrink: 0; }
.rubro-item .rubro-nombre { font-size: 13px; color: var(--text); flex: 1; }
.rubro-item .rubro-badge { font-size: 10px; padding: 1px 6px; border-radius: 8px; font-weight: 600; }
.rubro-item .rubro-count { font-size: 11px; color: var(--text-muted); margin-left: auto; }
.select-all-row { display: flex; gap: 14px; margin-bottom: 12px; font-size: 12px; }
.select-all-row button { background: none; border: none; color: var(--brand-strong); cursor: pointer;
                         text-decoration: underline; font-size: 12px; padding: 0; }

/* Iconos SVG genéricos */
.icon-btn { background: none; border: none; padding: 4px; border-radius: 4px;
            cursor: pointer; color: var(--text-muted); line-height: 0;
            transition: all .12s; }
.icon-btn:hover { background: var(--bg); color: var(--text); }
.icon-btn svg { width: 16px; height: 16px; display: block; }

/* ───────────────────────────────────────────────────────────────────────────
   /dashboard — tema claro
   ─────────────────────────────────────────────────────────────────────── */
.section-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase;
                 letter-spacing: .06em; margin: 18px 0 10px; font-weight: 600; }

.summary-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 24px; }
@media (max-width: 700px) { .summary-cards { grid-template-columns: 1fr; } }
.summary-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
                padding: 16px 20px; }
.summary-card .label { font-size: 11px; color: var(--text-muted); text-transform: uppercase;
                       letter-spacing: .05em; margin-bottom: 6px; font-weight: 600; }
.summary-card .value { font-size: 26px; font-weight: 700; color: var(--text); }
.summary-card.ing .value { color: var(--green); }
.summary-card.eg  .value { color: var(--red); }
.summary-card.net .value.pos { color: var(--green); }
.summary-card.net .value.neg { color: var(--red); }
.summary-card .sub { font-size: 11px; color: var(--text-muted); margin-top: 4px; }

.cards-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
              gap: 10px; margin-bottom: 28px; }
.mini-card { padding: 14px 16px; }
.card-canal { font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 2px; }
.card-moneda { font-size: 10px; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; }
.card-saldo { font-size: 20px; font-weight: 700; margin-top: 5px; color: var(--text); }
.card-saldo.pos { color: var(--green); }
.card-saldo.neg { color: var(--red); }
.card-saldo.na  { color: var(--text-muted); font-size: 13px; font-weight: 500; }
.card-sub { font-size: 10px; color: var(--text-muted); margin-top: 2px; }

.chart-box { padding: 18px; margin-bottom: 20px; }
.chart-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.chart-title { font-size: 14px; font-weight: 600; color: var(--text); }
.charts-row { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
@media (max-width: 900px) { .charts-row { grid-template-columns: 1fr; } }
.chart-canvas-wrap { position: relative; height: 280px; }
.evol-canvas-wrap { position: relative; height: 220px; }

.chart-toggle { display: flex; gap: 4px; flex-shrink: 0; }
.btn-toggle { padding: 4px 12px; background: var(--surface); border: 1px solid var(--border);
              border-radius: 5px; font-size: 11px; color: var(--text-muted); cursor: pointer; font-weight: 600; }
.btn-toggle:hover { border-color: var(--brand); color: var(--brand-strong); }
.btn-toggle.active { background: var(--brand); border-color: var(--brand); color: #fff; }

.mes-selector { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 14px; }
.btn-mes { padding: 4px 10px; background: var(--surface); border: 1px solid var(--border);
           border-radius: 5px; font-size: 12px; color: var(--text-muted); cursor: pointer; }
.btn-mes:hover { border-color: var(--brand); color: var(--brand-strong); }
.btn-mes.active { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 600; }

/* ───────────────────────────────────────────────────────────────────────────
   Searchable select (searchable-select.js)
   ─────────────────────────────────────────────────────────────────────── */
.srch { position: relative; display: inline-block; width: 100%; }
/* §27 · En la BARRA DE FILTROS el combo no va a 100%.
   `.srch` nace en 100% porque casi siempre vive adentro de algo que ya le fija
   el ancho —una celda de tabla, un .form-group de modal— y ahí llenar el hueco
   es exactamente lo que se quiere. Pero `.filtros-form` es
   `display:flex; flex-wrap:wrap`, y un flex item de ancho 100% FUERZA salto de
   línea: los seis filtros de Movimientos se apilaban de a uno por renglón,
   1352px cada uno, 245px de barra. Con el input encima vacío (ver §27 en
   searchable-select.js) el resultado eran seis renglones en blanco.
   Se acota al contenedor y no se toca el default: los .searchable de tablas y
   modales siguen igual. El ancho es fijo y no `auto` a propósito — `.srch-i`
   mide 100% de su wrap, así que un wrap shrink-to-fit dependería del tamaño
   intrínseco del <input>, que varía por navegador. */
.filtros-form .srch { width: 170px; }
.srch select { position: absolute; left: 0; top: 0; width: 1px; height: 1px;
               opacity: 0; pointer-events: none; }
.srch-i { width: 100%; padding: 5px 10px; border: 1px solid var(--border);
          border-radius: 6px; background: var(--surface); font-size: 13px;
          color: var(--text); cursor: text; box-sizing: border-box; }
.srch-i:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
.srch-l { position: fixed; max-height: 240px; overflow-y: auto;
          background: #fff; border: 1px solid var(--border); border-radius: 6px;
          box-shadow: 0 4px 14px rgba(0,0,0,0.10);
          list-style: none; padding: 4px 0; margin: 0; z-index: 1000;
          display: none; min-width: 140px; }
.srch-l.o { display: block; }
.srch-l li { padding: 5px 12px; font-size: 13px; cursor: pointer;
             white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
             color: var(--text); }
.srch-l li:hover, .srch-l li.a { background: var(--bg); }
.srch-l li.s { font-weight: 600; color: var(--brand-strong); }
.srch-l li.srch-empty { color: var(--text-muted); cursor: default;
                        font-style: italic; }

/* Tabla de codificación: densidad y agrupación visual de dimensiones Estudio */
.table-codif td, .table-codif th { padding: 6px 6px; }
.table-codif .col-est { border-left: 2px solid var(--border); }
.table-codif .sel-dim + .srch-i, .table-codif td .srch-i { font-size: 12px; padding: 3px 6px; }

/* ── §3x-bis · ANCHO FIJO: lo que hay que agregar para que CORTE BIEN ────────
   `td { overflow: hidden }` es GLOBAL (arriba), así que con `table-layout:fixed`
   todas estas celdas ya recortaban — pero SIN elipsis, o sea cortando el texto a
   la mitad de una letra y sin ninguna señal de que falta algo. La elipsis no es
   cosmética: es lo único que le dice al operador que tiene que pasar el mouse.

   ⚠️ TODO SCOPEADO A `.table-codif`, y no es prolijidad: `.num` vive en SIETE
   plantillas y `td` en todas. Bajar esto a la hoja global movería una docena de
   pantallas que nadie midió — la lección de §45.2, que por eso scopeó su ritmo
   vertical a `.est-compacto` en vez de tocar `.stats-bar`.

   Lo que NO está acá porque YA estaba y recién ahora funciona: `.detalle` y
   `td.canal` traen `text-overflow: ellipsis` desde §22c/§32, y no hacían nada —
   en layout automático el navegador ensancha la columna hasta que el texto entre,
   así que un `text-overflow` declarado no llega a aplicarse NUNCA (§3x.4). Eran
   dos reglas correctas esperando la decisión que las volviera ciertas. */
.table-codif th { text-overflow: ellipsis; }
.table-codif td.tipo-cell { text-overflow: ellipsis; }
.table-codif td .items-aplic { display: block; white-space: nowrap;
                               overflow: hidden; text-overflow: ellipsis; }
/* ⚠️⚠️ LAS TRES DE PLATA: `nowrap` para que un importe NUNCA envuelva a dos
   líneas (subiría el alto de la fila, que es trabajo de otro punto de esta
   sesión y no de éste), y elipsis para que un recorte se VEA. Van a la derecha,
   así que lo que se pierde son los dígitos de la izquierda: «1.234.567,89»
   recortada se lee «234.567,89», un número creíble y diez veces menor. El ancho
   está calculado para que no pase; esto y el `title` de la plantilla son la red
   por si pasa igual. Es la familia de §21 —un importe mal presentado es
   invisible— y de la trampa de `|plata` en ARRANQUE §4. */
.table-codif td.num { white-space: nowrap; text-overflow: ellipsis; }
/* §3x-ter · «(a cobrar)» en la columna Cuenta, que mide 66px con 54 de caja
   útil. MEDIDO en navegador: a 13px el texto pide 56,4px, o sea que se cortaba
   por 2,4px — «(a cobrar…», que es peor que el «—» que vino a reemplazar,
   porque un texto recortado se lee como un dato incompleto y no como un estado.

   Se baja a 11px y NO se abrevia, que era la otra salida: «a cobrar» sin
   paréntesis entra a 13px, pero los paréntesis son los que dicen que esto es un
   ESTADO y no el nombre de una cuenta llamada «a cobrar». Perder el paréntesis
   es perder justamente la distinción que §3x-ter vino a hacer; perder 2px de
   tipografía no cuesta nada — es el mismo tamaño con el que la grilla ya
   escribe los números de comprobante bajo el detalle.

   A 11px pide 47,7px contra 54 disponibles: 6px de margen, que aguanta el
   redondeo de subpíxel y una fuente de fallback. */
.table-codif td.canal .cta-a-cobrar { color: #9ca3af; font-size: 11px; }

/* §3x-ter · El badge de una descartada, en la columna EST de 40px. `max-width`
   al 100% de la celda + elipsis: sin esto un `inline-block` se DESBORDA de su
   `<td>` en vez de recortarse —`overflow:hidden` recorta al hijo en el borde,
   pero el badge se dibuja encima de la columna de al lado hasta ahí— y el ancho
   fijo dejaría de verse fijo justo en las dos filas que no lo cumplen. */
.table-codif td .badge-descartada { display: inline-block; max-width: 100%;
                                    overflow: hidden; text-overflow: ellipsis;
                                    white-space: nowrap; vertical-align: middle; }
/* §3x-ter · El tilde de EST, centrado como los de «Of.» y «Opi»: los tres son
   una casilla sola en una columna angosta, y alinearlos distinto los haría ver
   como controles distintos. El `gap` se va con el `<span>` que ya no está. */
.table-codif td .tick-estado { gap: 0; justify-content: center; width: 100%; }

/* Semáforo de cotejo contra presupuesto (§7.6) — aviso, nunca bloquea */
.sem-chip { display: inline-block; padding: 1px 8px; border-radius: 10px;
            font-size: 11px; font-weight: 600; white-space: nowrap; }
.sem-chip.verde    { background: #dcfce7; color: #15803d; }
.sem-chip.amarillo { background: #fef9c3; color: #a16207; }
.sem-chip.rojo     { background: #fee2e2; color: #b91c1c; }
/* RONDA 1 · «al tope»: consumió el presupuesto entero. Más fuerte que el
   amarillo de «cerca» y más suave que el rojo de «excede» — es el límite
   exacto, no una violación. */
.sem-chip.tope     { background: #ffedd5; color: #9a3412; font-weight: 600; }
.sem-chip.neutro   { background: var(--bg); color: var(--text-muted); }
/* §24.4.c · El VERDE no se pinta. `semaforo()` lo sigue devolviendo —«dentro» es
   una respuesta y los tests la verifican— pero la pantalla se calla: sólo se
   dibuja el ≥90% y el excede. Silencio = está bien. La regla de §7.6 no cambia
   (avisa, nunca bloquea); lo que cambia es que dejar de avisar TAMBIÉN informa,
   y una columna con todo pintado de verde no dejaba ver los dos que importaban.
   La clase se conserva a propósito, sin color: sacarla del HTML obligaría a que
   la plantilla decidiera qué es «suficientemente bien», que es justo lo que vive
   en services/cotejo.semaforo. */
td.sem-verde    { color: inherit; }
td.sem-amarillo { color: #b45309; }
td.sem-tope     { color: #9a3412; font-weight: 600; }
td.sem-rojo     { color: var(--red); font-weight: 700; }

/* En filas inline (sel-rubro), input más compacto */
.sel-rubro + .srch-i, .srch .sel-rubro + .srch-i,
.srch .sel-rubro ~ .srch-i { font-size: 12px; padding: 3px 6px; }
td.rubro-cell .srch-i { font-size: 12px; padding: 3px 6px; }
.action-cell .srch-i { font-size: 12px; padding: 4px 8px; }

/* §18.3 · Pago multi-entrega en Movimientos: la fila es UNA, el desglose cuelga.
   El chevron abre el panel de aplicaciones; la celda de ítem de una fila-pago no
   es editable (el ítem vive en cada aplicación, no en el pago). */
.btn-aplic { background: none; border: 0; padding: 0 2px 0 0; cursor: pointer;
             display: inline-flex; align-items: center; gap: 4px; font: inherit; }
.btn-aplic .chev { color: #6b7280; font-size: 10px; width: 10px; }
.btn-aplic:hover .badge { filter: brightness(0.96); }
.items-aplic { font-size: 12px; color: #6b7280; font-style: italic; }
.fila-aplic > td { border-top: 0; }
/* §35 · Acá vivían las reglas de `#modal-nuevo` (max-height:92vh + overflow, y la
   grilla de 3 columnas). SE FUERON CON EL MODAL: la carga es la pantalla
   `/codificacion/nueva`. Se deja la nota y no el CSS, porque el `92vh` con
   `overflow-y:auto` es justamente la prueba de que aquello YA SCROLLEABA — que
   es el argumento por el que §35 dejó de ser un modal. */

/* ══════════════════════════════════════════════════════════════════════════
   §19 · MOVIMIENTOS: el período, el tipo y las acciones de fila
   ══════════════════════════════════════════════════════════════════════════ */

/* El período es el TÍTULO de la pantalla, no un filtro escondido: el operador tiene
   que ver de un vistazo en qué mes está parado. */
.page-header h1 .per-titulo { font-size: 20px; font-weight: 700; }
.page-header h1 small { display: block; font-size: 12px; font-weight: 400;
  color: #6b7280; margin-top: 2px; text-transform: none; }

.periodo-tira { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 10px; }
.periodo-tira .per { position: relative; padding: 5px 11px; border-radius: 7px;
  border: 1px solid var(--border); background: #fff; color: #6b7280;
  font-size: 12px; font-weight: 600; text-decoration: none; line-height: 1;
  display: inline-flex; align-items: center; gap: 5px; }
.periodo-tira .per:hover { border-color: var(--brand); color: var(--brand-strong); }
.periodo-tira .per.activo { background: var(--brand); border-color: var(--brand);
  color: #fff; }
/* El PUNTO: ese mes tiene movimientos sin rubro o pendientes. Es lo que deja ver el
   trabajo que falta en los meses en los que NO estás parado. */
.periodo-tira .punto { width: 6px; height: 6px; border-radius: 50%;
  background: var(--orange); display: inline-block; }
.periodo-tira .per.activo .punto { background: #fff; }

.chips-bar { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
a.stat-chip { text-decoration: none; }
a.stat-chip:hover { border-color: var(--brand); }
.stat-chip.chip-on { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand) inset; }

/* §22c · Los chips de LO QUE ESTÁ FILTRADO (distintos de los .stat-chip, que
   CUENTAN). Estos declaran por qué la grilla muestra lo que muestra, y cada uno
   trae su ✕ para sacarse solo. Van en ámbar, no en el gris del resto: son un
   estado activo de la pantalla, no decoración. */
.filtro-activo { display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
                 background: #fffbeb; border: 1px solid #fde68a; border-radius: 8px;
                 padding: 8px 12px; margin-bottom: 12px; }
.filtro-activo .fa-rotulo { font-size: 11px; text-transform: uppercase;
                            letter-spacing: .04em; color: #92400e; font-weight: 700; }
.fa-chip { display: inline-flex; align-items: center; gap: 6px; background: #fff;
           border: 1px solid #fcd34d; border-radius: 6px; padding: 3px 4px 3px 9px;
           font-size: 12px; color: #78350f; }
.fa-chip b { font-weight: 700; color: #92400e; }
.fa-chip a { text-decoration: none; color: #b45309; padding: 0 5px; border-radius: 4px;
             font-size: 13px; line-height: 1.4; }
.fa-chip a:hover { background: #fde68a; color: #7c2d12; }

/* El aviso de lo que queda AFUERA del ancla temporal. */
.aviso-fuera { background: #eff6ff; border: 1px solid #bfdbfe; color: #1e40af;
               border-radius: 8px; padding: 8px 12px; margin-bottom: 12px; font-size: 13px; }
.aviso-fuera a { color: inherit; font-weight: 600; }

/* §22c · El pie con el total de lo filtrado. `sticky` porque el total de una
   grilla que scrollea sirve poco si hay que llegar al fondo para verlo.

   ⚠️ §3x-ter · EL `sticky` SE ACOTA A LA ÚLTIMA FILA, y es por el pie nuevo: son
   TRES renglones ahora (uno por moneda + el consolidado), y `bottom: 0` en los
   tres los apilaría a todos en el mismo lugar — tres totales superpuestos, que
   es peor que ninguno pegado.

   Se elige el consolidado y no los nativos porque es el único que resume la
   grilla ENTERA; los de cada moneda son su desglose y se leen al llegar al pie.

   ✅ LA CONDUCTA REAL, medida en navegador el 15-ago-2026 en los dos viewports:
   el consolidado SE PEGA. Su `<td>` queda clavado —`top` idéntico en las cinco
   posiciones de scroll, con el borde inferior contra el del wrapper— mientras el
   `<tr>` recorre toda la tabla. Las `.fila-total-nat` son `static` y entran en la
   banda visible recién al llegar al final, que es exactamente el reparto que esta
   regla busca.

   ⚠️ EL SELECTOR ES `> td` Y ESO ES LO QUE HAY QUE MEDIR. El sticky vive en las
   CELDAS, no en la fila: un `<tr>` cuyos `<td>` son sticky no refleja el
   desplazamiento —las celdas se corren adentro y la fila se queda en el flujo—,
   así que `tr.getBoundingClientRect()` devuelve el elemento que NO se mueve.
   Acá decía «INERTE, confinado al containing block del tfoot» y era eso: dos
   sondas midieron el `<tr>`, dieron la misma serie de números y se leyeron como
   confirmación independiente. Ver ARRANQUE §4. */
.table-codif tfoot .fila-total:last-child > td { position: sticky; bottom: 0; }
.table-codif tfoot .fila-total > td { background: #f9fafb; padding: 9px 8px; }
.table-codif tfoot .fila-total-cons > td { border-top: 2px solid var(--border); }
/* §3x-ter · Los nativos son el DESGLOSE del consolidado, y la jerarquía la marca
   el SEPARADOR —1px contra los 2px del consolidado—, no el tamaño de los
   números.

   ⚠️ Acá había un `font-size: 12px` que los achicaba, y se saca: con los números
   más chicos y menos pesados que los del consolidado, el verde y el rojo de las
   nativas se leían como si NO estuvieran (reporte de Dave: «van en negro»).
   Medido en navegador, el color SÍ estaba aplicado en las tres filas
   —`rgb(22,163,74)` y `rgb(220,38,38)`, idéntico al consolidado—, o sea que el
   problema nunca fue el color sino el PESO con el que se lee.

   Es la lección de §21 dada vuelta: ahí un importe mal presentado era invisible
   por el formato; acá un color correcto era invisible por el tamaño. Una señal
   que está en el DOM y no llega al ojo no está puesta. */
.table-codif tfoot .fila-total-nat > td { border-top: 1px solid var(--border); }
.fila-total b { font-size: 14px; }
.fila-total small { display: block; font-size: 11px; color: #6b7280; font-weight: 400; }
/* §22b · La celda U$S de una fila que no suma: se ve, pero se ve que no cuenta. */
.usd-no-suma { opacity: .45; text-decoration: line-through; }

/* La columna TIPO: qué ES esta fila, sin abrir nada. */
.tipo-cell { white-space: nowrap; }
.badge-pago { background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe; }
.badge-ade { background: #fffbeb; color: #92400e; border: 1px solid #fde68a; }
.tipo-simple { font-size: 11px; color: #9ca3af; }
.ade-saldo { display: block; font-size: 10px; color: #92400e; margin-top: 2px; }

/* El menú de la fila (⋯). Sólo muestra las acciones que esa fila puede hacer. */
.actions-cell { position: relative; }
.btn-mas { font-size: 16px; line-height: 1; color: #9ca3af; padding: 2px 6px;
  border-radius: 5px; }
.btn-mas:hover { color: var(--brand); background: #f3f4f6; }
/* El menú abierto NO puede quedarse dentro de la tabla: la tabla es
   `border-collapse: collapse`, y con los bordes colapsados Chrome IGNORA el z-index de
   las celdas. Da igual cuánto le suba: las celdas de las filas de abajo —con sus
   <select> de estado— se le pintan encima igual, y el menú queda visible pero muerto:
   se ve, se apunta, y el click aterriza en el <select> de la fila siguiente. Medido con
   elementFromPoint, no deducido. Por eso el JS lo saca al <body> mientras está abierto
   (.flotante) y lo devuelve a su celda al cerrarlo: fuera de la tabla, el z-index vale.
   Queda debajo del modal (200): si se abre un modal, el menú ya se cerró. */
.menu-fila.flotante { position: fixed; z-index: 150; }
.menu-fila { position: absolute; right: 10px; top: 100%; z-index: 30;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,.12); padding: 4px; min-width: 210px;
  text-align: left; }
.menu-fila .mi { display: block; width: 100%; text-align: left; background: none;
  border: none; cursor: pointer; font-size: 12px; color: #374151;
  padding: 7px 10px; border-radius: 6px; white-space: nowrap; }
.menu-fila .mi:hover { background: #f3f4f6; }
.menu-fila .mi-borrar { color: var(--red); }
.menu-fila form { margin: 0; }

.btn-desvincular { background: none; border: 1px solid var(--border); cursor: pointer;
  font-size: 11px; color: #92400e; padding: 2px 8px; border-radius: 5px; }
.btn-desvincular:hover { border-color: #92400e; background: #fffbeb; }

#modal-vincular .modal-box { max-height: 90vh; overflow-y: auto; }

/* ── §20 S3 · Presupuesto por bloques ─────────────────────────────────────── */
/* Los tres bloques de un ítem. El color no decora: distingue qué se presupuestó
   antes (previstas), qué se agregó al codificar (agregados) y qué está a medio
   codificar (sin línea) — que es lo único que pide acción. */
.chip-bloque { display:inline-block; padding:1px 8px; border-radius:10px; font-size:10px;
               font-weight:700; text-transform:uppercase; letter-spacing:.04em; }
.chip-bloque.previstas { background:#e0e7ff; color:#3730a3; }
.chip-bloque.agregados { background:#fef3c7; color:#92400e; }
.chip-bloque.sinlinea  { background:#fee2e2; color:#b91c1c; }

#tabla-presupuesto .fila-item > td { background:#f8fafc; border-top:2px solid #e2e8f0; }
#tabla-presupuesto .fila-item strong { font-size:14px; }
#tabla-presupuesto .cuenta-lineas { margin-left:8px; font-size:11px; color:#9ca3af; font-weight:400; }
#tabla-presupuesto .fila-bloque > td { background:#fcfdff; font-size:12px; padding-top:5px; padding-bottom:5px; }
#tabla-presupuesto .fila-bloque.sin-linea > td { background:#fffaf7; }
#tabla-presupuesto .fila-linea > td:first-child { padding-left:20px; }
#tabla-presupuesto .fila-total-bloque > td { font-size:12px; color:#6b7280; }
#tabla-presupuesto .fila-total-bloque.sin-linea > td { color:#92400e; }
/* §67-bis · El adelanto pendiente de imputar. TEAL (la marca) y no el ámbar de
   «sin línea»: aquélla pide acción —hay que ir a corregir la codificación— y
   ésta no pide nada, se resuelve sola cuando llega la entrega. Dos filas que se
   leen igual se obedecen igual, y una de las dos no hay que obedecerla. */
#tabla-presupuesto .fila-total-bloque.sin-imputar > td { color:var(--brand-strong); }
/* La misma fila, en la tabla por ítem de Estado de Proyecto (§67-bis). */
.fila-sin-imputar > td { color:var(--brand-strong); font-style:italic; }
/* ⚠️ `--brand-strong` y NO `--brand`: la regla del token es de CONTRASTE
   MEDIDO, no de gusto — `--brand` como TEXTO da 3,74 sobre blanco, debajo
   del 4,5 de WCAG. Ver la cabecera de este archivo. */
/* El tope IMPLÍCITO de un agregado sin monto: no es un dato que alguien cargó,
   y tiene que verse distinto de uno que sí. */
.tope-implicito { color:#92400e; border-bottom:1px dotted #d97706; cursor:help; }

/* Toggle de vistas */
.btn-vista { padding:5px 14px; font-size:12px; font-weight:600; cursor:pointer;
             border:1px solid #e0e3e8; background:#fff; color:#6b7280; }
.btn-vista:first-child { border-radius:6px 0 0 6px; }
.btn-vista:last-child  { border-radius:0 6px 6px 0; border-left:none; }
.btn-vista.activa { background:var(--brand); color:#fff; border-color:var(--brand); }

/* ── §24 · Presupuesto: densidad y operación ─────────────────────────────────
   El ítem cerrado es UNA fila y se despliega a demanda; lo explicativo y el alta
   viven plegados arriba. La ventana de Opi no scrollea (html,body:overflow
   hidden), así que cada renglón fijo que se pliega es alto que gana la tabla. */
.caret, .caret-linea { background:none; border:none; cursor:pointer; padding:0 4px;
                       color:#6b7280; font-size:11px; line-height:1; }
.caret:hover, .caret-linea:hover { color:var(--brand); }
.caret { font-size:13px; }
#tabla-presupuesto .fila-item > td:first-child { cursor:default; }

/* Paneles plegables (<details> nativo: cero JS, y por lo tanto cero riesgo de
   que un <script> mal ubicado los deje muertos — ver ARRANQUE §4). */
.panel-plegable { border:1px solid var(--border); border-radius:8px; background:var(--surface);
                  margin-bottom:10px; }
.panel-plegable > summary { cursor:pointer; padding:7px 14px; font-size:12px; font-weight:600;
                            color:var(--brand-strong); list-style:none; user-select:none; }
.panel-plegable > summary::-webkit-details-marker { display:none; }
.panel-plegable > summary::before { content:'▸ '; font-size:10px; }
.panel-plegable[open] > summary::before { content:'▾ '; }
.panel-plegable.ayuda > summary { color:#6b7280; font-weight:500; }
.panel-cuerpo { padding:4px 14px 14px; border-top:1px solid var(--border); }

/* RONDA 2 · Acá vivía `.presup-barra`, la franja de fecha del presupuesto y TC
   sugerido. Se fue ENTERA: sus dos datos son de apoyo y ahora van en `.vp-pie`,
   dentro del bloque «Cuánto vale el proyecto». Una caja propia con borde y
   fondo les daba el mismo peso visual que a las cifras que definen el proyecto,
   y encima gastaba un renglón de tabla (§38 [d] ya había medido que ese renglón
   valía cinco líneas de presupuesto). */

/* La alerta de «sin línea»: sólo se dibuja si hay casos REALES (§24.4.e). Una
   leyenda describe una categoría posible; esto dice que hay trabajo pendiente. */
.aviso-sinlinea { background:#fffaf7; border:1px solid #fed7aa; border-left:3px solid #d97706;
                  border-radius:6px; padding:8px 14px; margin-bottom:10px;
                  font-size:12px; color:#92400e; }

/* El desglose de una línea: las tres capas que §24.5.b sacó de la grilla. */
#tabla-presupuesto .fila-desglose > td { background:#f8fafc; padding:8px 14px 8px 34px; }
.desglose-caja { display:flex; gap:28px; flex-wrap:wrap; align-items:center; }
.desglose-capas { display:flex; gap:22px; flex-wrap:wrap; font-size:12px; color:#374151; }
.desglose-capas b { font-weight:600; color:#6b7280; font-size:11px; text-transform:uppercase;
                    letter-spacing:.03em; margin-right:4px; }
.desglose-capas small { display:block; font-size:10px; color:#9ca3af; }
.desglose-estructura { display:flex; gap:16px; align-items:center; font-size:12px;
                       color:#6b7280; margin-left:auto; }
.desglose-estructura label { display:flex; gap:6px; align-items:center; }

/* Feedback del guardado por blur (§24.5.a). El error NO se borra solo: si la
   fila se rechazó, lo que hay que hacer es leerlo. */
.guardado { display:inline-block; font-size:10px; margin-left:6px; }
.guardado.ok    { color:var(--green); }
.guardado.error { color:var(--red); font-weight:600; }

/* ═══════════════════════════════════════════════════════════════════════════
   §30 · DENSIDAD DE LISTAS — el patrón transversal
   ═══════════════════════════════════════════════════════════════════════════
   Medido antes de tocar nada: la primera fila de datos arrancaba a 375px del
   borde en Movimientos y a 702px en Configuración. A 1366×768 eso son 10 y 1
   fila visibles. El operador que pasa movimientos en serie tiene que ver
   movimientos, no formulario.

   Nada de esto cambia la INTERACCIÓN: los inputs siguen siendo inputs, la
   edición inline sigue siendo inline y el guardado no se toca. Lo único que
   cambia es cuánto espacio ocupa cada cosa. */

/* ── El panel de filtros plegable (templates/_filtros.html) ───────────────── */
.panel-filtros { margin-bottom: 10px; }
.panel-filtros > summary {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  padding: 5px 12px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface); font-size: 13px; font-weight: 500; color: var(--text);
  list-style: none; user-select: none; }
.panel-filtros > summary::-webkit-details-marker { display: none; }
.panel-filtros > summary:hover { border-color: var(--brand); color: var(--brand-strong); }
.panel-filtros[open] > summary { border-color: var(--brand); color: var(--brand-strong);
  border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.pf-icono { font-size: 11px; color: var(--text-muted); }
.panel-filtros[open] .pf-icono { color: var(--brand-strong); }
/* §30.3 · El botón AVISA que hay filtros puestos sin tener que desplegarlo. Sin
   esto, un drill-down que llega con filtros y el panel cerrado dejaría al
   operador leyendo una grilla acotada sin ninguna pista de por qué. */
.pf-badge { display: inline-flex; align-items: center; justify-content: center;
  min-width: 17px; height: 17px; padding: 0 5px; border-radius: 9px;
  background: var(--brand); color: #fff; font-size: 11px; font-weight: 700; }
.pf-cuerpo { border: 1px solid var(--brand); border-radius: 0 6px 6px 6px;
  padding: 10px 12px; margin-top: -1px; background: var(--surface); }
/* El form de adentro pierde su margen: ya lo pone el panel. */
.pf-cuerpo .filtros-form { margin-bottom: 0; }

/* ── Cabeceras compactas ─────────────────────────────────────────────────── */
/* El título de una pantalla de lista no necesita 40px: necesita decir dónde
   estás. §30.6 — compactar sin perder legibilidad. */
.page-header.ph-compacto { margin-bottom: 8px; }
.page-header.ph-compacto h1 { font-size: 16px; line-height: 1.25; }
.page-header.ph-compacto h1 small { font-size: 12px; }

/* Los desc-block explican la pantalla la PRIMERA vez y estorban las otras mil.
   Se pliegan: el texto no se pierde, deja de ocupar. */
details.desc-plegable { margin-bottom: 10px; }
details.desc-plegable > summary { cursor: pointer; font-size: 12px;
  color: var(--text-muted); padding: 2px 0; list-style: none;
  display: inline-flex; align-items: center; gap: 6px; }
details.desc-plegable > summary::-webkit-details-marker { display: none; }
details.desc-plegable > summary:hover { color: var(--brand); }
details.desc-plegable > summary::before { content: '?'; display: inline-flex;
  align-items: center; justify-content: center; width: 15px; height: 15px;
  border: 1px solid var(--border); border-radius: 50%; font-size: 10px;
  font-weight: 700; }
details.desc-plegable[open] > summary { color: var(--brand-strong); }
details.desc-plegable .desc-block { margin-top: 6px; }

/* ── §30.7 · LA ALTURA DE FILA, que es lo que más rinde ───────────────────── */
/* De 47px a ~32px en las grillas editables. NO cambia la interacción: el input
   sigue siendo un input, editable siempre, con su mismo form y su mismo
   guardado. Lo único que se achica es el padding, que era de formulario y no de
   grilla.
   Se aplica por clase y no globalmente: los formularios de ALTA (el `<details>`
   del pie de cada ABM, los modales) conservan el tamaño cómodo, porque ahí sí
   se está llenando un formulario y no leyendo una lista. */
.table-densa td { padding: 3px 8px; }
.table-densa th { padding: 6px 8px; }
.table-densa td input[type="text"],
.table-densa td input[type="number"],
.table-densa td input[type="date"],
.table-densa td select,
.table-densa td .srch-i,
.table-densa td .money-input {
  padding: 2px 7px !important; font-size: 12.5px; line-height: 1.35; }
.table-densa td .money-wrap { display: inline-block; }
/* El checkbox de una grilla densa no necesita 16px de alto propio. */
.table-densa td input[type="checkbox"] { width: 14px; height: 14px; }
/* Los badges de estado bajan con la fila. */
.table-densa td .badge { padding: 1px 7px; font-size: 10.5px; }
/* El ⋯ y su celda (§26.2) no cambian de tamaño: son el blanco de un click y
   achicarlos volvería a la trampa de §19 (un objetivo que se ve y no se acierta). */
.table-densa td.actions-cell { padding: 2px 8px; }

/* ── §30.5 · Píldoras y tira de período, en UN renglón ────────────────────── */
/* Son elementos de una palabra: partirlos en dos renglones gasta 34px por nada. */
.chips-bar { display: flex; gap: 6px; flex-wrap: nowrap; overflow-x: auto;
  margin-bottom: 8px; padding-bottom: 2px; }
.chips-bar::-webkit-scrollbar { height: 4px; }
.periodo-tira { flex-wrap: nowrap; overflow-x: auto; }

/* ── El pie de total, pegado abajo y sin robarle altura a las filas ───────── */
.table-densa tfoot td { padding: 5px 8px; }

/* §30 · OPCIÓN 2 para Configuración: las CUATRO tablas siguen apiladas y en el
   mismo orden. No se convierten en pestañas ni en acordeón a propósito — una
   sección que antes se encontraba scrolleando tiene que seguir encontrándose
   scrolleando. Lo único que cambia es cuánto ocupa cada una: 702px de chrome
   antes de la primera fila era el peor número de toda la app (1 fila visible a
   1366×768). */
.card.card-compacta { padding: 12px 16px; margin-bottom: 12px; }
.card.card-compacta h2 { font-size: 14px; margin-bottom: 8px; }
.card.card-compacta h2 small { font-size: 11px; }
.card.card-compacta .desc-plegable { margin-bottom: 6px; }

/* §30.5 · La tira de período y las píldoras, en UN renglón. */
.barra-contexto { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 8px; }
.barra-contexto .periodo-tira { margin-bottom: 0; flex: 0 1 auto; }
.barra-contexto .chips-bar { margin-bottom: 0; flex: 0 1 auto; }
/* ⚠️ `flex: 0 1 auto`, NO `1 1 auto`. Con `flex-grow: 1` la barra de píldoras se
   estiraba a los 1352px del contenedor —su contenido mide ~600— y empujaba la
   tira de meses al renglón siguiente: el mismo problema que se venía a arreglar,
   causado por la regla que lo arreglaba. Se ve sólo midiendo el `scrollWidth`
   contra el ancho disponible. */

/* ═══════════════════════════════════════════════════════════════════════════
   §31 · EL MODAL DE CARGA
   ═══════════════════════════════════════════════════════════════════════════ */

/* §35 · Las reglas de ancho y grilla de `#modal-nuevo` SE FUERON con el modal.
   Vale conservar el dato que dejaron, porque es la historia entera del bloque:
   §31 midió que el peor caso —oficial + proyecto + panel de pago— recortaba
   107px con «Guardar» afuera, y lo resolvió ensanchando a 1120px y 4 columnas.
   §35 encontró lo mismo otra vez (227px a 1512, 279px a 1366) y esa segunda vez
   se leyó como lo que era: **el panel de pago no cabe en el formulario de carga
   porque no es parte de cargar**. Se fue a su propio modal (`#modal-pago`), y la
   pantalla entra exacta sin trucos de layout. */

/* Los dos rótulos de sección: «Qué es» y «Cuánto». No son decorado — son lo que
   hace legible el orden nuevo (primero qué es, después cuánto). */
.mg-seccion { flex-direction: row; align-items: baseline; gap: 10px;
  border-bottom: 1px solid var(--border); padding-bottom: 3px; margin-top: 4px; }
.mg-seccion > span { font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--text-muted); }

/* §31.2 · UN CAMPO ATENUADO. No desaparece y no se mueve: queda donde estaba,
   apagado, para que la pantalla no cambie de forma mientras se carga. Y sigue
   siendo clickeable —`pointer-events` NO se toca— porque si el operador
   insiste, se activa: el automatismo sugiere, no decide (§19). */
.campo-atenuado { opacity: .42; }
.campo-atenuado select, .campo-atenuado input { background: var(--bg); cursor: pointer; }
.campo-atenuado:hover { opacity: .75; }

/* §31.5 · El «+» de la grilla: fila fantasma al final e ícono en el encabezado. */
.fila-nueva td { padding: 0; }
.fila-nueva button { width: 100%; text-align: left; background: none; border: none;
  padding: 7px 10px; font-size: 12.5px; color: var(--text-muted); cursor: pointer;
  display: flex; align-items: center; gap: 7px; }
.fila-nueva button:hover { background: var(--bg); color: var(--brand-strong); }
.fila-nueva button b { font-size: 15px; line-height: 1; }
.th-nuevo { background: none; border: none; cursor: pointer; color: var(--text-muted);
  font-size: 15px; line-height: 1; padding: 2px 6px; border-radius: 5px; }
.th-nuevo:hover { color: var(--brand); background: #f3f4f6; }

/* §31 · La lista de entregas del panel de pago. Era `max-height:280px` inline, y
   con eso el peor caso del modal seguía recortando 46px a 1366×768. La lista YA
   tiene scroll propio, así que achicarla en pantallas bajas no esconde nada:
   mueve el scroll de donde estorba (el modal entero, con «Guardar» afuera) a
   donde no (una lista que de todos modos se recorre). */
.pago-entregas { max-height: 280px; overflow: auto; }
@media (max-height: 820px) { .pago-entregas { max-height: 200px; } }

/* §35 · El apretado de `#modal-nuevo` en pantallas bajas se fue con el modal.
   Lo que sí sobrevive es el escalón de `.pago-entregas` de arriba (280→200px),
   porque ahora vive en `#modal-pago` y ahí sigue haciendo falta. */

/* §32.5 · El contacto del cliente dentro del modal de Proyectos. De SÓLO
   LECTURA: no es un campo, no postea, y se edita en Clientes (que es donde
   vive). No va en un `title` de la grilla —un tooltip no existe en táctil, no
   se descubre y no se puede copiar—, así que acá tiene que ser legible y
   SELECCIONABLE: nada de `user-select:none` ni de `pointer-events:none`. */
.cli-contacto { margin-top: 6px; padding: 8px 10px; background: #f9fafb;
                border: 1px solid var(--border); border-radius: 6px;
                font-size: 12px; line-height: 1.55; color: #374151; }
.cli-contacto-rot { color: #9ca3af; font-weight: 600; }

/* §32 · El modal de Clientes. Dos columnas alcanzan para ocho campos, así que
   se queda con el `.modal-box` de 520px del canon y sólo se le da aire vertical
   por si la pantalla es baja. */
#modal-cli .modal-box { max-height: 92vh; overflow-y: auto; }

/* §33C · `.table-fija` — LA GRILLA DE LECTURA, genérica.
   ⚠️ Extraída de `.table-clientes` (§32.11) sin cambiarle una propiedad: son
   las MISMAS dos reglas, con otro selector. Si Clientes se ve distinto después
   de esta extracción, la extracción está mal, no la pantalla.

   CUÁNDO SE PONE, y no es "en toda grilla migrada a modal": `fixed` sólo es
   correcto si TODAS las columnas declaran ancho y suman 100% — con una columna
   sin declarar, el navegador le da lo que sobre y `td{overflow:hidden}` la
   recorta en vez de ensancharla (el bug de 6d9c287, explicado en style.css:208).
   Y sólo aporta algo si alguna columna TIENE que elipsizar: en layout automático
   el navegador ensancha la columna para que entre el texto, así que un
   `text-overflow` declarado no llega a aplicarse nunca.

   Por eso Clientes la lleva (un email de 64 caracteres no cabe en ninguna
   grilla) y §33C.1 NO se la puso a Ítems: sus cuatro columnas de datos entran
   holgadas y `fixed` sólo le agregaría una forma nueva de romperse.

   `.trunc` va en el `<td>` que puede cortar, y va SIN `title`: el valor completo
   vive en el modal, y un tooltip no existe en táctil, no se descubre y no se
   puede copiar (el criterio de §32.5). */
.table-fija { table-layout: fixed; }
.table-fija td.trunc { white-space: nowrap; text-overflow: ellipsis; }

/* §33C.2 · `.card-header` — la regla 1 en una pantalla con VARIAS tablas.
   La regla dice que el alta va «en el header», y el motivo escrito es que la
   ventana de Opi no scrollea: un alta al pie de la tabla queda fuera de vista
   apenas hay filas. En Ítems o Proveedores «el header» es el de la PÁGINA,
   porque hay una sola tabla. Configuración tiene CUATRO en el mismo documento,
   y cuatro botones «+ agregar» en el encabezado de la página no dirían a qué
   tabla pertenece cada uno.
   Así que el header de cada tabla es el de SU card: el <h2> y el botón en la
   misma línea. Se cumple el propósito de la regla —el alta arriba, a la vista,
   junto a lo que da de alta— y no se inventa un patrón nuevo: es el mismo
   `.page-header` una jerarquía más abajo. */
.card-header { display: flex; align-items: center; justify-content: space-between;
               gap: 12px; margin-bottom: 16px; }
.card-header h2 { margin-bottom: 0; }

/* §32.11 · La grilla de Clientes entra en `table-layout: fixed`, y cumple la
   condición que pide el comentario de más arriba: sus NUEVE columnas declaran
   ancho —la de acciones INCLUIDA— y suman 100%.

   ⚠️ Esto NO reintroduce el bug de 6d9c287. Aquel era `fixed` con la columna de
   acciones SIN declarar: se llevaba el % que sobrara (16% ≈ 208px) para unos
   botones de ~245px fijos y, con `td { overflow:hidden }`, los recortaba en vez
   de ensancharse — «Eliminar» quedaba cortado. Declararla elimina la causa, no
   la disimula. Hoy la celda contiene un solo `⋯` de 18px y el 5% le da 68px.
   Y el arnés lo vigila: `verifica_b32_contacto` [8] asserta que la columna de
   acciones recibe su ancho declarado.

   `fixed` es además lo que hace que la elipsis FUNCIONE: en layout automático
   el navegador ensancha la columna para que entre el texto, así que un
   `text-overflow` no llega a aplicarse nunca.

   §33C · ⚠️ ACÁ VIVÍAN `.table-clientes { table-layout: fixed }` y
   `.table-clientes td.trunc { … }`. Se fueron a `.table-fija` (más arriba), sin
   cambiarles nada, el día que una SEGUNDA grilla las necesitó: dos copias de la
   misma regla son dos oportunidades de que se desincronicen, y es el mismo
   movimiento que §23 hizo con `menu-fila.js`.

   `table-clientes` SIGUE en el markup de la grilla, y a propósito: quedó sin
   ninguna regla CSS propia, pero es el ancla de tres asserts
   (`verifica_b32_contacto` [8][9] y `verifica_b26_acciones` [11], que hacen
   `querySelector('table.table-clientes')`). Sacarla del `<table>` habría puesto
   dos arneses en rojo sin que nada estuviera mal — un falso rojo enseña a
   ignorar el arnés. Es una clase de IDENTIDAD, no de estilo. */

/* §32.11 · «No cargado» se dibuja «—», no vacío: una celda en blanco se lee como
   un renderizado que falló. Es el patrón que la columna TC ya usaba; acá se le
   puso nombre para que las tres digan lo mismo de una sola definición. */
.sin-dato { color: #9ca3af; }

/* §33B · «Cuánto vale el proyecto»: las cuatro magnitudes, arriba de la barra.
   Va ARRIBA y no cerrando la tabla porque la ventana de Opi no scrollea —
   scrollea la tabla por dentro—, así que un bloque debajo queda fuera de vista
   apenas hay líneas. Es el mismo error que §24.4.f arregló con el alta. */
.valor-proyecto { background: var(--surface); border: 1px solid var(--border);
                  border-radius: 8px; padding: 10px 14px; margin-bottom: 8px; }
.valor-proyecto-rot { display: block; font-size: 10px; font-weight: 700;
                      letter-spacing: .04em; text-transform: uppercase;
                      color: var(--text-muted); margin-bottom: 6px; }
.vp-cifras { display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
.vp-item { display: flex; flex-direction: column; gap: 1px; }
.vp-et { font-size: 11px; color: var(--text-muted); }
.vp-item strong { font-size: 15px; font-weight: 700; color: var(--text); }
.vp-nota { font-size: 10.5px; color: #9ca3af; }
/* El operador entre sumandos: la cuenta se lee, no se deduce. */
.vp-op { font-size: 15px; color: #9ca3af; align-self: center; padding-top: 10px; }
/* El total NO es un sumando más: se separa y pesa. */
.vp-total { border-left: 2px solid var(--brand); padding-left: 12px; margin-left: 2px; }
.vp-total strong { font-size: 17px; color: var(--brand-strong); }
@media (max-height: 820px) { .valor-proyecto { padding: 7px 12px; margin-bottom: 6px; } }

/* RONDA 2 · El pie de segundo plano DENTRO del bloque de valor: fecha del
   presupuesto y TC sugerido. Antes era `.presup-barra`, una franja propia con
   caja, borde y rótulos del mismo tamaño que las cifras de arriba — o sea, dos
   cosas de peso distinto dibujadas igual. Acá va más chico, separado por una
   línea fina, y ocupa el ancho entero del bloque. */
.vp-pie { flex: 0 0 100%; display: flex; align-items: baseline; gap: 18px;
          flex-wrap: wrap; margin-top: 6px; padding-top: 6px;
          border-top: 1px solid var(--border); font-size: 12px; }
.vp-pie-rot { font-size: 10px; color: #6b7280; text-transform: uppercase;
              letter-spacing: .04em; margin-right: 4px; }
.vp-pie strong { font-size: 12px; font-weight: 600; }
/* Los dos bloques se leen como una unidad: el de arriba pierde el margen y el
   de abajo se pega. */
.valor-proyecto { margin-bottom: 6px; }

/* §33B · La acción de la landing: un control que se ve, no un link de texto.
   Un proyecto «sin armar» ofrece armarlo; uno armado, abrirlo. */
.btn-fila { display: inline-block; padding: 3px 10px; font-size: 12px;
            white-space: nowrap; text-decoration: none; border-radius: 6px;
            color: var(--brand-strong); border: 1px solid var(--border);
            background: var(--surface); }
.btn-fila:hover { border-color: var(--brand); background: #f0fdfa; }

/* ══ §35 · CARGA RÁPIDA (/codificacion/nueva) ═══════════════════════════════
   ⚠️ SIN SCROLL, y es el motivo por el que esto dejó de ser un modal: la
   ventana de Opi no scrollea (`html,body{overflow:hidden}`, style.css:25) y el
   `.modal-box` de §31 ya necesitaba `max-height:92vh; overflow-y:auto` para
   entrar. Si algo no entra acá, SE SACA — no se le pone `overflow`. */
.carga-scroll { display: flex; flex-direction: column; gap: 8px; }

/* La barra superior persiste al guardar (§35.1): cuenta · fecha · TC.
   §35.12 [4] · Padding de 10px→6px y label de la barra a 10px con menos
   separación: ~28px menos, en la fila que menos los necesitaba —cuenta, fecha y
   TC son tres campos cortos con rótulos de una palabra—. Sigue siendo cromo:
   las cajas de los inputs no se tocaron. */
.carga-barra { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap;
               background: var(--surface); border: 1px solid var(--border);
               border-radius: 10px; padding: 6px 14px; }
.carga-barra .form-group { min-width: 130px; }
.carga-barra label { font-size: 10px; margin-bottom: 2px; }
/* §26.4 · Con la moneda base el grupo del TC DESAPARECE, rótulo incluido. Lo
   esconde el JS con `hidden`; el input oculto sigue adentro y sigue posteando
   vacío, que es lo que el server espera para forzar tc = 1,00. */
.carga-barra-nota { margin-left: auto; align-self: center; }
.carga-persiste { font-size: 11px; color: var(--text-muted); white-space: nowrap; }

/* Las dos áreas (§35.2). Se apagan entre sí — el motor es §31.2. */
.carga-areas { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.carga-area { background: var(--surface); border: 1px solid var(--border);
              border-radius: 10px; padding: 10px 14px;
              transition: opacity .12s ease, filter .12s ease; }
.carga-area-h { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; }
.carga-area-t { font-size: 11px; font-weight: 700; text-transform: uppercase;
                letter-spacing: .05em; color: var(--brand-strong); }
.carga-area-h small { font-size: 11px; color: var(--text-muted); }
/* ⚠️ El área atenuada NO desaparece ni se mueve: queda donde estaba, para que
   la pantalla no cambie de forma mientras se carga (§31.2). Y sigue
   CLICKEABLE — insistir la reactiva; el automatismo sugiere, no decide. */
.carga-area.area-atenuada { opacity: .38; }
.carga-area.area-atenuada .carga-area-t { color: var(--text-muted); }

/* ⚠️ ESCONDER DE VERDAD — y las dos veces que esto NO alcanzó están acá.
   `n-proyecto` y `n-cliente` son los <select> nativos que el combinado escribe
   (§35.3): tienen que estar en el DOM y no se ven.

   1ª · `width:1px` NO daba 1px: `.form-group select` (style.css:110) le pone
        `padding:7px 10px` + borde, y con `box-sizing:content-box` el total era
        22px. Dos cajitas grises medibles, en medio del área. Por eso van
        `padding:0; border:0` y `box-sizing:border-box` — no alcanza con pedir
        el ancho, hay que sacarle lo que se le suma.
   2ª · Y esconder NO SACA DEL TAB (ARRANQUE §4): eso lo re-afirma
        `sacarEscondidosDelTab()` después de cada sync, porque `atenuar()` les
        devuelve `tabIndex = 0`. Las dos mitades hacen falta; ninguna sola sirve.
   La especificidad se sube a `select.carga-oculto` para ganarle a la regla de
   `.form-group select`, que es más específica que una clase sola. */
.carga-oculto,
select.carga-oculto,
input.carga-oculto { position: absolute; width: 1px; height: 1px; overflow: hidden;
                     clip: rect(0 0 0 0); white-space: nowrap;
                     padding: 0; border: 0; box-sizing: border-box; }
.carga-nota { display: block; margin-top: 4px; font-size: 11px; color: var(--text-muted); }
.carga-oblig { display: none; margin-top: 4px; font-size: 11px; color: #92400e; }
.carga-oblig.se-ve { display: block; }

/* §36 [E] · El pie de totales, UNA sola línea y chica.
   Antes eran tres celdas alineadas con columnas de la grilla; ahora es un
   renglón corrido, que es como se lee un total: de izquierda a derecha, de lo
   nativo a lo consolidado. `nowrap` + scroll propio para que una tercera moneda
   lo alargue en vez de partirlo en dos líneas. */
/* §37 [4] · Los totales arrancan bajo las columnas de importe y en la MISMA
   tipografía que la grilla — eran 11px, más chicos que las cifras que resumen,
   que es al revés de lo que uno espera de un total. `text-align:left` porque
   ahora la celda ya empieza donde tiene que empezar: alinear a la derecha los
   volvería a empujar contra el borde. */
/* §3x-ter · SE FUERON `.tot-linea`, `.tot-bloque` y `.tot-cons`: eran las tres
   del pie de UN RENGLÓN (§36 [E]) y con el pie en columnas no las usa nadie. Se
   borran en vez de quedar por si acaso — una regla huérfana que le pega a una
   clase que ya no existe es la que el próximo lector cree que está viva. */
.fila-total .tot-cuenta-cell { text-align: right; padding: 6px 8px;
                               color: var(--text-muted); }
.fila-total .tot-cuenta { color: var(--text-muted); margin-left: 10px;
                          font-size: 11px; font-weight: 400; }
.fila-total .tot-aviso { color: var(--orange); margin-left: 10px;
                         font-size: 11px; font-weight: 400; }

/* §36 [B]+[C] · Movimientos: título, contadores y «Filtrar» en UN renglón.
   Salió de sacar la tira de meses (§36 [A]): el título ya dice el mes activo, y
   con la tira afuera los tres bloques entran juntos. Lo que se gana son filas
   de movimientos visibles, que es todo el objetivo del bloque. */
.movs-cabecera { display: flex; align-items: center; gap: 14px;
                 flex-wrap: nowrap; margin-bottom: 8px; }
.movs-cabecera .page-header.ph-inline { margin: 0; padding: 0; border: 0;
                                        flex: 0 0 auto; }
.movs-cabecera .page-header.ph-inline h1 { white-space: nowrap; }
.movs-cabecera .chips-bar { margin: 0; flex: 1 1 auto; min-width: 0;
                            overflow-x: auto; }

/* ⚠️ EL PANEL DE FILTROS FLOTA, no empuja. Un `<details>` normal desplaza todo
   lo que tiene abajo al abrirse: acá eso serían ~5 filas de movimientos que
   desaparecen cada vez que alguien mira los filtros — justo lo que este bloque
   vino a recuperar. Con el cuerpo en `absolute` la grilla no se entera.
   El `position:relative` va en el <details> y no en `.movs-cabecera`, para que
   el panel se alinee con SU botón y no con el borde de la pantalla. */
.movs-cabecera .panel-filtros { flex: 0 0 auto; margin-left: auto;
                                position: relative; }
.movs-cabecera .panel-filtros .pf-cuerpo {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  /* ⚠️ EL ANCHO NO ES DECORATIVO: los SEIS combos de Movimientos tienen que
     entrar en UN renglón — es la garantía de §30, que sacó 245px de barra
     poniéndolos juntos, y `verifica_b27` [2] la mide comparando sus `top`.
     Con 820px caían a dos renglones y el arnés se puso rojo: el panel flotante
     había reintroducido, por el ancho, el problema que §30 arregló. */
  min-width: min(1180px, 94vw); background: var(--surface);
  border: 1px solid var(--border); border-radius: 10px; padding: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
}

/* §35.12 [6] · El equivalente en la moneda base, debajo del importe. Sólo
   lectura y sólo cuando la moneda NO es la base — en U$S no se dibuja, así que
   el caso más común no paga alto de pantalla ([4]).
   `text-align:right` para que el número quede bajo el número, no bajo el
   rótulo: se lee comparándolo con el importe de arriba. */
.carga-equiv { margin-top: 3px; font-size: 11px; color: var(--text-muted);
               text-align: right; white-space: nowrap; }

/* §35.12 [5] · El acuse de recibo de «Guardar y seguir». Va A LA IZQUIERDA de
   los botones y no como cartel flotante: un toast que aparece y se va no se
   distingue de un parpadeo, y el operador que dudaba de si había guardado
   necesita algo que SIGA ahí cuando vuelva a mirar. */
.carga-contador { margin-right: auto; font-size: 12px; color: #15803d;
                  align-self: center; }
.carga-contador a { color: var(--brand-strong); margin-left: 6px; }

/* §35.12 [5] · La fila recién cargada, al volver de la pantalla de carga.
   El fondo se desvanece en 6s: la marca tiene que durar lo suficiente para
   encontrarla y no tanto como para quedar confundida con un estado de la fila
   —una fila permanentemente verde diría algo sobre el movimiento, no sobre
   cuándo se cargó—. El borde izquierdo NO se desvanece con el fondo por la
   misma razón que el `no-store` de §703e1ea: lo que ubica tiene que seguir
   ubicando aunque el operador vuelva a mirar diez segundos después. */
@keyframes fila-recien-fade {
  from { background: #dcfce7; }
  to   { background: transparent; }
}
tr.fila-recien > td { animation: fila-recien-fade 6s ease-out forwards; }
tr.fila-recien > td:first-child { box-shadow: inset 3px 0 0 var(--brand); }

.carga-aviso { font-size: 12px; color: #92400e; background: #fffbeb;
               border: 1px solid #fde68a; border-radius: 6px; padding: 6px 10px; }
.carga-camino-nota { min-height: 15px; }
.carga-camino-nota small { font-size: 11px; color: var(--text-muted); }

.carga-comun { background: var(--surface); border: 1px solid var(--border);
               border-radius: 10px; padding: 10px 14px;
               display: grid; grid-template-columns: 220px 1fr; gap: 10px 12px; }
/* §54 · El detalle y los dos números de comprobante COMPARTEN UNA FILA. Puestos
   en fila propia, «Guardar» dejaba de entrar sin scrollear a 1366x600 y
   `verifica_b35 [4]` se ponía rojo: una fila de `.carga-comun` cuesta ~52px y el
   margen que §35 había medido eran 25. El detalle se lleva el doble de ancho
   porque es el que se lee de un vistazo; los números son de consulta puntual. */
.carga-detalle { grid-column: 2 / -1; display: grid;
                 grid-template-columns: 2fr 1fr 1fr; gap: 10px 12px; }
/* §35.5 · INGRESO a la izquierda, EGRESO a la derecha. Escribir en una vacía la
   otra: el signo es en cuál escribiste, no una segunda pregunta. */
.carga-importes { grid-column: 1 / -1; display: grid;
                  grid-template-columns: 1fr 1fr; gap: 12px; max-width: 460px; }
.lbl-ingreso { color: var(--green); }
.lbl-egreso  { color: var(--red); }
.carga-flags { grid-column: 1 / -1; display: flex; gap: 18px; align-items: flex-end;
               flex-wrap: wrap; }
.carga-flag { display: flex; align-items: center; gap: 8px; font-size: 13px;
              color: var(--text); text-transform: none; font-weight: 500; }
/* Un flag vedado se ATENÚA con la razón a la vista, no desaparece: un control
   que se esfuma no enseña por qué (§31). */
.carga-flag.vedado { opacity: .45; }
.carga-veda { font-size: 11px; color: #92400e; }
.carga-acciones { display: flex; justify-content: flex-end; gap: 8px; }

/* §35.7 · EL RESUMEN DEL PAGO — lo que queda en la pantalla cuando el panel se
   fue al modal. Es la contrapartida obligatoria de esa mudanza: sin él el
   egreso queda bloqueado en un número sin nada que diga de dónde salió. Son
   ~30px contra los 418 del panel, y el «cambiar» es la puerta de vuelta. */
.carga-pago-resumen { grid-column: 1 / -1; display: flex; align-items: center;
                      justify-content: space-between; gap: 12px; font-size: 13px;
                      color: #92400e; background: #fffbeb; border: 1px solid #fde68a;
                      border-radius: 6px; padding: 6px 10px; }

/* §35.7 · El modal de pago es ANCHO (la tabla de entregas tiene 5 columnas) pero
   NO alto: la lista ya se acota sola con `.pago-entregas`. */
#modal-pago .modal-box { max-height: 88vh; overflow-y: auto; }
@media (max-width: 900px) { #modal-pago .modal-box { width: auto; max-width: 94vw; } }

@media (max-width: 1100px) {
  /* §35.7 · En celular las dos áreas se APILAN, y ahí sí scrollea. */
  .carga-areas { grid-template-columns: 1fr; }
  .carga-comun { grid-template-columns: 1fr; }
  .carga-detalle { grid-template-columns: 1fr; }
  .carga-scroll { overflow-y: auto; }
}

/* §25.8 · El aviso de corte de los estados de cuenta. Va pegado al saldo que
   califica —no como cartel arriba— porque lo que tiene que quedar claro es a
   qué fecha corresponde ESE número, y un aviso lejos del número se lee una vez
   y se olvida. */
/* §45 · padding vertical 6px -> 4px: 26px -> 22px. Es UN renglón de texto con su
   barra de color; el borde izquierdo es lo que lo hace visible, no el aire. */
.corte-aviso { font-size: 12px; color: #374151; background: var(--bg);
               border-left: 3px solid var(--brand); border-radius: 4px;
               padding: 4px 10px; margin-bottom: 12px; }
.corte-aviso .corte-post { color: var(--orange); margin-left: 4px; }

/* §37 [3] · El tick de estado. La palabra al lado NO es decoración: un checkbox
   sin marcar significa «pendiente», y sin el rótulo se lee como «vacío». */
.tick-estado { display: inline-flex; align-items: center; gap: 5px;
               font-size: 12px; cursor: pointer; }
.tick-estado input { width: 15px; height: 15px; accent-color: var(--brand);
                     cursor: pointer; }

/* §37 [5] · «+ Nuevo movimiento» en la fila fantasma. Era un link gris que se
   leía como nota al pie en la pantalla donde cargar ES la acción principal. */
.btn-fila-nueva { display: inline-block; text-decoration: none;
                  font-weight: 600; color: var(--brand-strong);
                  padding: 4px 10px; border-radius: 6px;
                  border: 1px dashed var(--brand); }
.btn-fila-nueva:hover { background: var(--bg); }

/* §38 [d] · PRESUPUESTO, COMPACTADO. Medido: 248px de cromo antes de la primera
   fila, sobre filas de 25px — diez líneas que no se veían. Lo que se recorta es
   CROMO (rótulos en renglón propio, cajas apiladas que podían compartir fila),
   no información: no desaparece ningún número ni ninguna nota. */
.presup-titulo { display: flex; align-items: center; gap: 16px;
                 flex-wrap: nowrap; margin-bottom: 6px; }
.presup-titulo .page-header.ph-inline { margin: 0; padding: 0; border: 0;
                                        flex: 0 0 auto; }
.presup-titulo .page-header.ph-inline h1 { white-space: nowrap; }
.presup-titulo .filtros-form { margin: 0; flex: 0 1 auto; min-width: 0; }
/* §39 [3] · El alta al extremo derecho del renglón, separada del título y del
   selector. Dentro del `page-header` quedaba pegada al h1. */
.presup-titulo #btn-agregar-linea { margin-left: auto; flex: 0 0 auto; }

/* §39 [1] · El alta de Movimientos, en el mismo renglón que el título y los
   contadores. `margin-left:auto` la empuja al extremo, y «Filtrar» queda a su
   derecha — el mismo orden que en Presupuesto: primero lo que crea, después lo
   que acota. */
.movs-cabecera #btn-abrir-modal { margin-left: auto; flex: 0 0 auto; }
.movs-cabecera .panel-filtros { margin-left: 8px; }

/* «Cuánto vale el proyecto», compacto. RONDA 2 · La barra de fecha/TC ya no es
   un bloque hermano: se absorbió como pie del mismo recuadro. */
/* ⚠️ ACÁ SE INTENTÓ QUE LOS DOS BLOQUES COMPARTIERAN RENGLÓN, Y NO ENTRABAN:
   medido a 1512px, con `wrap` se apilaban igual y con `nowrap` subían a 112px.
   RONDA 2 lo resolvió por el otro lado — no fusionando las dos cajas en un
   renglón sino METIENDO la de abajo adentro de la de arriba, como pie de
   segundo plano. El wrapper `.presup-cabecera` ya no existe en el HTML. */

/* El rótulo del bloque deja de gastar un renglón propio: va inline con las
   cifras. Sigue en mayúsculas y con color de rótulo, así se lee como título de
   grupo y no como una etiqueta más de la fila. */
.valor-proyecto { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.valor-proyecto-rot { display: inline; margin-bottom: 0; flex: 0 0 auto;
                      max-width: 92px; line-height: 1.15; }
/* Las cifras pasan de dos niveles (etiqueta arriba / número abajo) a uno. */
.vp-item { flex-direction: row; align-items: baseline; gap: 5px; }
.vp-item strong { font-size: 14px; }
/* RONDA 2 · `.presup-barra` se fue: sus dos datos viven ahora en `.vp-pie`,
   dentro del bloque de valor. Las reglas que la compactaban se van con ella. */

/* ══════════════════════════════════════════════════════════════════════════
   §45 · EL RITMO VERTICAL DE LOS CUATRO ESTADOS DE CUENTA
   ══════════════════════════════════════════════════════════════════════════
   Medido a 1512×800: Proveedor tenía 400px de cromo antes de la primera fila,
   sobre filas de 23px. De esos 400, **88px eran margin-bottom entre bloques** —
   casi cuatro filas regaladas sin que ningún bloque muestre un dato menos.

   ⚠️ POR QUÉ VA SCOPEADO Y NO SE TOCAN LAS REGLAS GLOBALES. Cuatro de los siete
   bloques son COMPARTIDOS: `.filtros-form` está en 6 templates,
   `.desc-plegable` en 9, `.stats-bar` en 7 y `.page-header.ph-compacto` en casi
   todos. Bajarles el margen en la hoja movería una docena de pantallas que
   nadie auditó. Acá se cambia sólo el ESPACIO ENTRE ELLOS cuando están dentro de
   un estado de cuenta; el alto de cada bloque, y su margen en el resto de la
   app, quedan exactamente como estaban.

   ⚠️ Y NO SE FUSIONA NADA. §38.4 lo midió en Presupuesto y salió PEOR (112px
   contra 92px apilados): cuatro cifras con sus rótulos no entran en un renglón,
   y forzarlas las envuelve por dentro. El ahorro sale de compactar cada bloque
   y el aire entre ellos, no de juntarlos. La idea es tentadora y vuelve sola.

   El criterio del ritmo, para que no vuelva a ser siete valores distintos:
     · 4px  entre el título y su sub-nav — son la misma cosa, un rótulo y sus
            pestañas, y separarlos los hacía leer como dos bloques.
     ·8px   entre bloques de control (sub-nav, selector, toggle, aviso).
     · 6px  antes del desplegable de ayuda, que ya está cerrado y pesa poco.
     · 10px antes de la grilla y de los stats — el único lugar donde el aire
            hace trabajo: separa los CONTROLES de los DATOS.
   Sigue habiendo jerarquía; lo que se fue es la repetición.                  */
.est-compacto > .page-header.ph-compacto { margin-bottom: 4px; }
.est-compacto > .tab-bar                 { margin-bottom: 10px; }
.est-compacto > .filtros-form            { margin-bottom: 8px; }
.est-compacto > .filter-segmented        { margin-bottom: 8px; }
.est-compacto > .corte-aviso             { margin-bottom: 8px; }
.est-compacto > .desc-plegable           { margin-bottom: 6px; }
/* El bloque de `.stats-bar` NO se toca —59px, 7 templates, y su compactación es
   una sesión propia—; lo único que cambia es cuánto aire lleva DEBAJO, y sólo
   dentro de un estado de cuenta. */
.est-compacto > .stats-bar               { margin-bottom: 10px; }

/* §46 · El SENTIDO del saldo del proveedor, al lado de la cifra.
   ⚠️ VA INLINE, DENTRO de `.stat-value`, y eso no es una preferencia: como
   hermano —un tercer renglón del `.stat`— le costaba 15px A LOS SEIS recuadros,
   porque `.stats-bar` es flex con `align-items: stretch` y estira todos a la
   altura del más alto. Un inline de 11px cabe en la caja de línea de los 18px y
   no agranda nada. El color lo HEREDA de `.stat-value.red` / `.green`: una
   cifra y su palabra que no compartieran color serían dos datos, no uno. */
.stat-sentido { font-size: 11px; font-weight: 500; margin-left: 6px;
                letter-spacing: .01em; }
/* «al día» no tiene color propio: es la ausencia de deuda en las dos
   direcciones, y pintarlo lo pondría al nivel de los otros dos estados. */
.stat-sentido.mudo { color: var(--text-muted); }

/* ══════════════════════════════════════════════════════════════════════════
   RONDA 2 · EL RESUMEN DEL PEDIDO — una franja fina, no cuatro recuadros
   ══════════════════════════════════════════════════════════════════════════
   Reemplaza a la `.stats-bar` de cuatro `.stat` que ocupaba una franja entera
   arriba y dejaba el formulario apretado abajo. Y evita de raíz la trampa de
   §46: acá NO hay `align-items: stretch` ni recuadros que se estiren entre sí —
   es texto inline, así que agregarle una referencia a una cifra no le crece la
   altura a las otras tres. */
.pedido-resumen { display: flex; align-items: baseline; gap: 20px; flex-wrap: wrap;
    padding: 6px 14px; margin-bottom: 8px; background: var(--surface);
    border: 1px solid var(--border); border-radius: 8px; font-size: 13px; }
.pedido-resumen > span { display: flex; align-items: baseline; gap: 5px; }
.pr-rot { font-size: 10px; color: #6b7280; text-transform: uppercase;
          letter-spacing: .04em; }
.pedido-resumen strong { font-size: 14px; font-weight: 700; color: var(--text); }
.pr-azul    { color: var(--brand-strong) !important; }
.pr-naranja { color: var(--orange) !important; }
/* La plata se separa de las cosas con una línea, no con otra caja. */
.pr-plata { margin-left: auto; padding-left: 16px;
            border-left: 1px solid var(--border); }
.pr-plata strong { font-size: 13px; font-weight: 600; }
/* El aviso de «sin unidades» ocupa el lugar de las tres cifras, no una franja
   aparte: es la RESPUESTA a la pregunta que las cifras no pueden contestar. */
.pr-aviso { font-size: 12px; color: #92400e; max-width: 62ch; line-height: 1.35; }

/* ══ §65.4 · LA PANTALLA DEL PEDIDO EN UNA SOLA PASADA ══════════════════════
   El requisito de §65.4 no es estético: «una sola pantalla, todo visible sin
   scrollear». Lo que había medía tres alturas de fila muertas entre el título y
   el primer campo, los campos ocupaban un tercio del ancho con el resto vacío, y
   el bloque al que uno viene arrancaba pasados los 900px.

   ⚠️ EL PISO SON 1366×700, y es el piso a propósito: la pantalla de Dave es
   1920×1080, pero la gente de Opi puede estar en una notebook o con la ventana a
   medias. Si entra en 1366×700 entra en todas. Lo mide `verifica_b65_pantalla`
   en el navegador — un assert de contenido no puede ver esto. */

/* ⚠️ LA CLASE NO LLEVA EL NÚMERO. Era `.pedido-resumen-cols` y §6 la llevó a cinco
   (presupuestado · comprometido · entregado · adelantado · saldo): el layout es
   «N columnas iguales» con `flex: 1 1 0`, así que la cantidad nunca fue parte
   del diseño — sólo del nombre, que es como se rompe al agregar una. */
.pedido-resumen-cols { gap: 0; padding: 8px 0; }
.pedido-resumen-cols > .pn { flex: 1 1 0; display: block; padding: 0 14px;
    border-left: 1px solid var(--border); }
.pedido-resumen-cols > .pn:first-child { border-left: none; }
/* ⚠️ La plata en bloque y las unidades DEBAJO, no al lado: es lo que separa las
   dos naturalezas que la barra vieja mezclaba en la misma línea. */
.pedido-resumen-cols .pr-rot { display: block; margin-bottom: 1px; }
.pedido-resumen-cols strong { display: block; font-size: 14px; line-height: 1.15; }
/* §6.5 · ⛔ ACÁ VIVÍA `.pn-sub`, EL TERCER RENGLÓN. Pasó al `title` del número
   (28-ago-2026): costaba ~15px en los CINCO —en un flex, el más alto le fija la
   altura a todos— para una nota que sólo dos usan. La regla se queda escrita
   porque el criterio no cambió: si algún día vuelve un tercer dato PERMANENTE a
   esta barra, va en bloque y no al lado. */
/* La marca de que hay más: sin ella, el `title` es un dato que nadie descubre. */
.pn-tip strong { border-bottom: 1px dotted var(--border); cursor: help; }
.pn-azul strong    { color: var(--brand-strong); }
.pn-naranja strong { color: var(--orange); }

/* ══ §6 · LA BARRA DEL ACTO — rótulo ARRIBA, no en columna propia ══════════
   ⚠️⚠️ REEMPLAZA A `.cierre-grid` EN LA PANTALLA DEL PEDIDO, y el motivo salió de
   medir: la grilla de tres columnas costaba 197px para cinco campos cortos, y §6
   le sumó a esa pantalla la tabla de líneas entera. El `label` en columna fija de
   108px era el gasto — con el rótulo arriba, en 11px, los cinco entran en dos
   renglones y nada se esconde.
   `.cierre-grid` SE QUEDA: la usan otras pantallas del mismo bloque. */
.acto-bar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 18px;
    padding: 8px 14px; border-top: 1px solid var(--border); }
.ab-grupo { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 6px 12px; }
.ab-tit { flex: 1 0 100%; font-size: 10px; font-weight: 700; color: #6b7280;
    text-transform: uppercase; letter-spacing: .04em; }
.ab-tit em { font-weight: 400; text-transform: none; letter-spacing: 0; }
.ab-campo { display: flex; flex-direction: column; gap: 2px; }
.ab-campo > span { font-size: 11px; color: #4b5563; }
.ab-acciones { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.ab-pie { font-size: 11px; color: #9ca3af; max-width: 32ch; }

/* ⚠️ LA FILA DE LA TABLA DE LÍNEAS LLEVA UN INPUT DE PLATA, y eso la estiraba a
   41px contra los ~30 de una fila de texto. Se aprieta el input, no la fila: el
   alto lo pone su padding. */
#tabla-lineas td { padding-top: 3px; padding-bottom: 3px; }
#tabla-lineas .money-wrap input, #tabla-lineas input[type="text"] { padding: 3px 6px; }
.btn-mini { padding: 2px 8px; font-size: 11px; }
.fila-renglon-cancelada { opacity: .55; }

/* El cierre y la agenda: tres columnas y una fila de acciones. */
.cierre-grid { display: grid; grid-template-columns: repeat(2, 1fr);
    gap: 0 18px; padding: 12px 14px; margin-bottom: 8px; }
.cg-col { border-left: 1px solid var(--border); padding-left: 14px; }
.cg-col:first-of-type { border-left: none; padding-left: 0; }
.cg-tit { font-size: 10px; font-weight: 700; color: #6b7280;
    text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px; }
.cg-fila { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
.cg-fila > label { flex: 0 0 108px; font-size: 12px; color: #4b5563; }
.inp-fecha, .inp-sel, .inp-txt { padding: 5px 8px; border: 1px solid #e0e3e8;
    border-radius: 6px; font-size: 13px; max-width: 100%; }
.inp-sel, .inp-txt { min-width: 120px; }
.cg-nota { font-size: 11px; color: #6b7280; line-height: 1.4; margin-top: 4px; }
.cg-alerta { color: #9a3412; }
/* Las acciones cruzan las tres columnas: los dos botones son del acto entero. */
.cg-acciones { grid-column: 1 / -1; display: flex; align-items: center; gap: 10px;
    margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.cg-pie { font-size: 11px; color: #9ca3af; max-width: 44ch; }
.cg-adelantos { grid-column: 1 / -1; margin-top: 8px; padding-top: 8px;
    border-top: 1px dashed var(--border); font-size: 12px; }
.cg-lista { margin: 4px 0 0; padding-left: 18px; color: #4b5563; font-size: 12px; }

@media (max-height: 760px) {
  /* ⚠️ EN EL PISO DE 700 EL AIRE SOBRA ANTES QUE EL CONTENIDO. Se aprieta el
     INTERLINEADO, y lo que NO se esconde es lo que §65.4 pide ver.
     Los números salieron de medir, no de estimar: 1044px de contenido en 648 de
     ventana era el punto de partida.

     ⚠️⚠️ QUÉ PROTEGE ESTA REGLA, EXACTAMENTE — corregido el 28-ago-2026.
     Acá decía «NO se esconde NADA», en general, y era más ancho que el requisito
     que cita: lo que §65.4 punto 4 exige tener a la vista son SUS PUNTOS (a) y
     (b) —(a) proveedor → proyecto → ítem con lo presupuestado; (b) el pedido:
     unidades · precio unitario · total—, que desde §66/§6 paso 1 viven en la
     TABLA DE LÍNEAS. Ésos no se colapsan ni se achican: son a lo que uno viene.

     Lo que SÍ se puede plegar es lo que no está en esa lista y no se consulta a
     diario: moneda/TC, fecha y descripción, que son campos de ALTA (§6.5). Hoy
     ni siquiera se pliegan: viven en la fila del título (`.ph-datos`), o sea que
     están MÁS a la vista que cuando esta regla se escribió. La diferencia no es
     de grado — es entre RECLASIFICAR un campo y COMPRIMIR la pantalla
     escondiendo lo que hace falta ver, que sigue prohibido.

     ⛔ Dicho en general, este comentario se leía como un veto a cualquier
     plegado, y un veto sin su alcance obliga al próximo a elegir entre
     desobedecerlo sin argumento o dejar de arreglar la pantalla. */
  .cierre-grid { padding: 7px 14px; gap: 0 16px; }
  .cg-fila { margin-bottom: 2px; }
  .cierre-grid .cg-nota { margin-top: 2px; line-height: 1.3; }
  .cg-acciones { margin-top: 6px; padding-top: 6px; }
  .cg-adelantos { margin-top: 5px; padding-top: 5px; }
  .cg-lista { margin-top: 2px; }
  .acto-bar { padding: 5px 14px; gap: 6px 16px; }
  .ab-grupo { gap: 4px 10px; }
  #tabla-lineas td { padding-top: 1px; padding-bottom: 1px; }
  #form-lineas .card-header { margin-bottom: 4px; }
  .pedido-resumen-cols { padding: 4px 0; margin-bottom: 6px; }
  .pedido-resumen-cols strong { font-size: 13.5px; }
  /* §6.5 · ⚠️ `.card-compacta` NO ESTABA ACÁ, y son DOS en esta pantalla
     (Líneas y Entregas): su padding y su margen se cobraban enteros mientras
     todo lo de al lado ya estaba apretado. Es el aire que quedaba sin cosechar
     cuando se midió que sobraban 0px.

     ⚠️⚠️ §6.5-bis · TODAS ESTAS VAN ACOTADAS A `.pg-pedido`, Y ES UNA CORRECCIÓN.
     Se escribieron con selectores GLOBALES —`.table-densa td`, `.card-header`,
     `.card.card-compacta`, `.page-scroll`— así que apretaron DIEZ pantallas en
     vez de esta una: Presupuesto, Clientes, Proveedores, Proyectos, los tres
     estados de cuenta, Adelantos, IVA y Configuración.
     Lo destapó la SUITE COMPLETA, no el área: `ui_b23_menu` necesita que
     Proyectos DESBORDE para probar que el menú flotante se cierra al scrollear,
     y con 4px menos por fila —15 filas, 60px— la página dejó de desbordar. El
     arnés tenía escrito ese riesgo: «el día que la tabla se acorte el test daría
     verde sin haber probado nada», y por eso falla en vez de callarse.
     LECCIÓN: una regla de alto pensada para UNA pantalla se acota a esa
     pantalla. La media query dice CUÁNDO, no A QUÉ. */
  .pg-pedido .card.card-compacta { padding: 8px 14px; margin-bottom: 8px; }
  .pg-pedido .card.card-compacta h2 { margin-bottom: 6px; }
  .pg-pedido .card-header { margin-bottom: 6px; }
  /* La tabla de ENTREGAS usa `.table-densa` genérica: `#tabla-lineas` ya tenía
     su override a 1px y ésta no, así que pagaba 3px por fila sin motivo. */
  .pg-pedido .table-densa td { padding-top: 1px; padding-bottom: 1px; }
  .pg-pedido .table-densa th { padding-top: 4px; padding-bottom: 4px; }
  /* El marco de la página: 20px arriba y abajo en una pantalla que pelea por
     unidades. No baja a 0 — sin margen el contenido se pega al borde y se lee
     peor, que es cambiar un problema por otro. */
  .page-scroll.pg-pedido { padding-top: 12px; padding-bottom: 12px; }
  /* §6.5 · ⛔ ACÁ SE APRETABA `.pedido-datos` y su fila de estado/eliminar. Los
     dos se fueron: la card entera subió a la fila del título y las acciones al
     header, así que no queda nada que apretar acá. */
  /* §6.5 · ⛔ ACÁ TENÍA CUATRO REGLAS PARA `.ph-datos`/`.ph-pedido` Y ESTABAN
     MUERTAS: sus reglas base se escribieron MÁS ABAJO en este archivo, después
     de esta media query, y con la misma especificidad gana la última — o sea la
     base, aunque no sea de media query. Tres mediciones seguidas dieron el mismo
     número y el CSS parecía no aplicarse.
     Los valores viven ahora en el bloque base, que es donde pueden ganar. La
     lección es del archivo, no de esta pantalla: una media query sólo pisa lo
     que está ANTES. */
  .page-header.ph-compacto { margin-bottom: 6px; }
}

/* §6.5 · ⛔ ACÁ VIVÍA EL BLOQUE `.pedido-datos` —la card de datos del pedido con
   la densidad de `.modal-ancho`—. Se fue con la card (28-ago-2026): sus tres
   campos subieron a la fila del título (`.ph-datos`, más arriba). Se borra en vez
   de quedar huérfano: CSS que no selecciona nada no documenta una decisión, hace
   creer que algo se sigue estilando.

   Lo que SÍ hay que conservar de ese bloque es la razón por la que sus campos se
   podían mover, y vive en dos lugares que siguen vivos: el comentario de
   `.ph-datos` y el de la media query de abajo. */
.pd-nota { margin: 6px 0 0; font-size: 11px; color: #6b7280; line-height: 1.3; }

/* ══ §6.5 · LA FILA DEL TÍTULO DEL PEDIDO ══════════════════════════════════
   Título + datos editables + acciones. Reemplaza a la card `pedido-datos` Y al
   plegable que la sucedió por un día: los dos costaban una caja propia —borde,
   padding, margen— para tres campos que caben en una fila que ya existía.

   ⚠️⚠️ ENVUELVE A DOS FILAS, NO A UNA. A 1366px los tres campos más el título
   más los cuatro botones no entran en una línea, así que el contenedor es
   `flex-wrap` y el form de datos tiene `flex-basis:100%`: cae SOLO, completo y
   sin apretarse, en vez de estrujar los campos hasta hacerlos ilegibles. Es una
   decisión medida, no una preferencia — a lo ancho la pantalla ya desborda 79px
   por la nav global (ver el arnés), y sumarle campos comprimidos empeoraría eso.
   A pantallas más anchas la segunda fila sigue existiendo: previsible es mejor
   que una fila que se parte sola según el largo de la descripción. */
/* ⚠️ `row-gap` CHICO Y NO 6px, y el número salió de un assert: con la fila de
   datos adentro el header empujaba la tira de cinco números a `bottom = 200`, y
   `ui_b65` [2] exige `< 200` —«es una BARRA, no una lista que hay que ir a
   buscar»—. El umbral NO se toca: subirlo sería cambiar la promesa. */
.ph-pedido { flex-wrap: wrap; row-gap: 2px; }
.ph-pedido > h1 { margin-right: auto; }
.ph-acciones .ph-btns { display: flex; align-items: center; gap: 6px; }
.ph-acciones .ph-btns form { display: inline; margin: 0; }
.btn-hdr { padding: 4px 12px; font-size: 12px; }
.ph-datos .btn-hdr { padding: 3px 12px; }
/* Un hueco, no una línea: separa «Eliminar» —el único irreversible— de los dos
   reversibles, sin agregar un borde más a una fila que ya tiene botones. */
.hdr-sep { width: 10px; }

/* La segunda fila: los datos del pedido, en línea y siempre editables. */
.ph-datos { flex: 1 0 100%; display: flex; align-items: center; gap: 8px;
            margin: 0; }
/* ⚠️⚠️ RÓTULO EN LÍNEA, NO ARRIBA, Y EL MOTIVO ES UN ASSERT QUE SE PUSO ROJO.
   Apilados, cada campo medía dos renglones y la fila del título empujaba la tira
   de cinco números a 214px — `ui_b65` [2] exige que los cinco entren en los
   primeros 200px, o «no es una barra, es una lista que hay que ir a buscar».
   En línea, la fila entera mide lo que mide un input y la tira vuelve a subir.
   El umbral NO se tocó: subirlo sería cambiar la promesa, no arreglar nada. */
.phd { display: flex; align-items: center; gap: 6px; min-width: 0; }
.phd > span:first-child { font-size: 10px; color: #6b7280; text-transform: uppercase;
                          letter-spacing: .04em; white-space: nowrap; }
.phd input, .phd select { padding: 4px 8px; font-size: 12.5px;
    border: 1px solid #e0e3e8; border-radius: 6px; }
/* La descripción se queda con lo que sobre: es el único que puede ser largo. */
.phd-crece { flex: 1 1 auto; }
.phd-crece input { width: 100%; }
.ph-datos .fg-par { display: flex; gap: 6px; align-items: center; }
.ph-datos .fg-par > * { min-width: 0; }
/* Con los rótulos en línea, el botón se alinea solo: no hace falta `align-self`. */
.cg-ade { color: #4b5563; }

/* ══ §6.2 · «+ agregar renglón» en el detalle del pedido ═══════════════════ */
.ren-add { display: flex; align-items: center; gap: 12px; margin-top: 6px;
           flex-wrap: wrap; }
/* El aviso de que el pedido vuelve a «pendiente»: ámbar, porque pide leer antes
   de guardar — no rojo, porque no es un error ni frena nada (§3.4 de la doctrina
   de avisos: un aviso que suena a rechazo se lee como rechazo). */
.ren-add-aviso { font-size: 11px; color: #92400e; background: #fffbeb;
    border: 1px solid #fde68a; border-radius: 6px; padding: 3px 8px;
    line-height: 1.35; }
/* La fila nueva se distingue de las guardadas: mientras no se apriete «Guardar
   líneas» no existe en la base, y una fila que se ve igual que las demás invita
   a irse de la pantalla creyendo que quedó. */
#tabla-lineas tr.fila-nueva > td { background: #f0fdfa; }
.btn-quitar-renglon { background: none; border: none; cursor: pointer;
    color: #b91c1c; font-size: 16px; line-height: 1; padding: 2px 6px; }

/* §68 · La nota al pie de un campo de formulario: dice qué alcance tiene lo que
   el control decide. Nace con el tilde «Comisiona» del proveedor, que desde §68
   es la ÚNICA respuesta y antes era la última de tres. */
.fg-nota { display: block; margin-top: 3px; font-size: 10.5px; color: #6b7280;
           line-height: 1.35; }
