@import url('https://fonts.googleapis.com/css2?family=Archivo+Expanded:wght@700;800&family=Archivo:wght@600;700;800&family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600;700&display=swap');

/* Bloque 5 (2026-09-06) — modo oscuro. Estructura de tres capas exigida
   por tener que soportar "sigue al sistema" Y un interruptor manual a la
   vez: la base de :root son los valores CLAROS; el media query cubre
   "sistema en oscuro, sin elección explícita" (guardado con
   :not([data-theme="light"]) para que una elección explícita de CLARO
   le gane al sistema); y el bloque [data-theme="dark"] cubre la
   elección explícita de OSCURO, para que gane en cualquier sistema.
   El sidebar (--sidebar-*) ya era oscuro en los dos temas desde el
   rediseño de la Fase A — no se toca.
   Blanco con verde oliva (2026-09-17): Daniel no quería el azul ni el gris
   grafito; escogió esta entre cuatro muestras. En tema claro la barra es
   blanca (texto oscuro, acento oliva); en oscuro vuelve a ser oscura, por
   eso los --sidebar-* también se redefinen en los bloques oscuros. El
   verde, el amarillo y el rojo de estado no cambian. */
:root {
  --ink: #1f2419; --ink-soft: #5a6152; --ink-faint: #8d9385;
  --paper: #f5f6f2; --surface: #ffffff; --surface-sunk: #f7f8f4;
  --line: #dfe2d8; --line-soft: #eaece5;
  --accent: #4e6b2f; --accent-ink: #ffffff; --steel: #8a9579;
  --ok-bg: #e2f0e8; --ok-fg: #1f6b45;
  --warn-bg: #fbf1de; --warn-fg: #8a6314; --warn-border: #eddcb2;
  --bad-bg: #f8e7e6; --bad-fg: #a13f3f;
  --sidebar: #ffffff; --sidebar-line: #e3e6dc; --sidebar-text: #2b3124;
  --sidebar-text-dim: #6b735f; --sidebar-accent: #4e6b2f;
  --sidebar-activo: rgba(78,107,47,0.10); --sidebar-registrar: #ffffff;
  --shadow: 0 1px 2px rgba(24,27,20,0.05), 0 6px 16px -8px rgba(24,27,20,0.14);
  --topbar-bg: rgba(245,246,242,0.92);
  --sidebar-w: 258px;
  color-scheme: light;
  /* Alias hacia atrás: nombres viejos que las vistas siguen usando en estilos
     inline (var(--dim), var(--bg), etc.) — no tocar esas 19 vistas para esto. */
  --dim: var(--ink-soft); --border: var(--line); --bg: var(--paper);
  --card: var(--surface); --navy: var(--sidebar); --green: var(--ok-fg);
  --warn-text: var(--warn-fg);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ink: #e4e8dc; --ink-soft: #a6ad99; --ink-faint: #76806a;
    --paper: #11130e; --surface: #1a1d16; --surface-sunk: #151812;
    --line: #30362a; --line-soft: #23281f;
    --accent: #a3c27a; --accent-ink: #11130e; --steel: #94a083;
    --sidebar: #181b14; --sidebar-line: #2b3025; --sidebar-text: #e4e8dc;
    --sidebar-text-dim: #9aa38d; --sidebar-accent: #a3c27a;
    --sidebar-activo: rgba(163,194,122,0.14); --sidebar-registrar: #11130e;
    --ok-bg: #17301f; --ok-fg: #6fd08c;
    --warn-bg: #3a2c10; --warn-fg: #e0b458; --warn-border: #5a4620;
    --bad-bg: #3a1e1e; --bad-fg: #e08585;
    --shadow: 0 1px 2px rgba(0,0,0,0.35), 0 6px 18px -8px rgba(0,0,0,0.55);
    --topbar-bg: rgba(17,19,14,0.88);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --ink: #e4e8dc; --ink-soft: #a6ad99; --ink-faint: #76806a;
  --paper: #11130e; --surface: #1a1d16; --surface-sunk: #151812;
  --line: #30362a; --line-soft: #23281f;
  --accent: #a3c27a; --accent-ink: #11130e; --steel: #94a083;
  --sidebar: #181b14; --sidebar-line: #2b3025; --sidebar-text: #e4e8dc;
  --sidebar-text-dim: #9aa38d; --sidebar-accent: #a3c27a;
  --sidebar-activo: rgba(163,194,122,0.14); --sidebar-registrar: #11130e;
  --ok-bg: #17301f; --ok-fg: #6fd08c;
  --warn-bg: #3a2c10; --warn-fg: #e0b458; --warn-border: #5a4620;
  --bad-bg: #3a1e1e; --bad-fg: #e08585;
  --shadow: 0 1px 2px rgba(0,0,0,0.35), 0 6px 18px -8px rgba(0,0,0,0.55);
  --topbar-bg: rgba(17,19,14,0.88);
  color-scheme: dark;
}

* { box-sizing: border-box; }
/* Bloque 5 — accesibilidad transversal: foco visible en todo lo interactivo
   (antes solo input/select/textarea lo tenían), y respeto por
   prefers-reduced-motion para quien lo pida a nivel de sistema. */
a:focus-visible, button:focus-visible, .nav-link:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}
@media print {
  thead { display: table-header-group; }
  .tabla-scroll table thead th { position: static; }
  /* Sin esto, una tabla de más de 70vh se imprimiría recortada dentro de
     su propio recuadro con scroll — al imprimir tiene que verse completa,
     repartida en tantas páginas como haga falta. */
  .tabla-scroll { max-height: none; overflow: visible; }
}
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font-family: 'IBM Plex Sans', -apple-system, "Segoe UI", Arial, sans-serif;
  font-size: 14px; line-height: 1.45;
}
h1, h2, h3 { font-family: 'Archivo', 'IBM Plex Sans', sans-serif; font-weight: 800; text-wrap: balance; margin: 0 0 1rem; color: var(--ink); }
a { color: inherit; }

