  :root{
    --paper:#f5f4f0; --surface:#ffffff; --line:#e4e2db; --line-2:#efeee9;
    --ink:#1a1d21; --ink-2:#6b6e76; --ink-3:#9a9ca2;
    --steel:#2a5b8c;
    --v:#1e8e5a; --v-bg:#e7f1ea; --v-ln:#cfe4d6;
    --a:#c07d10; --a-bg:#f7edd8; --a-ln:#ecdcb6;
    --r:#c33f38; --r-bg:#f6e4e2; --r-ln:#eccbc7;
    --mono:"SF Mono",ui-monospace,"Cascadia Code","JetBrains Mono",Menlo,Consolas,monospace;
    --sans:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
    --r-sm:6px; --r-md:10px; --sh:0 1px 2px rgba(26,29,33,.04),0 4px 16px rgba(26,29,33,.05);
  }
  *{box-sizing:border-box}
  /* `hidden` debe ganarle a cualquier display de clase (p.ej. .login-wrap{display:flex}),
     o el elemento "oculto" sigue ocupando su espacio. */
  [hidden]{display:none!important}
  html{-webkit-text-size-adjust:100%}
  body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--sans);
    font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased}
  .num{font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.01em}
  .eyebrow{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);font-weight:600}
  a{color:var(--steel);text-decoration:none}
  button{font-family:inherit}
  :focus-visible{outline:2px solid var(--steel);outline-offset:2px;border-radius:3px}

  /* ---- shell ---- */
  header{position:sticky;top:0;z-index:20;background:rgba(245,244,240,.86);
    backdrop-filter:saturate(1.2) blur(8px);border-bottom:1px solid var(--line)}
  .bar{max-width:1180px;margin:0 auto;padding:14px 24px;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
  .brand{font-weight:700;font-size:19px;letter-spacing:.02em}
  .brand b{color:var(--ink)} .brand span{color:var(--ink-3);font-weight:600}
  .who{margin-left:auto;display:flex;align-items:center;gap:12px;font-size:13px;color:var(--ink-2)}
  .who b{color:var(--ink)}
  .rolepill{border:1px solid var(--line);background:var(--surface);padding:3px 10px;border-radius:100px;font-size:12px}
  .linkbtn{appearance:none;border:0;background:none;color:var(--ink-2);cursor:pointer;font-size:13px;text-decoration:underline}
  .linkbtn:hover{color:var(--ink)}
  nav{max-width:1180px;margin:0 auto;padding:0 24px;display:flex;gap:4px;flex-wrap:wrap}
  .tab{appearance:none;background:none;border:0;padding:12px 4px;margin-right:20px;cursor:pointer;
    color:var(--ink-2);font-size:14px;font-weight:600;border-bottom:2px solid transparent;
    transition:color .15s,border-color .15s}
  .tab:hover{color:var(--ink)}
  .tab[aria-selected="true"]{color:var(--ink);border-color:var(--ink)}
  .tab .badge{display:inline-block;margin-left:6px;background:var(--r);color:#fff;border-radius:100px;
    font-size:11px;font-family:var(--mono);padding:1px 6px;vertical-align:1px}

  main{max-width:1180px;margin:0 auto;padding:28px 24px 80px}
  .view{display:none;animation:rise .35s ease both} .view.on{display:block}
  @keyframes rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

  .card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);box-shadow:var(--sh)}
  .pad{padding:20px 22px}
  h2.section{font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-2);
    font-weight:700;margin:34px 2px 12px}
  h2.section:first-child{margin-top:2px}

  /* ---- login ---- */
  .login-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
  .login{width:100%;max-width:360px;padding:32px}
  .login .brand{font-size:24px;margin-bottom:4px}
  .login p.lead{color:var(--ink-2);font-size:14px;margin:0 0 24px}
  .field{margin-bottom:14px}
  .field label{display:block;font-size:12.5px;font-weight:600;color:var(--ink-2);margin-bottom:6px}
  .field input{width:100%;border:1px solid var(--line);border-radius:var(--r-sm);padding:10px 12px;
    font-size:15px;font-family:inherit;color:var(--ink);background:var(--surface)}
  .field input:focus{outline:2px solid var(--steel);outline-offset:0;border-color:var(--steel)}
  .login .btn{width:100%;margin-top:6px;padding:11px}
  .login .err{color:var(--r);font-size:13px;margin-top:12px;min-height:18px}

  /* ---- selector de lote ---- */
  .lotebar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px}
  .lotesel{border:1px solid var(--line);background:var(--surface);border-radius:var(--r-sm);
    padding:8px 12px;font-size:14px;font-family:inherit;color:var(--ink);min-width:260px}
  .loteinfo{font-size:13px;color:var(--ink-2)}
  .loteinfo b{color:var(--ink);font-family:var(--mono)}

  /* ---- KPIs ---- */
  .kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
  .kpi{padding:18px 20px}
  .kpi .n{font-size:34px;font-weight:600;letter-spacing:-.02em;line-height:1}
  .kpi .l{color:var(--ink-2);font-size:13px;margin-top:8px}

  /* ---- río de confianza ---- */
  .river-card{margin-top:14px;overflow:hidden}
  .river-head{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;flex-wrap:wrap;margin-bottom:16px}
  .river-head p{margin:6px 0 0;color:var(--ink-2);max-width:52ch;font-size:14px}
  .river{display:flex;height:64px;border-radius:var(--r-sm);overflow:hidden;background:var(--line-2)}
  .seg{position:relative;display:flex;align-items:center;justify-content:center;color:#fff;
    font-weight:600;min-width:2px;width:0;transition:width 1.1s cubic-bezier(.22,1,.36,1)}
  .seg.v{background:var(--v)} .seg.a{background:var(--a)} .seg.r{background:var(--r)}
  .seg .sn{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:17px}
  .river-legend{display:flex;gap:22px;margin-top:14px;flex-wrap:wrap;font-size:13px;color:var(--ink-2)}
  .river-legend b{color:var(--ink)}
  .dot{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:7px;vertical-align:middle}
  .dot.v{background:var(--v)} .dot.a{background:var(--a)} .dot.r{background:var(--r)}
  .headline-verde{font-size:14px;color:var(--ink-2);text-align:right}
  .headline-verde b{display:block;font-family:var(--mono);font-size:30px;color:var(--v);font-weight:600;letter-spacing:-.02em}

  /* ---- precisión ---- */
  .two{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px}
  .prec-main{display:flex;gap:36px;align-items:flex-end;flex-wrap:wrap}
  .prec-main .big{font-family:var(--mono);font-size:40px;font-weight:600;letter-spacing:-.03em;line-height:1}
  .prec-main .u{color:var(--ink-2);font-size:13px;margin-top:6px}
  .delta{color:var(--v);font-weight:600;font-family:var(--mono);font-size:13px}
  .prec-sub{display:flex;gap:8px;margin-top:18px;flex-wrap:wrap}
  .chipm{border:1px solid var(--line);border-radius:100px;padding:5px 11px;font-size:12.5px;color:var(--ink-2)}
  .chipm b{color:var(--ink);font-family:var(--mono)}
  .note{color:var(--ink-3);font-size:12px;margin-top:16px;line-height:1.5}

  /* ---- barras ---- */
  .barrow{display:grid;grid-template-columns:130px 1fr 52px;align-items:center;gap:12px;margin:9px 0}
  .barrow .k{font-size:13px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .track{height:9px;background:var(--line-2);border-radius:100px;overflow:hidden}
  .fill{height:100%;background:linear-gradient(90deg,#3a6ea5,var(--steel));border-radius:100px;width:0;transition:width .9s cubic-bezier(.22,1,.36,1)}
  .barrow .val{font-family:var(--mono);font-size:12.5px;color:var(--ink-2);text-align:right}
  .barrow.pick{cursor:pointer;border-radius:6px}
  .barrow.pick:hover{background:#f0f4f8}
  .barrow.pick:hover .k{color:var(--steel)}

  /* ---- entrada: los meses donde queda trabajo ---- */
  /* Cada botón lleva su propio número, así que la fila entera se lee de un vistazo: dónde hay
     trabajo y cuánto. El `<input type="month">` que había aquí no podía decir ninguna de las dos
     cosas — pedía una fecha y la respuesta llegaba después. */
  .mesbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
  .mesbtn{appearance:none;border:1px solid var(--line);background:var(--surface);
    border-radius:var(--r-sm);padding:7px 12px;cursor:pointer;text-align:left;
    display:flex;flex-direction:column;gap:2px;min-width:106px}
  .mesbtn:hover{border-color:var(--ink-3)}
  .mesbtn[aria-pressed="true"]{border-color:var(--steel);box-shadow:inset 0 0 0 1px var(--steel)}
  .mesbtn-m{font-size:13px;font-weight:600;color:var(--ink)}
  .mesbtn-n{font-size:11.5px;color:var(--ink-2)}
  .mesbtn[aria-pressed="true"] .mesbtn-n{color:var(--steel)}
  /* El desplegable va vestido como los botones que tiene al lado: sin estilo propio, el select
     nativo sale gris sobre una fila de botones blancos y parece de otra pantalla. */
  .mesatras{min-width:210px;border:1px solid var(--line);border-radius:var(--r-sm);
    padding:7px 10px;font-size:13px;font-family:inherit;background:var(--surface);color:var(--ink)}
  /* Los meses que el cruce con NetSuite no puede verificar. Se distinguen a la vista y no solo
     por el rótulo: es lo que separa «aquí falta trabajo» de «esto quizá ya está contabilizado»,
     y esa diferencia vale un asiento duplicado. El ámbar es el de la paleta —definido en los dos
     temas—, no un literal: en oscuro, un amarillo fijo sobre fondo #15 no se lee. */
  .mesciego{border-color:var(--a-ln);background:var(--a-bg);color:var(--a)}

  /* El aviso del mes sin verificar. Va con sus cifras dentro (cuántas facturas no ve el cruce y
     hasta cuándo llega el histórico): un aviso que no se puede evaluar se ignora a la segunda. */
  .aviso{margin-top:12px;border:1px solid var(--a-ln);background:var(--a-bg);
    border-radius:var(--r-md);padding:12px 14px}
  .aviso-t{font-size:13.5px;font-weight:650;color:var(--a)}
  .aviso-c{margin-top:5px;font-size:13px;color:var(--ink-2);line-height:1.55}
  .aviso-c b{color:var(--ink);font-variant-numeric:tabular-nums}
  .aviso-ok{margin-top:10px;display:flex;gap:8px;align-items:flex-start;
    font-size:13px;color:var(--ink);cursor:pointer}
  .aviso-ok input{margin:2px 0 0;flex:none;accent-color:var(--a)}

  /* ---- entrada ---- */
  .card.drop{border:2px dashed var(--line);cursor:pointer;text-align:center;padding:52px 24px;transition:border-color .15s,background .15s}
  .card.drop.drag{border-color:var(--steel);background:#eef3f8}
  .drop-icon{width:52px;height:52px;margin:0 auto 18px;border-radius:14px;background:var(--line-2);
    display:flex;align-items:center;justify-content:center;font-size:22px;color:var(--ink-2);font-weight:700}
  .drop-title{font-size:17px;font-weight:600;color:var(--ink);max-width:48ch;margin:0 auto}
  .drop input[type=file]{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .drop-actions{margin-top:20px}
  .drop-sub{font-size:13px;color:var(--ink-3);max-width:54ch;margin:20px auto 0;line-height:1.6}

  .ej-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}
  .ej-name{font-weight:600;font-size:13.5px;color:var(--ink);word-break:break-word}
  .ej-meta{display:flex;justify-content:space-between;gap:8px;margin-top:10px;font-size:12.5px;color:var(--ink-2)}

  .file-strip{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap}
  .file-strip .name{font-weight:600;margin-top:6px;word-break:break-word}
  .file-strip .meta{color:var(--ink-2);font-size:13px;margin-top:4px}

  .classify-bar{margin-top:16px;display:flex;align-items:center;gap:18px;flex-wrap:wrap}
  .progress{display:flex;align-items:center;gap:12px;flex:1;min-width:220px}
  .progress-track{flex:1;height:8px;background:var(--line-2);border-radius:100px;overflow:hidden}
  .progress-fill{height:100%;width:0;background:linear-gradient(90deg,#3a6ea5,var(--steel));border-radius:100px;transition:width .5s cubic-bezier(.22,1,.36,1)}
  .progress-label{font-size:12.5px;color:var(--ink-2);white-space:nowrap}

  .tbl-wrap.scroll{max-height:420px;overflow-y:auto}

  /* ---- bandeja ---- */
  .toolbar{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:14px}
  .filters{display:flex;gap:6px}
  /* Los chips de filtro de auditoría y de cuentas. Sin esto el contenedor entra en el flex de
     `.toolbar` como un bloque, se encoge hasta el ancho de su palabra más larga —«export_lote_
     descartado»— y los botones se apilan en una columna, empujando el contador de eventos a un
     lado. Lo vio Ricardo el 25-ago en la pestaña de auditoría de RM. */
  .fchips{display:flex;gap:6px;flex-wrap:wrap;min-width:0}
  /* El selector por tipo (Fase 5) es un contenedor lógico: sus chips participan del flex de
     .filters (mismo gap) en vez de contar como un solo ítem. Vacío, no ocupa nada. */
  .tiposel{display:contents}
  .fchip{appearance:none;border:1px solid var(--line);background:var(--surface);border-radius:100px;
    padding:6px 13px;font-size:13px;font-weight:600;color:var(--ink-2);cursor:pointer;display:flex;align-items:center;gap:7px}
  .fchip[aria-pressed="true"]{color:var(--ink);border-color:var(--ink);background:#fff}
  .fchip.v[aria-pressed="true"]{border-color:var(--v);color:var(--v)}
  .fchip.a[aria-pressed="true"]{border-color:var(--a);color:var(--a)}
  .fchip.r[aria-pressed="true"]{border-color:var(--r);color:var(--r)}
  .search{flex:1;min-width:180px;border:1px solid var(--line);background:var(--surface);border-radius:var(--r-sm);
    padding:8px 12px;font-size:14px;color:var(--ink)}
  .count{color:var(--ink-3);font-size:13px;white-space:nowrap}

  table{width:100%;border-collapse:collapse}
  .tbl-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface)}
  thead th{text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);
    font-weight:600;padding:12px 16px;border-bottom:1px solid var(--line);white-space:nowrap;position:sticky;top:0;background:var(--surface)}
  thead th.r,tbody td.r{text-align:right}
  thead th.sortable{cursor:pointer;user-select:none}
  thead th.sortable:hover{color:var(--ink)}
  thead th.sortable[data-active="1"]{color:var(--ink)}
  .sort-ind{margin-left:5px;font-size:10px;color:var(--ink-3)}
  th.chk,td.chk{width:38px;text-align:center;padding-left:12px;padding-right:6px}
  th.chk input,td.chk input{cursor:pointer;width:15px;height:15px}
  /* botón de aprobar en lote (selección múltiple) */
  #aprobarSelBtn{margin-left:8px}
  tbody tr{border-bottom:1px solid var(--line-2);cursor:pointer;transition:background .12s}
  tbody tr:hover{background:#faf9f6}
  tbody tr:last-child{border-bottom:0}
  tbody tr.approved{background:#f6faf7}
  tbody tr.approved:hover{background:#eef7f1}
  tbody td{padding:13px 16px;font-size:14px;vertical-align:top}
  .prov{font-weight:600}
  .muted{color:var(--ink-2)}
  .money{font-family:var(--mono);font-variant-numeric:tabular-nums}
  .segpill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:3px 9px;border-radius:100px}
  .segpill.v{background:var(--v-bg);color:var(--v);border:1px solid var(--v-ln)}
  .segpill.a{background:var(--a-bg);color:var(--a);border:1px solid var(--a-ln)}
  .segpill.r{background:var(--r-bg);color:var(--r);border:1px solid var(--r-ln)}
  .conf{font-family:var(--mono);font-size:13px}
  .apr-badge{display:inline-flex;align-items:center;gap:5px;font-size:12.5px;font-weight:600;color:var(--v)}
  .apr-pending{font-size:12.5px;color:var(--ink-3)}
  .apr-who{display:block;font-size:11.5px;color:var(--ink-3);font-weight:400;margin-top:2px}
  /* Nota de crédito (CFDI de egreso): otra plantilla de NetSuite y otro CSV. Se marca para no
     confundirla con un gasto. */
  .nc-pill{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:100px;font-size:11px;
    font-weight:600;background:#efe6fb;color:#6b3fa0;border:1px solid #d9c6f2;vertical-align:middle}
  .fchip.nc[aria-pressed="true"]{background:#efe6fb;color:#6b3fa0;border-color:#c9adec}

  /* La razón social de cada fila (Ricardo, 17-ago). Deliberadamente CALLADA —tokens neutros,
     no un color propio— para no competir con el semáforo de segmento, que es lo que dice si
     hay trabajo. Va con variables de tema y no con hex fijos, para que no se quede clara sobre
     fondo oscuro. */
  .rs-pill{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:100px;font-size:11px;
    font-weight:600;background:var(--line-2);color:var(--ink-2);border:1px solid var(--line);
    vertical-align:middle;white-space:nowrap}
  /* El cambio de contraseña: oculto hasta que se pide, y en una sola línea para no empujar
     la barra de pestañas hacia abajo cuando se abre. */
  .pwbox{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 16px;
    background:var(--line-2);border-top:1px solid var(--line);font-size:13px}
  .pwbox label{color:var(--ink-2);font-size:12px}
  .pwbox input{padding:4px 8px;border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--surface);color:var(--ink)}
  .pwmsg{color:var(--r);font-size:12.5px}

  .rs-pill.falta{background:var(--a-bg);color:var(--a);border-color:var(--a-ln)}
  /* Lo que el SAT retiró después de entrar (cancelada o sustituida). En rojo y no en ámbar:
     no es «revisar», es «esto ya no vale». */
  .sat-pill{display:inline-block;margin-left:7px;padding:1px 7px;border-radius:100px;font-size:11px;
    font-weight:600;background:var(--r-bg);color:var(--r);border:1px solid var(--r-ln);
    vertical-align:middle;white-space:nowrap}
  .sat-aviso{color:var(--r);font-size:12.5px;margin:2px 0 8px}

  .detail{background:#faf9f6}
  .detail td{padding:0}
  .detail-in{padding:6px 16px 18px}
  .lg{margin:12px 0 6px;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);font-weight:600}
  .lrow{display:grid;grid-template-columns:1fr auto;gap:10px 18px;padding:10px 0;border-top:1px solid var(--line-2)}
  .lrow .meta{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:5px}
  .tag{font-size:12px;color:var(--ink-2);background:#fff;border:1px solid var(--line);border-radius:5px;padding:2px 8px}
  .tag b{color:var(--ink)}
  .como{margin-top:8px;font-size:13px;color:var(--ink-2);line-height:1.5;border-left:2px solid var(--steel);padding-left:12px}
  .actions{display:flex;gap:8px;margin-top:16px;align-items:center;flex-wrap:wrap}
  .btn{appearance:none;border-radius:var(--r-sm);padding:8px 15px;font-size:13.5px;font-weight:600;cursor:pointer;border:1px solid var(--line)}
  .btn.approve{background:var(--v);color:#fff;border-color:var(--v)}
  .btn.approve:hover{filter:brightness(1.05)}
  .btn.approve:disabled{background:var(--ink-3);border-color:var(--ink-3);cursor:default;filter:none}
  .btn.fix{background:#fff;color:var(--ink)}
  .btn.fix:hover{border-color:var(--ink)}
  .btn.ghost{background:#fff;color:var(--ink-2)}
  .btn:disabled{opacity:.55;cursor:default}

  /* ---- hallazgos fiscales ---- */
  .fisc{display:inline-flex;align-items:center;justify-content:center;width:19px;height:19px;
    border-radius:5px;font-size:12px;font-weight:700;margin-left:6px;vertical-align:-3px;cursor:help}
  .fisc.err{background:var(--r-bg);color:var(--r);border:1px solid var(--r-ln)}
  .fisc.avi{background:var(--a-bg);color:var(--a);border:1px solid var(--a-ln)}
  .fbox{margin-top:14px;border-radius:var(--r-sm);overflow:hidden;border:1px solid var(--line)}
  .fitem{padding:12px 14px;border-bottom:1px solid var(--line-2);font-size:13.5px;line-height:1.55}
  .fitem:last-child{border-bottom:0}
  .fitem.err{background:var(--r-bg)} .fitem.avi{background:var(--a-bg)}
  .fitem .fh{font-weight:700;font-size:11px;letter-spacing:.06em;text-transform:uppercase;margin-bottom:5px}
  .fitem.err .fh{color:var(--r)} .fitem.avi .fh{color:var(--a)}
  .fprop{margin-top:9px;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
  .fprop code{font-family:var(--mono);font-size:12.5px;background:#fff;border:1px solid var(--line);
    border-radius:4px;padding:3px 8px}

  /* ---- aviso de Exportar: impuesto sin determinar (NetSuite rechaza la factura al importar) ---- */
  .exp-warn{margin-top:10px;padding:10px 14px;border-radius:var(--r-sm);background:var(--r-bg);
    border:1px solid var(--r-ln);color:var(--r);font-size:13px;line-height:1.5}

  /* ---- corrección ---- */
  .fixbox{margin-top:14px;padding:16px;border:1px solid var(--a-ln);background:var(--a-bg);border-radius:var(--r-sm)}
  .fixgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
  .fixgrid label{display:block;font-size:11.5px;font-weight:600;color:var(--ink-2);margin-bottom:4px}
  .fixgrid input{width:100%;border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 10px;
    font-size:13.5px;font-family:inherit;background:#fff;color:var(--ink)}
  .fixbox textarea{width:100%;margin-top:10px;border:1px solid var(--line);border-radius:var(--r-sm);
    padding:8px 10px;font-size:13.5px;font-family:inherit;background:#fff;color:var(--ink);resize:vertical;min-height:56px}
  .fixhint{font-size:12px;color:var(--ink-2);margin-top:8px;line-height:1.5}

  /* ---- combobox cerrado (se escribe para filtrar, solo se elige del catálogo) ---- */
  .combo{position:relative}
  .combo-inp{width:100%;border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 10px;
    font-size:13.5px;font-family:inherit;background:var(--surface);color:var(--ink)}
  .combo-inp:focus{outline:2px solid var(--steel);outline-offset:0;border-color:var(--steel)}
  .combo-inp.off{border-color:var(--a-ln);background:var(--a-bg)}   /* valor fuera de catálogo */
  /* La lista NO hereda el ancho del campo.  En la rejilla del editor cada columna mide ~280px y
     las rutas de cuenta de NetSuite ('Gastos Administrativos : RRHH : Costo Social y Fiscal :
     IMSS Cuota patronal') pasan de 70 caracteres: recortadas con puntos suspensivos, dos cuentas
     hermanas se ven idénticas y hay que elegir a ciegas.  Lo reportó Ricardo el 8-ago. */
  .combo-list{position:absolute;z-index:40;left:0;right:auto;top:calc(100% + 3px);max-height:260px;
    min-width:100%;width:max-content;max-width:min(640px,90vw);
    overflow-y:auto;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
    box-shadow:var(--sh)}
  .combo-list.izq{left:auto;right:0}   /* cerca del borde derecho, se abre hacia dentro */
  /* Sin truncar: si la ruta no cabe en el ancho máximo, ajusta en dos renglones. */
  .combo-opt{padding:7px 10px;font-size:13px;cursor:pointer;line-height:1.45;overflow-wrap:anywhere}
  .combo-opt:hover,.combo-opt.sel{background:var(--line-2)}
  .combo-empty{padding:8px 10px;font-size:12.5px;color:var(--ink-3)}
  /* editor por línea */
  .ledit{border-top:1px solid var(--line-2);padding:12px 0}
  .ledit .lcap{font-size:13px;color:var(--ink);margin-bottom:8px}
  /* El bloque «aplicar a todas» pisa N líneas de un golpe: se separa del resto para que no se
     confunda con la edición de una sola, que es lo que hay debajo. */
  .ledit.todas{border-top:0;background:var(--line-2);border:1px solid var(--line);
    border-radius:var(--r-sm);padding:12px 14px}
  .ledit.todas .lcap{color:var(--ink-2);font-size:12.5px;line-height:1.5}
  .ledit .lgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
  .ledit .lgrid label{display:block;font-size:11px;font-weight:600;color:var(--ink-2);margin-bottom:3px}
  .fac-edit{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:6px}
  .fac-edit label{display:block;font-size:11.5px;font-weight:600;color:var(--ink-2);margin-bottom:4px}
  .incompleta{color:var(--r);font-size:12.5px;font-weight:600}
  .req{color:var(--r)}
  @media (max-width:820px){ .ledit .lgrid,.fac-edit{grid-template-columns:1fr 1fr} }

  /* ---- exportar ---- */
  .load-head{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap}
  .load-actions{display:flex;gap:8px;flex-wrap:wrap}
  .load-head .big{font-family:var(--mono);font-size:32px;font-weight:600;color:var(--v)}
  pre.csv{margin:0;padding:16px;background:#fbfbf9;border:1px solid var(--line);border-radius:var(--r-sm);
    overflow-x:auto;font-family:var(--mono);font-size:12px;color:var(--ink-2);line-height:1.6;max-height:340px}

  /* ---- auditoría ---- */
  .ev-accion{display:inline-block;font-size:11.5px;font-weight:700;padding:2px 8px;border-radius:4px;
    text-transform:uppercase;letter-spacing:.04em}
  .ev-clasificar{background:#e8eef5;color:var(--steel)}
  .ev-aprobar{background:var(--v-bg);color:var(--v)}
  .ev-corregir{background:var(--a-bg);color:var(--a)}
  .ev-exportar{background:#efeee9;color:var(--ink-2)}
  .ev-login{background:#f2f1ec;color:var(--ink-3)}
  .ev-cambio{font-family:var(--mono);font-size:12.5px}
  .ev-cambio .de{color:var(--r);text-decoration:line-through}
  .ev-cambio .a{color:var(--v);font-weight:600}
  .ev-com{color:var(--ink-2);font-size:13px;font-style:italic}

  .empty{padding:48px 20px;text-align:center;color:var(--ink-3)}
  .toast{position:fixed;bottom:22px;left:50%;transform:translate(-50%,20px);background:var(--ink);color:#fff;
    padding:11px 18px;border-radius:100px;font-size:13.5px;font-weight:600;opacity:0;pointer-events:none;
    transition:opacity .25s,transform .25s;z-index:50;box-shadow:0 8px 30px rgba(0,0,0,.25)}
  .toast.show{opacity:1;transform:translate(-50%,0)}

  @media (max-width:820px){
    .kpis{grid-template-columns:repeat(2,1fr)} .two{grid-template-columns:1fr}
    .river-head{flex-direction:column;align-items:flex-start} .headline-verde{text-align:left}
    .card.drop{padding:36px 18px} .fixgrid{grid-template-columns:1fr}
  }
  @media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

  /* ══════════════════════════════════════════════════════════════════════════════
     MODO OSCURO
     ══════════════════════════════════════════════════════════════════════════════
     Se redefinen solo los TOKENS, nunca los componentes: el resto de la hoja ya está
     escrita contra las variables, así que el tema se cambia en un sitio y no en ciento.

     No es una inversión mecánica. El papel se vuelve un gris muy oscuro con un punto de
     azul (el mismo sesgo del acero de la marca) y no negro puro, que en pantalla grande
     cansa; y los tres colores del semáforo se ACLARAN, porque el verde y el rojo de la
     versión clara sobre fondo oscuro se apagan hasta dejar de leerse. El semáforo es la
     información más densa de la pantalla: si pierde contraste, la pantalla pierde su
     función.

     **Por qué no hay `@media (prefers-color-scheme: dark)` aquí.** Desde que el tema se puede
     elegir a mano, quien decide es el script del `<head>` (ver `index.html` y `js/tema.js`):
     resuelve las tres opciones —claro, oscuro, como el sistema— y deja SIEMPRE un
     `data-theme="dark"|"light"` puesto antes del primer pintado. Escribir además el media query
     obligaría a repetir la paleta entera en dos sitios, y dos copias de veinte colores no se
     mantienen sincronizadas: la segunda vez que alguien ajuste un verde, ajustará una sola.
     El precio es que sin JavaScript la página se queda en claro — y sin JavaScript esta
     aplicación no existe, porque toda la interfaz son módulos ES. */
  :root[data-theme="light"]{color-scheme:light}
  :root[data-theme="dark"]{
    color-scheme:dark;
    --paper:#15181c; --surface:#1c2026; --line:#2c323a; --line-2:#242931;
    --ink:#e8eaed; --ink-2:#a4a9b3; --ink-3:#767c87;
    --steel:#6fa8dc;
    --v:#4ec98a; --v-bg:#163024; --v-ln:#26543c;
    --a:#e0a83c; --a-bg:#33280f; --a-ln:#57431a;
    --r:#e8756c; --r-bg:#361d1c; --r-ln:#59302d;
    --sh:0 1px 2px rgba(0,0,0,.3),0 4px 16px rgba(0,0,0,.35);
  }
  [data-theme="dark"] header{background:rgba(21,24,28,.86)}
  /* Estos tres traían un color literal, de cuando solo había tema claro. */
  [data-theme="dark"] pre.csv{background:#14171b}
  [data-theme="dark"] .ev-clasificar{background:#1e2a38}
  [data-theme="dark"] .ev-exportar{background:#242931}
  [data-theme="dark"] .ev-login{background:#20242a}
  [data-theme="dark"] .toast{background:#2c323a;color:var(--ink)}
  /* Los campos de formulario heredan el tema del sistema, no el de la página, y en oscuro
     salen blancos sobre blanco. */
  [data-theme="dark"] input,
  [data-theme="dark"] select,
  [data-theme="dark"] textarea{background:var(--surface);color:var(--ink);border-color:var(--line)}

  /* ---- interruptor de tema ---- */
  /* Tres estados y no dos: «como el sistema» tiene que poder elegirse, porque es lo que hace
     que la pantalla se oscurezca sola por la noche en el equipo de Ale. Un interruptor de dos
     posiciones deja esa opción sin forma de volver. */
  .tema{display:flex;gap:0;border:1px solid var(--line);border-radius:100px;overflow:hidden;
    background:var(--surface)}
  .temabtn{appearance:none;border:0;background:none;cursor:pointer;padding:3px 9px;
    font-size:11.5px;font-weight:600;color:var(--ink-3);font-family:inherit}
  .temabtn + .temabtn{border-left:1px solid var(--line)}
  .temabtn:hover{color:var(--ink-2)}
  .temabtn[aria-pressed="true"]{background:var(--line-2);color:var(--ink)}

  /* ══════════════════════════════════════════════════════════════════════════════
     PANTALLAS ANGOSTAS (<820px)
     ══════════════════════════════════════════════════════════════════════════════
     El caso real no es un teléfono: es José abriendo la conciliación en media pantalla
     junto al portal del banco, y Ricardo mirando el panel desde la tableta. Lo que se
     arregla es lo que se rompía ahí. */
  @media (max-width:820px){
    .bar{padding:12px 16px} nav{padding:0 16px} main{padding:0 16px}
    .toolbar{flex-wrap:wrap}
    .toolbar .search,.toolbar .sel{flex:1 1 100%;min-width:0}
    /* La tabla no se apila: se desplaza dentro de su caja. Apilarla perdería la comparación
       de columnas, que es justo para lo que se usa (¿esta cuenta cuadra con la de arriba?).
       El `-webkit-overflow-scrolling` mantiene el desplazamiento con inercia en iPad. */
    .tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
    .tbl-wrap table{min-width:760px}
    /* El detalle SÍ se apila: ahí no hay columnas que comparar. */
    .detail-in .lrow{flex-direction:column;align-items:flex-start;gap:6px}
    .ledit .lgrid,.fac-edit{grid-template-columns:1fr}
    .load-head{flex-direction:column;align-items:stretch}
    .load-actions .btn{flex:1 1 auto}
  }
  @media (max-width:520px){
    .kpis{grid-template-columns:1fr}
    .who .rolepill{display:none}        /* el rol cabe en el menú de la app, no en la barra */
  }

  /* ---- navegación agrupada ---- */
  /* El grupo es un rótulo, no un menú: las pestañas siguen a un clic de distancia. Esconderlas
     tras un desplegable cambiaría el ruido por algo peor —una pestaña que nadie encuentra—.
     El rótulo va ENCIMA de sus pestañas, en columna. Al lado, como estaba, la fila entera medía
     más que el ancho de la barra y partía por donde le tocaba: un rótulo se quedaba en un
     renglón y sus pestañas en el siguiente, que es peor que no agrupar.
     `justify-content:flex-end` alinea las pestañas por abajo aunque un grupo no lleve rótulo —
     con un solo grupo rotulado no se rotula ninguno, y los dos casos conviven. */
  .navgrupo{display:flex;flex-direction:column;justify-content:flex-end;gap:0}
  .navgrupo + .navgrupo{margin-left:26px;padding-left:26px;border-left:1px solid var(--line)}
  .navgrupo-tabs{display:flex;gap:0}
  .navgrupo-t{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);
    font-weight:700;white-space:nowrap;padding:10px 0 0}
  /* Con el rótulo encima, el hueco de arriba ya lo pone él. */
  .navgrupo-t + .navgrupo-tabs .tab{padding-top:4px}
  @media (max-width:820px){
    /* En angosto el separador vertical estorba: los grupos ya se separan al saltar de renglón. */
    .navgrupo + .navgrupo{margin-left:0;padding-left:0;border-left:0}
    .navgrupo{flex:0 0 auto}
    .navgrupo-t{display:none}
    .navgrupo-t + .navgrupo-tabs .tab{padding-top:12px}
  }