/* ---- shell: sidebar y topbar fijos, main desplazado — así ninguna de las
   19 vistas necesita envolver <main> en un contenedor nuevo (ver nav.ejs). ---- */
aside.sidebar {
  position: fixed; top: 0; left: 0; bottom: 0; width: var(--sidebar-w);
  background: var(--sidebar); color: var(--sidebar-text); border-right: 1px solid var(--sidebar-line);
  display: flex; flex-direction: column; overflow-y: auto; z-index: 10;
}
.topbar {
  position: fixed; top: 0; left: var(--sidebar-w); right: 0; z-index: 5;
  background: var(--topbar-bg); backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
  padding: 0.85rem 2rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
/* --ink-soft y sin mayúsculas: con --ink-faint en letra de 11 px la ruta no
   llegaba al contraste mínimo (2,6:1 en tema claro; revisión de UX). */
.topbar .crumb { font-size: 0.82rem; color: var(--ink-soft); font-weight: 600; }
.topbar .salir { color: var(--bad-fg); text-decoration: none; font-size: 0.85rem; font-weight: 600; }
.theme-toggle {
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-soft);
  border-radius: 7px; width: 1.9rem; height: 1.9rem; font-size: 0.95rem; line-height: 1;
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--steel); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* max-width subido de 1180px a 1600px (2026-09-10): el tope viejo venía del
   rediseño de la Fase A pensando en texto corrido, pero deja tablas de
   muchas columnas (ej. Resolution Center, P&G detallado) angostas con
   espacio en blanco de sobra a la derecha en cualquier monitor >1500px —
   el usuario lo notó en una tabla real. Las vistas de texto/formulario no
   se ven afectadas: sus tarjetas y grillas ya se ajustan a su contenido,
   no a `main` completo. */
main { margin-left: var(--sidebar-w); padding: 4.4rem 2rem 4rem; max-width: 1600px; }

.hamburger { display: none; }
.sidebar-backdrop { display: none; }

/* Bloque 5.3 (2026-09-07) — antes esto ponía el sidebar en `position:
   static`, que en un aside con 30+ enlaces significa "empujar toda la
   lista completa arriba del contenido" en vez de un menú móvil de
   verdad. Ahora el sidebar se queda `fixed` pero fuera de pantalla
   (`translateX(-100%)`) y un botón ☰ nuevo en el topbar lo desliza —
   mismo patrón sin dependencias que ya usa el ⌘K (toggle de clase +
   `hidden`, sin librería). */
@media (max-width: 900px) {
  aside.sidebar {
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    box-shadow: none;
  }
  body.sidebar-open aside.sidebar { transform: translateX(0); box-shadow: 0 0 0 100vmax rgba(0,0,0,0); }
  .topbar { left: 0; }
  main { margin-left: 0; padding-top: 1.6rem; }
  .hamburger {
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--line); background: var(--surface); color: var(--ink-soft);
    border-radius: 7px; width: 2.1rem; height: 2.1rem; font-size: 1.1rem; line-height: 1;
    cursor: pointer; flex: none;
  }
  .sidebar-backdrop {
    display: none; position: fixed; inset: 0; background: rgba(17,19,14,0.45); z-index: 9;
  }
  body.sidebar-open .sidebar-backdrop { display: block; }
}

/* ---- marca ---- */
.brand { padding: 1.5rem 1.4rem 1.2rem; border-bottom: 1px solid var(--sidebar-line); }
.brand-mark { display: flex; align-items: center; gap: 0.7rem; }
.brand-mark svg { width: 32px; height: 32px; flex: none; }
/* Logo real subido en Configuración → Logo del panel: sobre chip blanco, que
   la barra es oscura y casi todos los logos son de tinta oscura.
   El usuario lo seguía viendo pequeño (2026-09-16): con un tope de alto de
   64px, un logo cuadrado se quedaba en 64px de ancho aunque la barra tenga
   213px libres — solo los logos muy apaisados llegaban al tope de ancho.
   Ahora ocupa TODO el ancho disponible y el alto es el que mande el tope;
   `object-fit: contain` centra el dibujo sin deformarlo, y como el chip es
   blanco el sobrante no se nota. Sirve igual para un logo cuadrado, uno
   apaisado o uno vertical. */
.brand-logo {
  width: 100%; max-height: 120px; object-fit: contain;
  background: #fff; border-radius: 0.5rem; padding: 8px 10px; display: block;
}
.brand-word { font-family: 'Archivo Expanded', 'Archivo', sans-serif; font-weight: 800; font-size: 1rem; letter-spacing: 0.02em; line-height: 1.05; color: var(--sidebar-text); }
.brand-word span { display: block; color: var(--sidebar-text-dim); font-family: 'Archivo Expanded', sans-serif; font-weight: 800; }
.brand-sub { margin-top: 0.6rem; font-size: 0.7rem; color: var(--sidebar-text-dim); letter-spacing: 0.04em; text-transform: uppercase; }

/* ---- nav lateral ---- */
nav.groups { padding: 1rem 0.8rem 1.2rem; flex: 1; }
.nav-group { margin-bottom: 1.3rem; }
.nav-group-label { font-size: 0.66rem; letter-spacing: 0.09em; text-transform: uppercase; color: var(--sidebar-text-dim); padding: 0 0.6rem 0.4rem; font-weight: 600; }
.nav-link {
  display: flex; align-items: center; gap: 0.6rem; padding: 0.48rem 0.6rem; border-radius: 7px;
  color: var(--sidebar-text); text-decoration: none; font-size: 0.85rem; font-weight: 500;
  border-left: 3px solid transparent;
}
.nav-link:hover { background: var(--sidebar-activo); }
.nav-link.active { background: var(--sidebar-activo); border-left-color: var(--sidebar-accent); color: var(--sidebar-text); font-weight: 600; }
.nav-link .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--sidebar-text-dim); flex: none; }
.nav-link.active .dot { background: var(--sidebar-accent); }
.nav-badge { margin-left: auto; font-family: 'IBM Plex Mono', monospace; font-size: 0.66rem; padding: 0.05rem 0.4rem; border-radius: 999px; background: var(--bad-bg); color: var(--bad-fg); }

.sidebar-foot { padding: 1rem 1.4rem 1.3rem; border-top: 1px solid var(--sidebar-line); font-size: 0.74rem; color: var(--sidebar-text-dim); }
.sidebar-foot strong { color: var(--sidebar-text); display: block; font-size: 0.82rem; margin-bottom: 0.15rem; }
.sidebar-foot a { color: var(--sidebar-accent); text-decoration: none; }

/* ---- tarjetas / KPI (clases ya usadas por las vistas: card, kpi, label, valor, grid) ---- */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 1.1rem 1.25rem; box-shadow: var(--shadow); margin-bottom: 1rem; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 0.9rem; }
.kpi { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 0.95rem 1.05rem; box-shadow: var(--shadow); }
.grid.card > .kpi, .card > .grid > .kpi { box-shadow: none; }
.kpi .label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-faint); font-weight: 600; margin-bottom: 0.4rem; }
.kpi .valor { font-family: 'IBM Plex Mono', monospace; font-size: 1.3rem; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }

/* ---- estados / pills (clases ya usadas: estado, ok, revisar, anulado, neutral) ---- */
.estado { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.7rem; font-weight: 600; padding: 0.2rem 0.55rem; border-radius: 999px; background: var(--surface-sunk); color: var(--ink-soft); border: 1px solid var(--line); margin-top: 0.4rem; }
.estado.ok { background: var(--ok-bg); color: var(--ok-fg); border-color: transparent; }
.estado.revisar { background: var(--warn-bg); color: var(--warn-fg); border-color: transparent; }
.estado.anulado { background: var(--bad-bg); color: var(--bad-fg); border-color: transparent; margin: 0; }
.estado.neutral { background: var(--surface-sunk); color: var(--ink-soft); }

/* ---- tablas ---- */
/* overflow-x: auto SOLO (sin overflow-y) rompe position:sticky: la
   especificación CSS obliga a que el eje sin declarar pase de "visible" a
   "auto" también, así que .tabla-scroll se vuelve un contenedor de scroll
   vertical — pero uno que nunca se desplaza de verdad (crece con su
   contenido), así que "sticky" queda pegado a un scroll que no ocurre y
   nunca se ve fijo. La solución real: declarar overflow-y explícito y
   darle un alto máximo, para que el propio recuadro sea el que desplaza
   (como "inmovilizar filas" en una hoja de cálculo) y sticky se pegue al
   techo de ESE recuadro, no de la página. */
.tabla-scroll { overflow: auto; max-height: 70vh; }
table { width: 100%; border-collapse: collapse; font-size: 0.87rem; }
th, td { text-align: left; padding: 0.55rem 0.6rem; border-bottom: 1px solid var(--line-soft); }
th { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-faint); font-weight: 600; border-bottom: 1px solid var(--line); }
tbody tr:hover { background: var(--surface-sunk); }

/* Encabezado fijo al bajar por una tabla larga (P&G, Gastos, Reservas...):
   sticky respecto al recuadro con scroll propio de arriba, no del topbar. */
.tabla-scroll table thead th {
  position: sticky; top: 0; background: var(--surface); z-index: 2;
}

/* Trunca a una sola línea con "…" en vez de partir en muchas — una celda con
   texto largo (razones, evidencia de Conciliación) no debe estirar la fila
   entera. El texto completo va en el atributo title (mismo string, nunca se
   arma dos veces distinto) para verlo al pasar el mouse. */
.truncar { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- formularios ---- */
form label { display: block; font-size: 0.72rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; color: var(--ink-soft); margin: 0.7rem 0 0.32rem; }
input, select, textarea {
  width: 100%; padding: 0.58rem 0.7rem; border: 1px solid var(--line); border-radius: 8px; font-size: 0.9rem;
  font-family: inherit; background: var(--surface); color: var(--ink);
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
/* Sin esto, un checkbox/radio suelto en una celda de tabla (candidatos de
   conciliación, selección en lote) heredaba el mismo padding/borde/ancho
   100% que un <input type=text> — se veía como una casilla gigante con
   borde en vez de un checkbox normal (hallazgo Opus 2026-09-10). */
input[type="checkbox"], input[type="radio"] { width: auto; padding: 0; border: none; }
button.btn { margin-top: 1.1rem; padding: 0.66rem 1.2rem; border: none; border-radius: 8px; background: var(--accent); color: var(--accent-ink); font-weight: 700; cursor: pointer; font-size: 0.9rem; font-family: 'Archivo', sans-serif; }
button.btn.green { background: var(--ok-fg); }
button.btn:hover { opacity: 0.92; }
.btn-link { display: inline-block; padding: 0.66rem 1.2rem; border-radius: 8px; background: var(--accent); color: var(--accent-ink); text-decoration: none; font-weight: 700; font-size: 0.9rem; font-family: 'Archivo', sans-serif; }
.btn-link.secondary { margin: 1.1rem 0 0 0.5rem; background: transparent; color: var(--ink); border: 1px solid var(--line); }
.btn-text { border: 0; background: none; color: var(--accent); padding: 0; margin-left: 0.55rem; cursor: pointer; font: inherit; text-decoration: underline; }
.btn-text.danger { color: var(--bad-fg); }
.btn-text:disabled { color: var(--ink-faint); cursor: default; text-decoration: none; }
.check-label { display: flex; align-items: center; gap: 0.4rem; text-transform: none; font-size: 0.9rem; font-weight: 400; }
.check-label input { width: auto; }
/* El calendario nativo muestra el orden que trae el navegador/SO de quien
   visita (Chrome en Windows con locale en-US, por ejemplo, muestra
   mes/día/año) — HTML no puede forzar un orden distinto ahí. El valor que
   se guarda siempre es correcto (ISO por debajo), pero para que nadie lo
   LEA mal a simple vista, cada campo de fecha lleva esta aclaración
   (inyectada por JS más abajo, para no tocar 15 plantillas a mano) —
   detectando el orden real de CADA navegador con Intl, no un "día/mes/año"
   fijo: un fijo queda al revés justo en el navegador que sí muestra
   mes/día/año, que es el caso real que lo delató (2026-09-13). */
.hint-fecha { display: block; margin-top: 0.2rem; font-size: 0.72rem; color: var(--ink-faint); text-transform: none; }

/* Eco del monto tecleado, con puntos de miles (ver partials/head.ejs,
   data-eco-monto). Va en los campos de plata que aceptan decimales —
   tesorería, abonos, compromisos— donde NO se puede usar data-miles porque
   ese borra el punto decimal y un saldo en dólares perdería los centavos.
   Es solo lectura: el valor que viaja al servidor nunca se toca. */
.hint-monto { display: block; margin-top: 0.2rem; font-size: 0.78rem; font-weight: 600; color: var(--ink-soft); text-transform: none; font-variant-numeric: tabular-nums; }

/* Aclaración corta bajo un campo — mismo nombre y misma regla que
   partials/head-rapido.ejs / head-movil.ejs (esas dos pantallas no incluyen
   este stylesheet, así que la duplican inline; acá queda disponible para el
   resto de vistas de escritorio, ver gasto.ejs / gasto-editar.ejs). */
.file-hint { display: block; margin-top: 0.35rem; color: var(--ink-faint); font-size: 0.78rem; }

/* ---- select buscable (progressive enhancement, ver partials/select-buscable.ejs) ---- */
.select-buscable-wrap { position: relative; }
.select-buscable-lista {
  position: absolute; z-index: 20; top: calc(100% + 2px); left: 0; right: 0; max-height: 220px;
  overflow-y: auto; background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: var(--shadow);
}
.select-buscable-item { padding: 0.5rem 0.7rem; font-size: 0.88rem; cursor: pointer; }
.select-buscable-item:hover, .select-buscable-item.activo { background: var(--accent); color: var(--accent-ink); }
.select-buscable-vacio { padding: 0.5rem 0.7rem; font-size: 0.85rem; color: var(--ink-faint); }

/* ---- mensajes / avisos ---- */
.msg { padding: 0.7rem 0.95rem; border-radius: 10px; margin-bottom: 1rem; font-size: 0.86rem; background: var(--surface-sunk); color: var(--ink-soft); }
.msg.ok { background: var(--ok-bg); color: var(--ok-fg); }
.msg.error { background: var(--bad-bg); color: var(--bad-fg); }
.aviso {
  display: flex; gap: 0.7rem; align-items: flex-start; background: var(--warn-bg); color: var(--warn-fg);
  border: 1px solid var(--warn-border); border-radius: 10px; padding: 0.7rem 0.95rem; font-size: 0.82rem; margin-bottom: 1.3rem;
}
.aviso .ico { flex: none; font-family: 'IBM Plex Mono', monospace; font-weight: 700; }

/* ---- pestañas de reportes (heredado; tabs-reportes.ejs ahora es un breadcrumb, no una barra completa) ---- */
.tabs { display: flex; gap: 0.9rem; flex-wrap: wrap; margin: 0 0 1rem; }
.tabs a { color: var(--ink-soft); text-decoration: none; font-size: 0.9rem; }
.tabs a:hover, .tabs a.active { color: var(--ink); }
.tabs a.active { font-weight: 700; }
.crumb-reportes { font-size: 0.78rem; color: var(--ink-faint); margin: -0.6rem 0 1.1rem; }
.crumb-reportes strong { color: var(--ink-soft); font-weight: 600; }

.mes-selector { display: flex; gap: 0.6rem; align-items: end; max-width: 360px; margin-bottom: 1rem; }
.mes-selector label { flex: 1; margin: 0; }
.mes-selector button { margin: 0; }
.subtabla-actualizar { display: flex; gap: 0.5rem; align-items: center; margin-top: 0.3rem; }
.subtabla-actualizar input { width: 130px; }
.subtabla-actualizar button { padding: 0.35rem 0.6rem; font-size: 0.8rem; margin: 0; }

/* Tesorería: "Guardar los saldos escritos" en un celular angosto no tiene
   sitio para 7 columnas — Tipo y Moneda son las dos que menos hacen falta
   para escribir un saldo nuevo (2026-09-15, ítem 2). */
@media (max-width: 760px) {
  .tabla-tesoreria th:nth-child(2), .tabla-tesoreria td:nth-child(2),
  .tabla-tesoreria th:nth-child(3), .tabla-tesoreria td:nth-child(3) { display: none; }
  .tabla-tesoreria input[type="number"] { width: 100%; }
}

.barra-rent { width: 100%; min-width: 90px; height: 0.5rem; background: var(--surface-sunk); border-radius: 999px; overflow: hidden; border: 1px solid var(--line-soft); }
.barra-rent-fill { height: 100%; background: var(--accent); border-radius: inherit; }

.chart-wrap { overflow-x: auto; }
.chart { display: block; width: 100%; min-width: 620px; height: 230px; }
.chart-ingreso { fill: var(--accent); }
.chart-utilidad { fill: var(--steel); }
.chart-axis { stroke: var(--line); stroke-width: 1; }
.chart-label { fill: var(--ink-faint); font-family: 'IBM Plex Mono', monospace; font-size: 10px; text-anchor: middle; }
.chart-legend { display: flex; gap: 1rem; color: var(--ink-soft); font-size: 0.8rem; margin-top: 0.4rem; }
.chart-legend span::before { content: ''; display: inline-block; width: 0.65rem; height: 0.65rem; border-radius: 2px; margin-right: 0.3rem; vertical-align: -1px; }
.chart-legend .ingreso::before { background: var(--accent); }
.chart-legend .utilidad::before { background: var(--steel); }

/* Bloque 5.4 — barra divergente (variación vs. presupuesto). Alto
   dinámico según cuántas filas tenga el mes, así que no hereda el
   `height: 230px` fijo de .chart. */
.chart-divergente { height: auto; min-width: 560px; }
.chart-var-pos { fill: var(--ok-fg); }
.chart-var-neg { fill: var(--bad-fg); }
.chart-legend-pos::before, .chart-legend-neg::before {
  content: ''; display: inline-block; width: 0.65rem; height: 0.65rem; border-radius: 2px; margin-right: 0.3rem; vertical-align: -1px;
}
.chart-legend-pos::before { background: var(--ok-fg); }
.chart-legend-neg::before { background: var(--bad-fg); }

/* Bloque 5.5 — utilidades para los patrones de `style=` inline más
   repetidos (el v4 midió 267, subiendo de los 217 que el v3 había
   bajado). Se agregan las clases para frenar el crecimiento en
   pantallas NUEVAS; no se barrieron las ocurrencias ya existentes en
   40+ vistas — el riesgo de una migración masiva no compensaba el
   beneficio puramente cosmético en esta ronda. */
.nota { color: var(--ink-soft); font-size: 0.9rem; }
.nota-chica { color: var(--ink-soft); font-size: 0.85rem; }
.subtitulo-card { margin-top: 0; font-size: 1rem; }
.fila-entre { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }

.accesos { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.85rem; }
.acceso { display: block; color: var(--ink); text-decoration: none; margin: 0; transition: border-color .12s ease; }
.acceso:hover { border-color: var(--accent); }

.fila-anulada { background: var(--bad-bg); color: var(--bad-fg); }
.acciones-gasto { white-space: nowrap; }
.acciones-gasto form { display: inline; }

/* ---- buscador ⌘K (Bloque 5) — índice construido en vivo desde los
   .nav-link ya renderizados en el sidebar, nunca una lista aparte que
   se pueda desincronizar de la navegación real ---- */
.cmdk-overlay {
  position: fixed; inset: 0; z-index: 100; background: rgba(17,19,14,0.55);
  display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh;
}
.cmdk-overlay[hidden] { display: none; }
.cmdk-panel {
  width: min(92vw, 560px); background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow); overflow: hidden;
}
.cmdk-input {
  width: 100%; border: 0; border-bottom: 1px solid var(--line); border-radius: 0;
  padding: 0.9rem 1.1rem; font-size: 1rem; background: var(--surface); color: var(--ink);
}
.cmdk-input:focus { outline: none; }
.cmdk-list { list-style: none; margin: 0; padding: 0.4rem; max-height: 55vh; overflow-y: auto; }
.cmdk-item {
  padding: 0.55rem 0.75rem; border-radius: 8px; font-size: 0.9rem; color: var(--ink);
  text-decoration: none; display: block; cursor: pointer;
}
.cmdk-item.activo, .cmdk-item:hover { background: var(--accent); color: var(--accent-ink); }
.cmdk-empty { padding: 1rem 1.1rem; color: var(--ink-faint); font-size: 0.88rem; }
.cmdk-hint {
  padding: 0.5rem 1.1rem; border-top: 1px solid var(--line-soft); font-size: 0.72rem;
  color: var(--ink-faint); display: flex; gap: 0.9rem;
}
.cmdk-hint kbd {
  font-family: 'IBM Plex Mono', monospace; background: var(--surface-sunk); border: 1px solid var(--line);
  border-radius: 4px; padding: 0.05rem 0.35rem; font-size: 0.7rem;
}

/* ---- tablas ordenables (Bloque 5) — opt-in vía data-sortable en <table> ---- */
table[data-sortable] th[data-key] { cursor: pointer; user-select: none; white-space: nowrap; }
table[data-sortable] th[data-key]:hover { color: var(--ink); }
table[data-sortable] th[data-key] .sort-arrow { display: inline-block; width: 0.9em; opacity: 0.5; }
table[data-sortable] th[data-key].sort-activo .sort-arrow { opacity: 1; }

/* ---- calendario de aseo (2026-09-10) ----
   Cada día es un <details>: los que ya pasaron se pliegan. Cada cambio de una
   fila se guarda solo (con JavaScript; sin él queda el botón Guardar). En el
   celular la tabla de siete columnas obligaba a deslizar de lado: debajo de
   760px cada limpieza es una tarjeta con sus rótulos. */
.agenda-ayuda { font-size: 0.8rem; color: var(--ink-soft); margin: 0 0 1rem; max-width: 72ch; }
.solo-js { display: none; }
.agenda-js .solo-js { display: inline; }
.agenda-js .guardar-fila { display: none; }
details.dia [hidden] { display: none !important; }
details.dia > summary { list-style: none; cursor: pointer; }
details.dia > summary::-webkit-details-marker { display: none; }
details.dia[open] > summary { margin-bottom: 0.75rem; }
.dia-titulo { margin: 0; font-size: 0.95rem; display: flex; justify-content: space-between; align-items: center; gap: 0.5rem 1rem; flex-wrap: wrap; }
.dia-nombre, .dia-cuenta { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.dia-nombre::before { content: '▸'; color: var(--ink-faint); font-size: 0.8rem; transition: transform 0.15s ease; }
details.dia[open] .dia-nombre::before { transform: rotate(90deg); }
.dia-titulo .estado { margin-top: 0; }
.dia-total { font-family: 'IBM Plex Sans', sans-serif; font-size: 0.75rem; font-weight: 600; color: var(--ink-faint); }
.tabla-agenda-wrap { overflow-x: auto; }
.tabla-agenda td { vertical-align: top; }
.tabla-agenda select, .tabla-agenda input[type="text"] { min-width: 8.5rem; }
.tabla-agenda .sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.apto-edificio { display: block; font-size: 0.72rem; color: var(--ink-faint); }
.hora-label { display: flex; align-items: center; gap: 0.4rem; margin: 0 0 0.25rem; font-size: 0.72rem; color: var(--ink-soft); white-space: nowrap; }
.hora-label input { width: 6.5rem; padding: 0.35rem 0.5rem; }
/* La hora que se asume cuando el campo está vacío: es lo que ve quien limpia. */
.hora-asumida { font-size: 0.68rem; color: var(--ink-faint); font-style: italic; }
.barra-kunas button.btn { margin-top: 0; }
@media (max-width: 560px) {
  .barra-kunas { gap: 0.5rem 0.75rem; }
  .barra-kunas button.btn { padding: 0.34rem 0.7rem; font-size: 0.78rem; }
}

.hora-vacia {
  color: var(--ink-faint); background: none; border: 0; padding: 0 0.15rem;
  font: inherit; cursor: pointer; border-bottom: 1px dotted var(--ink-faint);
}
.hora-vacia:hover, .hora-vacia:focus-visible { color: var(--ink); }
.nota-express { display: block; font-size: 0.7rem; color: var(--ink-faint); }
.estado.chip-estado { margin: 0 0 0.35rem; }
.select-estado { font-size: 0.8rem; padding: 0.35rem 0.5rem; }
.guardado { display: block; min-height: 1rem; font-size: 0.72rem; color: var(--ink-faint); white-space: nowrap; }
.guardado.ok { color: var(--ok-fg); }
.guardado.error { color: var(--bad-fg); white-space: normal; max-width: 14rem; }
.form-borrar { margin: 0.3rem 0 0; }
.form-borrar .btn-text { margin-left: 0; font-size: 0.75rem; }
.dia-acciones { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1.25rem; margin-top: 0.75rem; padding-top: 0.6rem; border-top: 1px dashed var(--line); }
.agregar-dia > summary { list-style: none; cursor: pointer; color: var(--accent); font-weight: 600; font-size: 0.85rem; }
.agregar-dia > summary::-webkit-details-marker { display: none; }
.agregar-dia[open] { flex-basis: 100%; order: 2; }
.whatsapp .btn-text { font-size: 0.85rem; }
.whatsapp .btn-text:first-child { margin-left: 0; }
.copiado { margin-left: 0.55rem; font-size: 0.75rem; color: var(--ok-fg); }
.texto-whatsapp { margin-top: 0.6rem; font-size: 0.8rem; font-family: 'IBM Plex Mono', monospace; }
@media (max-width: 760px) {
  .tabla-agenda thead { display: none; }
  .tabla-agenda, .tabla-agenda tbody, .tabla-agenda tr, .tabla-agenda td { display: block; width: 100%; }
  .tabla-agenda tr { border: 1px solid var(--line); border-radius: 10px; padding: 0.7rem 0.85rem; margin-bottom: 0.6rem; }
  .tabla-agenda tbody tr:hover { background: transparent; }
  .tabla-agenda td { border: 0; padding: 0.3rem 0; }
  .tabla-agenda td[data-label]::before {
    content: attr(data-label); display: block; margin-bottom: 0.15rem;
    font-size: 0.66rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-faint);
  }
  .tabla-agenda td.celda-express::before { display: inline; margin-right: 0.5rem; }
  .tabla-agenda td.celda-express .nota-express { display: inline; margin-left: 0.4rem; }
  .tabla-agenda td.celda-horas { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
  .tabla-agenda td.celda-horas::before { flex-basis: 100%; }
  .tabla-agenda select, .tabla-agenda input[type="text"] { min-width: 0; }
  .guardado { white-space: normal; }
}

/* ---- navegación por secciones (2026-09-10): 9 secciones en el menú, las
   páginas de cada una como pestañas arriba del contenido, la ruta
   "Sección › Página" clicable y "← Volver a …" en toda sub-página. Todo sale
   de src/navegacion.ts vía partials/nav.ejs. ---- */
.topbar-izq, .topbar-der { display: flex; align-items: center; gap: 0.75rem; min-width: 0; }
.topbar-der { gap: 0.9rem; flex: none; }
.topbar nav.crumb { display: flex; align-items: center; gap: 0.45rem; min-width: 0; overflow: hidden; white-space: nowrap; }
.topbar .crumb a { color: var(--ink-soft); text-decoration: none; }
.topbar .crumb a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.topbar .crumb [aria-current] { color: var(--ink); overflow: hidden; text-overflow: ellipsis; }
.topbar .crumb .sep { color: var(--ink-soft); }
.volver {
  display: inline-flex; align-items: center; gap: 0.3rem; flex: 0 1 auto; min-width: 0;
  padding: 0.32rem 0.75rem; border: 1px solid var(--line); border-radius: 7px;
  background: var(--surface); color: var(--ink); text-decoration: none;
  font-size: 0.83rem; font-weight: 600; white-space: nowrap;
}
.volver:hover { border-color: var(--accent); color: var(--accent); }

.registrar { display: flex; gap: 0.5rem; padding: 1rem 0.8rem 0; }
.registrar a {
  flex: 1; text-align: center; padding: 0.5rem 0.4rem; border-radius: 7px;
  border: 1px solid var(--sidebar-line); color: var(--sidebar-text); text-decoration: none;
  font-family: 'Archivo', 'IBM Plex Sans', sans-serif; font-weight: 700; font-size: 0.82rem;
}
.registrar a:first-child { background: var(--sidebar-accent); border-color: var(--sidebar-accent); color: var(--sidebar-registrar); }
.registrar a:hover { filter: brightness(1.12); }
.nav-group-pie { border-top: 1px solid var(--sidebar-line); padding-top: 0.9rem; }

.seccion-tabs { margin-left: var(--sidebar-w); max-width: 1600px; padding: 4.3rem 2rem 0; }
.seccion-tabs ~ main { padding-top: 1.2rem; }
.pestanas { display: flex; align-items: flex-end; gap: 0.15rem; overflow-x: auto; border-bottom: 1px solid var(--line); scrollbar-width: thin; }
.pestanas a {
  display: inline-flex; align-items: center; gap: 0.4rem; white-space: nowrap;
  padding: 0.55rem 0.8rem; margin-bottom: -1px; border-bottom: 2px solid transparent;
  color: var(--ink-soft); text-decoration: none; font-size: 0.87rem; font-weight: 600;
}
.pestanas a:hover { color: var(--ink); }
.pestanas a.activa { color: var(--accent); border-bottom-color: var(--accent); }
.pestanas .nav-badge { margin-left: 0; }
.pestanas-grupo {
  align-self: center; padding: 0 0.55rem 0 0.1rem; white-space: nowrap;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-soft);
}
.pestanas a.todos { margin-left: auto; color: var(--accent); }

/* Inicio de Reportes: los 22 reportes a la vista, por subgrupo. */
.directorio-reportes { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 1rem 1.4rem; }
.directorio-reportes h3 {
  margin: 0 0 0.45rem; font-family: 'IBM Plex Sans', sans-serif; font-weight: 700;
  font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-soft);
}
.directorio-reportes ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.3rem; }
.directorio-reportes a { color: var(--accent); text-decoration: none; font-weight: 500; }
.directorio-reportes a:hover { text-decoration: underline; }

@media (max-width: 900px) {
  /* El topbar fixed tapaba el comienzo de la página en el celular (main solo
     deja 1,6rem arriba). Pegado arriba pero dentro del flujo, no tapa nada. */
  .topbar { position: sticky; padding: 0.7rem 1rem; }
  .seccion-tabs { margin-left: 0; padding: 0.5rem 1rem 0; }
  .volver .volver-a { display: none; }
}
@media (max-width: 560px) {
  .topbar .volver + .crumb { display: none; }
}
@media print {
  aside.sidebar, .topbar, .seccion-tabs, .sidebar-backdrop { display: none; }
  main { margin-left: 0; padding-top: 0; }
}

/* ---- revisión de UX (2026-09-10): foco visible sobre el menú oscuro (el
   azul de --accent no llega a 3:1 sobre él en tema claro), foco de las
   pestañas sin recorte, toques de 44 px en el celular, el menú cerrado fuera
   del orden de tabulación, "+ Gasto" a un toque en el celular, las vistas
   internas de una pantalla como control segmentado (no otra fila de
   pestañas) y la pantalla de error con salida. ---- */
aside.sidebar a:focus-visible, aside.sidebar button:focus-visible { outline-color: var(--sidebar-accent); }
.pestanas a:focus-visible { outline-offset: -3px; }
.topbar-registrar { display: none; }
/* Un destino largo ("Retención en la fuente") se recorta con "…" en vez de
   montarse sobre los botones de la derecha. */
.volver-destino { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.subpestanas {
  display: inline-flex; flex-wrap: wrap; gap: 0.25rem; padding: 0.25rem; margin: 0 0 1rem;
  border: 1px solid var(--line); border-radius: 9px; background: var(--surface-sunk);
}
.subpestanas a {
  padding: 0.42rem 0.85rem; border-radius: 6px; color: var(--ink-soft);
  text-decoration: none; font-weight: 600; font-size: 0.86rem;
}
.subpestanas a:hover { color: var(--ink); }
.subpestanas a[aria-current] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }
.subpestanas a:focus-visible { outline-offset: -2px; }

.pantalla-error { max-width: 62ch; }
.pantalla-error .error-codigo {
  margin: 0 0 0.3rem; font-family: 'IBM Plex Mono', monospace; font-size: 0.78rem;
  letter-spacing: 0.06em; color: var(--ink-soft);
}
.pantalla-error h1 { font-size: 1.35rem; margin-bottom: 0.5rem; }
.error-acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin-top: 1.1rem; }
.error-acciones .btn-link { margin: 0; }
.error-acciones button.btn-link { border: 0; cursor: pointer; }
main.sin-menu { margin: 0 auto; padding-top: 3rem; max-width: 720px; }

@media (max-width: 900px) {
  aside.sidebar { visibility: hidden; transition: transform 0.2s ease, visibility 0s linear 0.2s; }
  body.sidebar-open aside.sidebar { visibility: visible; transition: transform 0.2s ease; }
  .hamburger, .topbar .theme-toggle { width: 2.75rem; height: 2.75rem; }
  .volver, .topbar-registrar { min-height: 2.75rem; }
  /* .btn-text (padding:0) dejaba "Marcar leída"/"Silenciar"/"Editar" junto al
     "Anular" en rojo, y las acciones de conciliación, con un toque casi del
     tamaño del texto subrayado (2026-09-15, ítem 3). */
  .btn-text { display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0 0.5rem; }
  .acciones-gasto { display: flex; gap: 0.75rem; align-items: center; }
  .topbar-registrar {
    display: inline-flex; align-items: center; padding: 0 0.8rem; border-radius: 7px; white-space: nowrap;
    background: var(--accent); color: var(--accent-ink); text-decoration: none; font-weight: 700; font-size: 0.85rem;
  }
  .topbar-der { gap: 0.5rem; }
  .nav-link { padding-top: 0.75rem; padding-bottom: 0.75rem; }
  .pestanas a { padding-top: 0.8rem; padding-bottom: 0.8rem; }
  .pestanas a.todos { order: -1; margin-left: 0; }
  .subpestanas { display: flex; margin-top: 0.75rem; }
  .subpestanas a { flex: 1 1 auto; text-align: center; padding: 0.7rem 0.6rem; }
}
@media (max-width: 560px) {
  /* "Salir" también está al pie del menú: aquí deja sitio a "+ Gasto". */
  .topbar .salir { display: none; }
}

/* ---- revisión de diseño (2026-09-16) ------------------------------------
   Cuatro cosas que se repetían a mano en 40+ vistas o que solo se notan en
   un celular de 390 px de ancho:

   1. `.cabecera-pagina` / `.acciones-cabecera`: 26 vistas abren con el mismo
      `style="display:flex; justify-content:space-between…"` y un par de
      botones al lado. Como `.btn-link.secondary` trae `margin: 1.1rem 0 0`
      (pensado para ir DEBAJO de un formulario), en esas filas de cabecera
      los botones secundarios quedaban 17 px más abajo que el primario.
   2. Toques de 44 px en el celular para campos y botones: el mínimo que
      Apple y Google recomiendan. Un `input` de 0,58rem de relleno mide unos
      36 px — se falla con el pulgar, que es como se usa esto de verdad.
   3. Márgenes laterales: 2 rem a cada lado en un celular se come 64 de los
      390 px justo donde hay tablas anchas.
   4. `.oculta-movil` para las columnas que no hacen falta para decidir nada
      (moneda cuando todo es COP, marcas de tiempo, retención) y
      `details.ayuda` para la explicación larga que estorba a partir de la
      segunda visita a la pantalla. ------------------------------------- */
.cabecera-pagina { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem 1rem; flex-wrap: wrap; }
.cabecera-pagina > h1 { margin-bottom: 0.6rem; }
.acciones-cabecera { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.acciones-cabecera .btn-link,
.acciones-cabecera .btn-link.secondary,
.acciones-cabecera button.btn { margin: 0; }

/* La explicación larga, plegada: quien ya sabe cómo funciona la pantalla no
   tiene que pasar por encima de tres párrafos cada vez que entra. El texto
   sigue en la página (y en el buscador del navegador), solo empieza cerrado. */
details.ayuda { margin: 0 0 1.1rem; }
details.ayuda > summary {
  display: inline-flex; align-items: center; gap: 0.35rem; min-height: 2.25rem;
  cursor: pointer; list-style: none;
  color: var(--accent); font-weight: 600; font-size: 0.86rem;
}
details.ayuda > summary::-webkit-details-marker { display: none; }
details.ayuda > summary::before { content: '›'; display: inline-block; transition: transform 0.15s ease; }
details.ayuda[open] > summary::before { transform: rotate(90deg); }
details.ayuda > p, details.ayuda > ul { color: var(--ink-soft); font-size: 0.88rem; max-width: 72ch; }
details.ayuda > p:first-of-type { margin-top: 0.4rem; }

/* Estado vacío con salida: "no hay nada" a secas deja a quien lo lee sin
   saber si está mal configurado o si de verdad no hay nada que hacer. */
.vacio-acciones { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: center; margin-top: 0.6rem; }

@media (max-width: 760px) {
  .oculta-movil { display: none; }
}

@media (max-width: 900px) {
  /* Campos y botones que se alcanzan con el pulgar. Las casillas y los radios
     quedan fuera: ahí el área tocable la da el <label>, y estirarlos los
     dibujaría como rectángulos gigantes dentro de las tablas. */
  input:not([type="checkbox"]):not([type="radio"]), select, textarea { min-height: 2.75rem; }
  button.btn, .btn-link {
    min-height: 2.75rem; display: inline-flex; align-items: center; justify-content: center;
  }
}

@media (max-width: 560px) {
  main { padding-left: 1rem; padding-right: 1rem; }
  .seccion-tabs { padding-left: 1rem; padding-right: 1rem; }
  .card { padding: 0.9rem 1rem; }
  /* Botones de ancho completo: apilados, uno debajo de otro, se tocan mejor
     que tres pastillas angostas peleando por la misma línea. */
  .acciones-cabecera { width: 100%; }
  .acciones-cabecera > .btn-link, .acciones-cabecera > button.btn { flex: 1 1 10rem; }
}
