
/* ==========================================================================
   RATIO ERP — sistema visual (calcado de docs/mockups-erp)
   Sidebar oscuro · topbar con buscador · tarjetas con acento · stat tiles ·
   píldoras de estado · barras de avance verde/rojo.
   ========================================================================== */
:root,
[data-theme="ratio-green"] {
  /* Manual de Estilo V1 (julio 2026): Bahnschrift es la familia primaria.
     La jerarquia se define por peso, tamaño, caja y posicion — no por cambiar
     de fuente. SemiBold para titulos/etiquetas/botones/datos; SemiLight para
     parrafos y ayuda. */
  --ratio-font: "Bahnschrift", "Segoe UI", ui-sans-serif, system-ui, sans-serif;
  --ratio-font-mono: "JetBrains Mono", "Fira Code", Consolas, monospace;
  --ratio-radius-xs: 0.25rem;
  --ratio-radius-sm: 0.375rem;
  --ratio-radius: 0.5rem;
  --ratio-radius-lg: 0.75rem;
  --ratio-radius-xl: 1rem;
  --ratio-radius-2xl: 1.5rem;
  --ratio-transition-fast: 0.1s ease;
  --ratio-transition: 0.15s ease;
  --ratio-transition-slow: 0.25s ease;

  /* ─── Manual de Estilo V1: la paleta aprobada ─────────────────────────
     Primary Dark #1F252B  encabezados, barra superior, navegacion, thead
     RATIO Green  #7FB239  acciones prioritarias, activos, marca
     Dark Green   #5E8F2E  enfasis de segundo nivel, estados activos discretos
     Light Gray   #F3F5F7  fondos de seccion, tarjetas, superficies alternas
     Border Gray  #D6DADF  divisores, contornos, lineas de tabla
     Text Dark    #2B2B2B  texto principal
     Success      #6FBF4A  confirmaciones, totales aprobados
     Regla 70/20/10: 70% superficies neutras, 20% Primary Dark y grises,
     maximo 10% de verdes. Los verdes NUNCA en parrafos largos. */
  --color-bg: #f3f5f7;
  --color-surface: #ffffff;
  --color-surface-hover: #f8f9fa;
  --color-surface-muted: #fafbfc;
  --color-surface-soft: #f3f5f7;
  --color-surface-subtle: #edf0f3;
  --color-sidebar: #1f252b;
  --color-sidebar-end: #181d22;
  --color-sidebar-hover: #2a323a;
  --color-sidebar-active-bg: rgba(127, 178, 57, 0.18);
  --color-sidebar-text: #c9cfd5;
  --color-sidebar-muted: #7e888f;
  --color-sidebar-border: rgba(255, 255, 255, 0.08);
  --color-primary: #7fb239;
  --color-primary-hover: #5e8f2e;
  --color-primary-light: #ecf3df;
  --color-primary-ring: rgba(127, 178, 57, 0.2);
  --color-primary-text: #ffffff;
  --color-header-bg: #1f252b;
  --color-header-bg-alt: #262d34;
  --color-header-text: #ffffff;
  --color-header-muted: #e8ebed;
  --color-row-stripe: #f8f9fa;
  --color-row-hover: #eff2ec;
  --color-row-selected: #e3edd2;
  --color-text: #2b2b2b;
  --color-text-strong: #1f252b;
  --color-text-muted: #6a7178;
  --color-text-light: #9aa1a8;
  --color-border: #d6dadf;
  --color-border-light: #e1e5e9;
  --color-border-subtle: #eceff2;
  --color-success: #6fbf4a;
  --color-success-light: #e9f5e1;
  --color-success-soft: #f3f9ee;
  --color-success-border: #c4e3af;
  --color-success-text: #5e8f2e;
  --color-danger: #dc2626;
  --color-danger-light: #fee2e2;
  --color-danger-soft: #fef2f2;
  --color-danger-border: #fecaca;
  --color-danger-text: #b91c1c;
  --color-warning: #d97706;
  --color-warning-hover: #f59e0b;
  --color-warning-light: #fef3c7;
  --color-warning-soft: #fffbeb;
  --color-warning-text: #92400e;
  --color-info: #2563eb;
  --color-info-hover: #1d4ed8;
  --color-info-light: #dbeafe;
  --color-info-soft: #eff6ff;
  --color-info-text: #1d4ed8;
  --color-teal: #0891b2;
  --color-purple: #6d28d9;
  --color-purple-light: #ede9fe;
  --color-purple-border: #c4b5fd;
  --color-purple-dash: #a78bfa;
  --color-purple-tint: rgba(109, 40, 217, 0.06);
  --color-warning-tint: rgba(217, 119, 6, 0.07);
  --color-overlay: rgba(15, 23, 42, 0.45);
  --color-overlay-strong: rgba(0, 0, 0, 0.3);
  --color-shadow-soft: rgba(15, 23, 42, 0.04);
  --color-shadow: rgba(15, 23, 42, 0.08);
  --color-shadow-menu: rgba(15, 23, 42, 0.15);
  --color-shadow-lg: rgba(15, 23, 42, 0.18);
  --color-transparent: transparent;

  --nav: var(--color-sidebar);
  /* ↑ Los alias empiezan aquí y NO se repiten en el tema oscuro: apuntan a los
     tokens base, así que al reemplazar aquellos, estos siguen solos. Es la razón
     de que exista la doble capa. */
  --nav-2: var(--color-sidebar-end);
  --nav-active: var(--color-primary);
  --nav-active-2: var(--color-primary-hover);
  --gold: var(--color-primary);
  --bg: var(--color-bg);
  --panel: var(--color-surface);
  --line: var(--color-border-light);
  --line-2: var(--color-border-subtle);
  --ink: var(--color-text-strong);
  --ink-2: var(--color-text);
  --muted: var(--color-text-muted);
  --muted-2: var(--color-text-light);
  /* EL COLOR DE UN HUECO.

     El dueño lo reportó: «he tenido muchos problemas con los placeholder, se ve
     como si fuera texto ya insertado». Y es el peor error posible en un campo —
     alguien guarda creyendo que capturó, o borra creyendo que había algo.

     Iba en `--muted-2`, el mismo gris que usan las etiquetas secundarias y los
     textos deshabilitados. Ese gris está pensado para LEERSE; una pista de
     captura tiene que hacer lo contrario: verse solo si uno la busca.

     Sobre fondo claro, un gris muy pálido. La contraparte oscura está abajo, en
     su tema, y sigue la misma regla al revés: apenas más claro que el fondo. */
  --placeholder: #c9ced4;
  --blue: var(--color-primary);
  --blue-ink: var(--color-primary-hover);
  --green: var(--color-success);
  --green-ink: var(--color-success-text);
  --red: var(--color-danger);
  --red-ink: var(--color-danger-text);
  --amber: var(--color-warning);
  --amber-ink: var(--color-warning-text);
  --teal: var(--color-teal);
  --shadow: 0 1px 2px var(--color-shadow-soft), 0 4px 12px rgba(15, 23, 42, 0.05);
}
* { box-sizing: border-box; }
html, body, #root { height: 100%; }
body {
  margin: 0;
  font-family: var(--ratio-font);
  /* Bahnschrift es variable: el cuerpo respira mas ligero (SemiLight del
     manual) y la jerarquia la ponen los pesos 600 de titulos y etiquetas. */
  font-weight: 380;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* ---------- layout general ---------- */
.shell { display: grid; grid-template-columns: 220px minmax(0, 1fr); min-height: 100%; }
.shell > div { min-width: 0; }

/* ---------- sidebar ---------- */
.sidebar {
  background: linear-gradient(180deg, var(--nav) 0%, var(--nav-2) 100%);
  color: var(--color-sidebar-text);
  display: flex;
  flex-direction: column;
  padding: 10px 14px 22px;
  position: sticky;
  top: 0;
  height: 100vh;
}
.logo { display: flex; align-items: center; justify-content: center; padding: 10 10 10 10; width: 100%; }
.logo img { width: auto; height: 92px; object-fit: contain; display: block; border-radius: var(--ratio-radius-sm); }
.logo span { display: none; }
.nav { display: flex; flex-direction: column; gap: 3px; }
.nav a {
  display: flex; align-items: center; gap: 5px;
  padding: 5px 12px; border-radius: 7px;
  color: var(--color-sidebar-text); text-decoration: none; font-size: 13px; font-weight: 400;
  cursor: pointer; border: 0; background: none; text-align: left; width: 100%;
}
.nav a:hover { background: var(--color-sidebar-hover); color: var(--color-header-text); }
.nav a.active {
  background: linear-gradient(90deg, var(--nav-active) 0%, var(--nav-active-2) 100%);
  color: var(--color-primary-text); font-weight: 600; box-shadow: inset 0 0 0 1px var(--color-sidebar-border);
}
.nav-ico { width: 18px; text-align: center; font-size: 15px; opacity: 0.9; }
.sidebar .foot { margin-top: auto; color: var(--color-sidebar-muted); font-size: 11px; padding: 0 8px; }

/* ---------- topbar ---------- */
.topbar {
  display: flex; align-items: center; gap: 16px;
  padding: 14px 28px; background: var(--panel); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 10;
}
.search {
  flex: 1; max-width: 620px;
  display: flex; align-items: center; gap: 10px;
  background: var(--color-surface-soft); border: 1px solid var(--line); border-radius: 10px;
  padding: 9px 14px; color: var(--muted); font-size: 14px;
}
.search input { border: 0; background: none; outline: none; width: 100%; font-size: 14px; color: var(--ink); }
.topbar .spacer { flex: 1; }
.identity { display: flex; align-items: center; gap: 10px; }
.identity select {
  padding: 8px 10px; border-radius: 9px; border: 1px solid var(--line);
  background: var(--panel); color: var(--ink); font-size: 13px; max-width: 320px;
}
.avatar {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  background: var(--blue); color: var(--color-primary-text); display: grid; place-items: center;
  font-weight: 700; font-size: 13px;
}

/* ---------- contenido ---------- */
.content { padding: 26px 32px 60px; min-width: 0; overflow-x: auto; }
.page-head { margin-bottom: 18px; }
/* Manual: titulo de pantalla en Bahnschrift SemiBold 20-24, MAYUSCULAS, una
   sola vez por pantalla, arriba a la izquierda. Las mayusculas van por CSS para
   que el contenido siga escrito en tipo oracion — cambiar la regla mañana no
   obliga a reescribir pantallas. */
.page-head h1 { margin: 0; font-size: 22px; font-weight: 600;
                text-transform: uppercase; letter-spacing: 0.04em; }
/* `.crumb` es tipografia, no posicion: describe «texto secundario bajo un
   titulo», y eso no depende de tener un `.page-head` arriba. Estaba escrita solo
   como descendiente, asi que los usos fuera de un encabezado —CostosPanel y
   SaludEjecucion— salian con el texto de cuerpo: mas grandes y mas oscuros que
   los otros 19 crumbs, justo donde debian ser secundarios. */
.crumb { color: var(--muted); font-size: 14px; }
.page-head .crumb { margin-top: 4px; }

/* `.pill` sin modificador de color no pinta nada: la base solo da forma. Faltaba
   `teal`, que usan cuatro lugares para marcar contenido del HUB — se veian como
   texto de 9px en negritas sin capsula, que parece una errata. El token --teal
   ya existia y solo lo consumia `.tile.teal`. */
.pill.teal { background: var(--color-info-light); color: var(--teal); }

/* Fila de filtros en forma de chip. Existia `.chip-filter` pero
   ReaperturasBandeja usaba `chip` / `chip on`, que no estan en ningun .css.
   Pero al arreglarlo salio que `.chip-filter.active` TAMPOCO existia: Conocimiento
   ya venia marcando `active` en cuatro botones sin que se viera nada. O sea que
   el estado activo de esta fila nunca funciono en ninguna parte.

   Se resuelve con UNA sola grafia, `.active`, que es la de `.tab.active` — el
   estado activo se llama igual en toda la casa. Agregar `.on` para Reaperturas
   habria dejado tres grafias y una de ellas seguiria muerta. */
.chip-filter.active { background: var(--blue-ink); color: var(--color-primary-text); border-color: var(--blue-ink); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }

/* ---------- tabs / filtros ---------- */
.tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--line); margin: 6px 0 20px; flex-wrap: wrap; }
.tab {
  padding: 8px 14px; border-radius: 8px 8px 0 0; font-size: 13px; font-weight: 600;
  color: var(--muted); background: none; border: 0; cursor: pointer;
}
/* Activa = subrayada, IGUAL que nivel-1. No es redundancia con la regla de
   abajo: es que `tabs` a secas tiene que verse como algo que ya existe.

   Antes esta linea rellenaba la pestana de azul solido, y eso creaba un TERCER
   aspecto que ninguna pantalla habia elegido — solo lo heredaba quien escribia
   `className="tabs"` sin nivel. Asi acabaron seis modulos (Admin, Contabilidad,
   Finanzas, KPIs, Proyectos, RH) con barra rellena mientras Compras y Ventas,
   con el MISMO rol, la tenian subrayada. El mismo rol se veia de dos maneras
   segun quien escribio la pantalla.

   Se arreglaron los seis llamadores, pero eso solo limpia el presente: el
   siguiente que escriba `tabs` sin nivel caeria en la misma trampa. Que la base
   sea el nivel 1 hace que omitir el nivel de el aspecto correcto por omision,
   porque la barra de modulo es el caso comun. */
.tab.active { color: var(--blue-ink); background: none; border-bottom: 2px solid var(--blue-ink); }
.tab:not(.active):hover { color: var(--ink); background: var(--color-surface-subtle); }

/* ---------- tabs de dos niveles ----------
   Nivel 1 = navegación de PROCESO del módulo (áreas). Prominente, tipo pestaña.
   Nivel 2 = filtros dentro de un área (estado, etc.). Secundario, tipo segmento. */
.tabs.nivel-1 { gap: 4px; border-bottom: 2px solid var(--line); margin: 6px 0 18px; }
.tabs.nivel-1 .tab {
  font-size: 14px; font-weight: 650; padding: 10px 18px; border-radius: 8px 8px 0 0;
  margin-bottom: -2px; border-bottom: 2px solid transparent; background: none; color: var(--muted);
}
.tabs.nivel-1 .tab.active { color: var(--blue-ink); background: none; border-bottom-color: var(--blue-ink); }
.tabs.nivel-1 .tab:not(.active):hover { color: var(--ink); background: var(--color-surface-subtle); }

.tabs.nivel-2 { gap: 6px; border-bottom: 0; margin: 0 0 14px; }
.tabs.nivel-2 .tab {
  /* Radio 1px, elegido por el dueño: primero fueron cápsulas de 999px, luego
     7px y quedó en 1 —«ponle mejor radio 1»—. Como cápsulas competían con las
     pastillas de estado: mismo contorno redondo, significado distinto. Se edita
     solo aquí porque es un control común: las pestañas de segundo nivel de
     todos los módulos cambian con esta línea. */
  font-size: 12.5px; font-weight: 600; padding: 5px 12px; border-radius: 1px;
  border: 1px solid var(--line); background: var(--color-surface-subtle); color: var(--muted);
}
.tabs.nivel-2 .tab.active { background: var(--blue-ink); color: var(--color-primary-text); border-color: var(--blue-ink); }
.tabs.nivel-2 .tab:not(.active):hover { color: var(--ink); border-color: var(--muted); }

.chip-filter { padding: 6px 12px; border-radius: 999px; border: 1px solid var(--line); background: var(--panel); color: var(--muted); font-size: 12px; }

/* ---------- botones ---------- */
/* Manual: boton = verbo de accion en MAYUSCULAS, Bahnschrift SemiBold 10-11.
   UNA accion principal (verde) por zona; lo demas es secundario. Las
   mayusculas van por CSS, no reescribiendo cada etiqueta. */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--color-primary); color: var(--color-primary-text); border: 0; border-radius: 8px;
  padding: 9px 16px; font-size: 12px; font-weight: 600; cursor: pointer;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.btn:hover { filter: brightness(1.07); }
.btn.green { background: var(--green); }
.btn.ghost { background: var(--panel); color: var(--color-text-strong);
             border: 1px solid var(--color-border); }
.btn.sm { padding: 5px 10px; font-size: 12px; }
.mini-select { padding: 4px 6px; border: 1px solid var(--line); border-radius: 7px; font-size: 12px; background: var(--panel); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.btn-stack .role { font-size: 11px; color: var(--muted); padding-left: 2px; }

/* ---------- stat tiles ---------- */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 14px; margin-bottom: 20px; }
.tile {
  background: var(--panel); border: 1px solid var(--line); border-top: 3px solid var(--blue);
  border-radius: 12px; padding: 14px 16px; box-shadow: var(--shadow);
}
.tile.green { border-top-color: var(--green); }
.tile.amber { border-top-color: var(--amber); }
.tile.red { border-top-color: var(--red); }
.tile.teal { border-top-color: var(--teal); }
.tile .k { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--muted); }
.tile .v { font-size: 24px; font-weight: 800; margin-top: 4px; letter-spacing: -0.5px; }

/* Un tile que lleva a algun lado. Que se pueda hacer clic tiene que verse ANTES
   del clic: hasta el 2026-07-27 el Resumen de Compras pintaba dos filas de
   tiles identicas donde solo una navegaba, y nada las distinguia.
   Se hereda de `.tile` a proposito, sin `border: none` — aquellos botones lo
   traian y con eso borraban la franja superior de color, que es lo unico que
   codifica la severidad del numero. */
button.tile {
  font: inherit; text-align: left; width: 100%; cursor: pointer;
  transition: box-shadow .12s ease, transform .12s ease;
}
button.tile:hover { box-shadow: 0 4px 14px rgb(0 0 0 / 12%); transform: translateY(-1px); }
button.tile:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

/* ---------- tarjetas ---------- */
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow); }
.card.pad { padding: 20px; }
/* Titulo de seccion: SemiBold 14-16, MAYUSCULAS (manual, tabla de jerarquia). */
.card-title { font-size: 14px; font-weight: 600; margin: 0 0 14px;
              text-transform: uppercase; letter-spacing: 0.03em;
              color: var(--color-text-strong); }

/* ---------- lista de proyectos ---------- */
/* La cartera vive en TablaDatos (el formato unificado de tablas, como las
   órdenes de compra — dueño 2026-08-24): orden acumulable y filtros por
   columna. Aquí quedan solo las piezas propias de sus celdas: el contador
   —el número manda, lo vencido en rojo abajo, el cero en gris— y las señales. */
/* El AVANCE kanban: 7 columnas-fase sobre las filas del plan (dueño,
   2026-08-24) — el espíritu del control legado, sin ser copia exacta. */
.kanban-avance { display: grid; grid-template-columns: repeat(7, minmax(160px, 1fr));
  gap: 10px; overflow-x: auto; padding-bottom: 6px; }
.col-fase { background: var(--color-surface-subtle); border: 1px solid var(--line);
  border-radius: 12px; padding: 10px; display: grid; gap: 8px; align-content: start; }
.col-fase .cf-cabeza { display: flex; justify-content: space-between;
  align-items: baseline; font-size: 13px; font-weight: 700; }
.col-fase .cf-cabeza b { font-variant-numeric: tabular-nums; color: var(--green); }
.col-fase .cf-peso { font-size: 10.5px; margin-top: -4px; }
.carta-paso { background: var(--panel); border: 1px solid var(--line);
  border-radius: 9px; padding: 7px 9px; display: grid; gap: 5px; }
.carta-paso .cp-nombre { font-size: 11.5px; line-height: 1.25; }
.carta-paso .cp-pie { display: flex; justify-content: flex-end; }
.carta-paso .cp-pie input { width: 56px; text-align: right; padding: 2px 6px;
  font-size: 12px; }

.cont-cartera { font-weight: 700; font-variant-numeric: tabular-nums; }
.cont-cartera.cero { color: var(--muted); font-weight: 400; }
.cont-cartera .venc { display: block; font-size: 10px; font-weight: 700; color: var(--red, #C4453A); }
.senales-cartera { display: flex; gap: 4px; flex-wrap: wrap; }
.kv { display: grid; grid-template-columns: auto auto; gap: 4px 16px; font-size: 12px; align-items: baseline; }
.kv .lbl { color: var(--muted); text-align: right; }
.kv .val { font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.avance-wrap { display: flex; align-items: center; gap: 10px; width: 100%; justify-content: flex-end; }

/* abreviaturas de estado (AC EN FA...) */
.abbr { font-size: 10px; font-weight: 700; letter-spacing: 0.5px; color: var(--muted); background: var(--color-surface-subtle); border-radius: 5px; padding: 3px 7px; }
.abbr.on { background: var(--green); color: var(--color-primary-text); }

/* ---------- barras ---------- */
.bar { height: 9px; border-radius: 999px; background: var(--color-border-subtle); overflow: hidden; min-width: 120px; flex: 1; }
.bar > span { display: block; height: 100%; background: var(--green); border-radius: 999px; }
.bar.over > span { background: var(--red); }
.bar.minbar { position: relative; }
.bar.minbar .marca { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--nav); border-radius: 2px; }
.bar-row { display: grid; grid-template-columns: 120px 1fr 52px; gap: 14px; align-items: center; padding: 9px 0; }
.bar-row .name { font-size: 13px; }
.bar-row .pct { text-align: right; font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.bar-row .pct.over { color: var(--red); }

/* ---------- píldoras ---------- */
.pill { display: inline-flex; align-items: center; font-size: 11px; font-weight: 700; border-radius: 999px; padding: 3px 10px; }
.pill.green { background: var(--color-success-light); color: var(--green-ink); }
.pill.red { background: var(--color-danger-light); color: var(--red-ink); }
.pill.amber { background: var(--color-warning-light); color: var(--color-warning-text); }
.pill.blue { background: var(--color-info-light); color: var(--color-info-text); }
.pill.gray { background: var(--color-surface-subtle); color: var(--muted); }

/* ---------- tablas ---------- */
.tbl-wrap { overflow-x: auto; border-radius: 12px; border: 1px solid var(--line); }
table.tbl { width: 100%; border-collapse: collapse; font-size: 13px; background: var(--panel); }
table.tbl thead th {
  background: var(--color-header-bg); color: var(--color-header-muted); text-align: left; font-weight: 600;
  padding: 11px 14px; font-size: 12px; white-space: nowrap;
}
table.tbl tbody td { padding: 11px 14px; border-bottom: 1px solid var(--line-2); }
table.tbl tbody tr:last-child td { border-bottom: 0; }
table.tbl tbody tr:hover { background: var(--color-row-stripe); }
table.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
table.tbl .link { color: var(--blue-ink); font-weight: 700; cursor: pointer; }

/* ---------- rail HUB ---------- */
.rail-group { margin-bottom: 16px; }
.rail-group h4 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); margin: 0 0 7px; }
.rail-link { color: var(--blue-ink); font-size: 13px; padding: 3px 0; cursor: default; }
.rail-empty { color: var(--muted-2); font-size: 12px; font-style: italic; }

/* ---------- leyenda de permisos ---------- */
.legend { display: flex; align-items: center; gap: 14px; font-size: 12px; color: var(--muted); }
.legend .dot { display: inline-flex; align-items: center; gap: 6px; }
.legend .dot::before { content: ""; width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.legend .pagina::before { background: var(--nav); }
.legend .info::before { background: var(--blue); }
.legend .boton::before { background: var(--gold); }

/* ---------- selector de cuentas (Finanzas) ---------- */
.acct-tabs { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.acct {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px 16px; cursor: pointer; min-width: 180px; text-align: left;
}
.acct:hover { border-color: var(--blue); }
.acct.active { border-color: var(--blue); box-shadow: 0 0 0 2px var(--color-primary-ring); }
.acct-name { font-weight: 700; font-size: 14px; display: flex; align-items: center; gap: 8px; }
.acct-sub { color: var(--muted); font-size: 11px; }
.pill.sm-pill { font-size: 9px; padding: 2px 7px; }

/* ---------- tabla de flujo (matriz concepto × periodo) ---------- */
table.flujo-tabla tr.fl-pos td { color: var(--green-ink); }
table.flujo-tabla tr.fl-neg td { color: var(--red-ink); }
table.flujo-tabla tr.fl-sub td { background: var(--color-success-soft); border-top: 1px solid var(--color-success-border); font-weight: 700; }
table.flujo-tabla tr.fl-sub-neg td { background: var(--color-danger-soft); border-top: 1px solid var(--color-danger-border); color: var(--red-ink); font-weight: 700; }
table.flujo-tabla tr.fl-total td { background: var(--color-surface-soft); border-top: 1.5px solid var(--nav); font-weight: 800; color: var(--nav); }
table.flujo-tabla tr.fl-grand td { background: var(--nav); color: var(--color-header-text); border-top: 3px double var(--color-header-bg-alt); font-weight: 800; }
table.flujo-tabla tr.fl-grand td strong { color: var(--gold); }
table.flujo-tabla thead th { position: sticky; top: 0; }

/* ---------- planeados / escenarios ---------- */
.proj-legend { margin-left: 16px; display: inline-flex; gap: 6px; }
.chip-legend { font-size: 10px; font-weight: 700; border-radius: 999px; padding: 2px 8px; border: 1px solid var(--line); }
.chip-legend.real { background: var(--panel); color: var(--muted); }
.chip-legend.mixta { background: var(--color-warning-light); color: var(--color-warning-text); }
.chip-legend.planeada { background: var(--color-purple-light); color: var(--color-purple); border-color: var(--color-purple-border); }
/* Columnas planeadas: hacha diagonal + color de acento */
table.flujo-tabla td.tipo-planeada, table.flujo-tabla th.tipo-planeada { background: repeating-linear-gradient(45deg, var(--color-transparent) 0 6px, var(--color-purple-tint) 6px 8px); }
table.flujo-tabla td.tipo-mixta, table.flujo-tabla th.tipo-mixta { background: repeating-linear-gradient(45deg, var(--color-transparent) 0 6px, var(--color-warning-tint) 6px 8px); }
table.flujo-tabla th.tipo-planeada { color: var(--color-purple-light); border-top: 2px dashed var(--color-purple-dash); }
table.flujo-tabla th.tipo-mixta { color: var(--color-warning-light); border-top: 2px dashed var(--color-warning-hover); }
.mark-plan { font-size: 10px; margin-left: 2px; }
/* Barras del gráfico */
.flujo-bar.tipo-planeada { opacity: 0.6; border: 1px dashed var(--color-purple); }
.flujo-bar.tipo-mixta { opacity: 0.85; border-top: 1px dashed var(--color-warning-text); }
.flujo-lbl.tipo-planeada { color: var(--color-purple); font-weight: 700; }
.flujo-lbl.tipo-mixta { color: var(--color-warning-text); font-weight: 700; }

/* ---------- gráfico de flujo (barras positivas/negativas) ---------- */
.flujo-chart { display: flex; gap: 8px; align-items: stretch; overflow-x: auto; padding: 6px 2px 4px; }
.flujo-col { display: flex; flex-direction: column; align-items: center; min-width: 56px; flex: 1; }
.flujo-top, .flujo-bot { width: 100%; display: flex; justify-content: center; align-items: flex-end; position: relative; }
.flujo-bot { align-items: flex-start; }
.flujo-axis { width: 100%; height: 1px; background: var(--nav); opacity: 0.4; }
.flujo-bar { width: 68%; border-radius: 4px 4px 0 0; min-height: 3px; }
.flujo-bar.in { background: var(--green); }
.flujo-bar.out { background: var(--red); border-radius: 0 0 4px 4px; }
.flujo-lbl { font-size: 11px; color: var(--muted); margin-top: 4px; text-align: center; font-variant-numeric: tabular-nums; }

/* ---------- gantt (timing) ---------- */
.gantt-row { display: grid; grid-template-columns: 200px 1fr; gap: 12px; align-items: center; }
.gantt-lbl { font-size: 13px; }
.gantt-track { position: relative; height: 22px; background: var(--color-surface-soft); border-radius: 6px; }
.gantt-bar { position: absolute; top: 3px; height: 16px; border-radius: 5px; background: var(--muted); display: flex; align-items: center; justify-content: center; min-width: 24px; }
.gantt-bar span { font-size: 10px; color: var(--color-primary-text); font-weight: 700; }
.gantt-bar.green { background: var(--green); }
.gantt-bar.blue { background: var(--blue); }
.gantt-bar.red { background: var(--red); }
.gantt-bar.gray { background: var(--muted); }

/* ---------- editor de permisos ---------- */
.chip-x { margin-left: 6px; cursor: pointer; font-weight: 700; opacity: 0.6; }
.chip-x:hover { opacity: 1; color: var(--red); }

/* ---------- reportes financieros ---------- */
.fld { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); font-weight: 600; }
.fld input { padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; font-size: 13px; }
table.statement { width: 100%; border-collapse: collapse; font-size: 13.5px; }
table.statement td { padding: 7px 8px; border-bottom: 1px solid var(--line-2); }
table.statement td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Manual: «valores numericos a la derecha; totales en verde». */
table.statement tr.total td { font-weight: 700; border-bottom: 1.5px solid var(--nav);
                              color: var(--color-success-text); }
table.statement tr.grand td { font-size: 15px; color: var(--nav); border-bottom: 3px double var(--nav); }
.aging { display: flex; gap: 18px; align-items: flex-end; height: 130px; padding: 0 8px; }
.aging-col { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; flex: 1; gap: 6px; }
.aging-bar { width: 70%; max-width: 60px; border-radius: 6px 6px 0 0; background: var(--muted); }
.aging-bar.green { background: var(--green); }
.aging-bar.amber { background: var(--amber); }
.aging-bar.red { background: var(--red); }
.aging-val { font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.aging-lbl { font-size: 11px; color: var(--muted); }

/* ---------- banners / avisos ---------- */
.banner { border-radius: 10px; padding: 12px 16px; font-size: 13px; margin: 14px 0; border-left: 4px solid var(--blue); background: var(--color-info-soft); color: var(--ink-2); }
.banner.error { border-left-color: var(--red); background: var(--color-danger-soft); color: var(--red-ink); }
.banner.ok { border-left-color: var(--green); background: var(--color-success-soft); color: var(--green-ink); }
/* Aviso: lo que va a pasar es correcto pero no tiene vuelta. Ni error (no hay
   nada mal) ni info (el azul no frena a nadie). Lo usa la confirmacion de
   enviar una OC al proveedor, que es su punto de no retorno. */
.banner.aviso { border-left-color: var(--amber); background: var(--color-warning-soft); color: var(--amber-ink); }

/* Barra de periodo + buscador. El SELECTOR recorta por fecha; el BUSCADOR no
   lo obedece, y esa es la decision: cuando uno busca una actividad concreta no
   se acuerda de cuando la cerro, y si el buscador respetara el filtro, no
   encontrarla no distinguiria «no existe» de «esta fuera del rango». */
.barra-periodo {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 10px 14px; margin-bottom: 14px; flex-wrap: wrap;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--color-surface-soft);
}
.periodo { display: flex; border: 1px solid var(--line); border-radius: 1px; overflow: hidden; }
.periodo button {
  background: var(--panel); color: var(--muted); border: 0;
  border-right: 1px solid var(--line); padding: 6px 13px; font-size: 12px;
  font-weight: 600; cursor: pointer;
}
.periodo button:last-child { border-right: 0; }
.periodo button.activo { background: var(--color-primary); color: var(--color-primary-text); }

/* ---------- mis actividades: los tres cubos ---------------------------------
   Cada cubo es una seccion con encabezado propio, separada por 1px. No son
   tarjetas flotantes: el dueno pidio «separar con bordes finos los campos o
   secciones», y con tres bloques uno tras otro las sombras compiten entre si. */
.cubo-cabeza {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 20px; background: var(--color-surface-soft);
  border-bottom: 1px solid var(--line);
}
.cubo-tit {
  display: flex; align-items: center; gap: 9px; font-size: 11.5px; font-weight: 600;
  letter-spacing: .05em; text-transform: uppercase; color: var(--ink);
}
.cubo-tit svg { width: 15px; height: 15px; color: var(--muted); }
/* El «por que» explica en minusculas por que esa tarea esta en ESE cubo. Sin
   el, tres listas de tareas seguidas se leen como una sola cortada en pedazos. */
.cubo-porque {
  font-size: 11.5px; color: var(--muted); font-weight: 380;
  text-transform: none; letter-spacing: 0;
}
/* Lo que queda de las filas de actividad: ahora viven DENTRO de la tabla del
   sistema (`.tbl`), asi que solo hacen falta el titulo y la fecha. La lista
   propia se retiro porque el dueno lo pidio: «las nuevas interfaces no
   corresponden a los estilos de otras ordenes». El listado de OC es la misma
   clase de pantalla y usa `.tbl`; dos maneras de pintar una lista se ven como
   dos aplicaciones distintas. */
.ft-titulo { font-size: 13.5px; font-weight: 600; color: var(--ink); }
/* Un texto que abre algo se anuncia al pasar el cursor, no antes: subrayarlo
   siempre convertiria la tabla en un muro de links. */
.enlace { cursor: pointer; }
.enlace:hover { color: var(--blue-ink); text-decoration: underline; }
.ft-fecha { font-variant-numeric: tabular-nums; white-space: nowrap; }
.ft-fecha small { display: block; color: var(--muted); font-size: 11px; margin-top: 2px; }
.ft-fecha.tarde { color: var(--red-ink); font-weight: 600; }
/* La vencida se marca por el filo, igual que la OC urgente en su listado. */
.tbl tbody tr.vencida td:first-child { box-shadow: inset 3px 0 0 var(--red); }
.tbl td.der, .tbl th.der { text-align: right; }

/* El selector dentro de una celda de rejilla: lo dibuja la cuadricula, no el.
   Mismo componente que el resto del ERP —con su buscador— pero sin su propio
   recuadro, que dentro de la tabla se veria como una caja dentro de otra. */
.selbus-compacto .selbus-caja {
  border: 0; border-radius: 0; background: transparent; padding: 8px 10px;
  font-size: 13px; min-height: 0; width: 100%;
}
.selbus-compacto .selbus-caja:focus {
  box-shadow: inset 0 0 0 2px var(--color-primary); background: var(--color-primary-light);
}

/* ---------- rejilla de captura tipo hoja de calculo -------------------------
   La pidio el dueno para dar de alta tareas en masa. Las celdas NO llevan borde
   propio: el borde lo pone la cuadricula de la tabla, y asi se ve como una hoja
   y no como cien inputs pegados — que es la diferencia entre parecer Excel y
   parecer un formulario largo. */
.rejilla { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--panel); }
.rejilla-scroll { overflow: auto; max-height: 58vh; }
.rejilla-tabla { width: 100%; border-collapse: collapse; }
.rejilla-tabla thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--color-header-bg); color: var(--color-header-muted);
  text-align: left; font-weight: 600; padding: 9px 10px; font-size: 11px;
  letter-spacing: .04em; text-transform: uppercase; white-space: nowrap;
}
.rejilla-tabla td { border-bottom: 1px solid var(--line-2); border-right: 1px solid var(--line-2); padding: 0; }
.rejilla-tabla td:last-child { border-right: 0; }
.rejilla-tabla .rj-num {
  width: 40px; text-align: right; padding: 0 8px; font-size: 11.5px;
  color: var(--muted-2); background: var(--color-surface-soft);
  font-variant-numeric: tabular-nums; user-select: none;
}
.rejilla-tabla .rj-acc { width: 38px; text-align: center; }

/* LA COLUMNA QUE NO SE ESCRIBE. En la bitácora del día conviven lo que el
   sistema arma —día, jornada, movimientos— y lo único que se teclea, la nota.
   Sin una diferencia visible, alguien se planta en «Jornada» esperando corregir
   una hora y no pasa nada; el fondo tenue dice «esto se lee» antes del clic.

   Fondo y no color de texto: bajarle el contraste a la letra haría ilegible
   justo el dato que se está mirando. */
.rj-lectura {
  display: inline-block; width: 100%; padding: 8px 10px;
  font-size: 13px; color: var(--ink);
}
.rejilla-tabla td:has(> .rj-lectura) {
  background: var(--panel-2, rgba(127, 127, 127, .06));
}
.rj-lectura.enlace { cursor: help; text-decoration-style: dotted; }

/* LOS ICONOS DE RENGLÓN (guardar · editar · descartar) de la bitácora del día.
   Van dentro de la fila y no en una barra de la hoja: guardar es de ESE día. */
.rj-acciones { display: flex; gap: 2px; justify-content: center; padding: 4px 2px; }
.rj-icono {
  background: none; border: 0; padding: 3px; border-radius: 6px;
  color: var(--muted); cursor: pointer; line-height: 0;
}
.rj-icono:hover:not(:disabled) { background: var(--hover, rgba(127,127,127,.14)); color: var(--ink); }
.rj-icono:disabled { opacity: .28; cursor: default; }
.rj-icono svg { width: 15px; height: 15px; }

/* Un renglón DADO DE BAJA: sigue explicando lo viejo pero ya no se ofrece.
   Se apaga en vez de esconderse — una plantilla desactivada que desaparece deja
   sin explicación a las evaluaciones que se hicieron con ella. */
.fila-apagada { opacity: .55; }

/* LAS DOS DECISIONES del tiempo extra, lado a lado (dueño, 2026-09-02): «en una
   misma fila pero dos columnas». En pantalla angosta se apilan — dos columnas
   de 150px son dos columnas ilegibles, y ahí importa más leerlas que verlas
   juntas. El borde fino las separa: con solo espacio, los botones de un lado se
   leen como del otro. */
.columnas-veredicto {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.lado-veredicto {
  border: 1px solid var(--line-2); border-radius: 8px; padding: 8px 10px;
}
.rj-celda {
  width: 100%; border: 0; background: transparent; color: var(--ink);
  font: inherit; font-size: 13px; padding: 8px 10px; outline: none;
}
/* TODOS los campos, no solo los de la rejilla. Antes esta era la única regla
   de placeholder del sistema, así que un input de formulario usaba el gris que
   trae el navegador —bastante oscuro— y ahí nacía la confusión.

   `opacity: 1` hace falta: Firefox le baja la opacidad al placeholder por su
   cuenta, y sin esto el color de aquí saldría distinto en cada navegador. */
input::placeholder,
textarea::placeholder,
.rj-celda::placeholder { color: var(--placeholder); opacity: 1; }

/* Al escribir en el campo, la pista se atenúa en los navegadores que la siguen
   mostrando: ahí ya hay texto de verdad con el que competir.

   .8 y no .65: el campo con el foco puesto y todavía VACÍO es justo donde hace
   falta leer la pista, y bajarla tanto deshacía en el momento de usarla lo que
   se acaba de ganar subiendo el color. */
input:focus::placeholder,
textarea:focus::placeholder { color: var(--placeholder); opacity: .8; }

/* «Estás validando tu propio trabajo». Texto dentro del formulario y no un
   popup (dueño, 2026-08-31): un diálogo de confirmación se cierra sin leerse,
   y esto no es una pregunta —el paso está permitido— sino una constancia que
   tiene que estar a la vista mientras se llena. Ámbar y con barra a la
   izquierda, el mismo lenguaje del resto de los avisos, pero sin la caja
   completa: pesa menos que un banner porque no interrumpe, acompaña. */
.dt-autovalidacion {
  font-size: 12px; line-height: 1.45; color: var(--amber-ink);
  border-left: 3px solid var(--amber); padding: 2px 0 2px 10px; margin-top: 4px;
}

/* ── SOLICITUDES DE PERMISO ───────────────────────────────────────────────
   Una pantalla para tres escritorios (empleado, jefe, RH). Los estilos son
   compartidos a propósito: el trámite es el mismo y verlo distinto según quién
   entra haría dudar de si es el mismo documento. */

/* La marca del campo obligatorio. Existía como estilo suelto en cada
   formulario; aquí tiene nombre para que todos digan lo mismo. */
.req-marca { color: var(--red); }
/* LA ETIQUETA Y SU ASTERISCO, en UN solo hijo del label.
   `.form-grid label` es flex en columna y ahí cada hijo es un renglón —el texto
   suelto incluido, que el navegador envuelve en un elemento anónimo—, así que
   «Motivo» y el `*` salían en dos líneas. Lo cazó el dueño (2026-09-02) en
   «Registrar salida», pero pasaba en los diez campos obligatorios. */
.etiqueta-campo { display: inline; }

.fila-permiso {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 10px 2px; cursor: pointer;
  /* Borde fino entre renglones: separa sin encajonar. */
  border-bottom: 1px solid var(--line-2);
}
.fila-permiso:last-child { border-bottom: 0; }
.fila-permiso:hover { background: var(--color-surface-hover); }

.acciones-permiso {
  margin-top: 12px; padding: 10px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--color-surface-soft);
}
.acciones-permiso input { width: 100%; }

.lista-evidencias { display: flex; flex-wrap: wrap; gap: 8px; }
.evidencia {
  display: flex; align-items: center; gap: 8px; text-decoration: none;
  color: var(--ink); border: 1px solid var(--line); border-radius: 8px;
  padding: 6px 10px; max-width: 260px;
}
.evidencia:hover { border-color: var(--blue); }
.evidencia strong {
  display: block; font-size: 12px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}

/* La conversación tiene ALTO MÁXIMO y scroll propio: sin eso, un trámite con
   diez idas y vueltas empuja los botones de acción fuera de la pantalla, que
   es justo cuando más falta hacen. */
.conversacion-permiso {
  max-height: 260px; overflow-y: auto; display: flex; flex-direction: column;
  gap: 8px; padding-right: 4px;
}
.mensaje {
  border-left: 3px solid var(--line); padding: 4px 0 4px 10px; font-size: 13px;
}
.mensaje-cabeza {
  display: flex; gap: 8px; align-items: center; font-size: 11px;
  margin-bottom: 2px;
}
/* Lo que escribió el SISTEMA se lee como bitácora, no como conversación: en
   gris y sin peso. Distinguirlo evita que «El jefe autorizó» parezca algo que
   alguien tecleó. */
.mensaje.sistema { color: var(--muted); font-style: italic; }
/* El canal PRIVADO se dibuja distinto para que quien escribe en él sepa que el
   empleado no lo va a leer. Una nota que uno cree privada y no lo es sería peor
   que no tener canal. */
.mensaje.privado {
  border-left-color: var(--amber);
  background: var(--color-warning-bg, rgba(242, 181, 68, 0.08));
  border-radius: 0 6px 6px 0; padding-right: 8px;
}

/* La barra de filtros de las bandejas (estado, fechas, empleado). En fila y
   con etiqueta ARRIBA de cada control: puestas al lado, los tres controles
   quedaban a distinta altura y la fila se leía torcida. */
.filtros-solicitudes {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
  padding: 10px 12px; margin-bottom: 12px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--color-surface-soft);
}
.filtros-solicitudes label {
  display: flex; flex-direction: column; gap: 3px;
  font-size: 11px; font-weight: 600; color: var(--muted);
}
.filtros-solicitudes select, .filtros-solicitudes input { font-size: 13px; }

/* ── TOOLTIP ───────────────────────────────────────────────────────────────
   La tarjeta que explica sin sacarte de donde estás. Va en un portal al body,
   así que su `position: fixed` no depende de ningún ancestro. */
.tt-disparador { display: contents; }
/* `display: contents` para que envolver una celda NO cambie el layout de la
   tabla: con un `span` normal, la fila dejaba de alinearse con las demás. */

.tt-caja {
  position: fixed; z-index: 2000;
  background: var(--color-surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; font-size: 12.5px; line-height: 1.45;
  box-shadow: 0 10px 30px var(--color-shadow-soft), 0 2px 8px rgba(0,0,0,.08);
  pointer-events: none;   /* no se puede «entrar» al tooltip: no es un menú */
  animation: tt-entra .12s ease-out;
}
@keyframes tt-entra { from { opacity: 0; transform-origin: top left; } }

.tt-titulo { font-weight: 700; margin-bottom: 4px; }
.tt-desc {
  color: var(--ink-2); margin-bottom: 8px;
  /* Acotada a cuatro renglones: un tooltip que hay que leer entero deja de ser
     un vistazo, y el texto completo vive en el detalle. */
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden;
}
.tt-desc.completa { display: block; -webkit-line-clamp: unset; overflow: visible;
  white-space: pre-wrap; }
.tt-datos { margin: 0; display: grid; gap: 3px; }
.tt-datos > div { display: flex; gap: 8px; }
.tt-datos dt {
  color: var(--muted); font-size: 11px; text-transform: uppercase;
  letter-spacing: .03em; min-width: 84px; flex: none;
}
.tt-datos dd { margin: 0; min-width: 0; }
.tt-vacio { color: var(--muted); font-size: 11.5px; }

/* ── COLUMNAS DE MIS ACTIVIDADES ───────────────────────────────────────────
   Las tres secciones a lo ancho y TODAS DEL MISMO ALTO (dueño, 2026-09-01).
   El alto igual sale solo de `grid`: los hijos de una fila se estiran al más
   alto, y por eso las tarjetas llevan `height: 100%` — sin él, cada una mide lo
   que ocupa su contenido y la fila se ve escalonada. */
.columnas-actividades {
  display: grid; gap: 14px; margin-bottom: 14px;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
.columnas-actividades > .card {
  height: 100%; margin-bottom: 0; display: flex; flex-direction: column;
}
/* El cuerpo se queda con el espacio sobrante y hace scroll si no cabe: sin
   esto, la columna con veinte actividades estiraba a las tres. */
.columnas-actividades .cubo-cuerpo { flex: 1; overflow: auto; max-height: 46vh; }

/* La leyenda del asterisco al pie de un formulario. Alineada a la derecha para
   que se lea como nota al pie y no compita con el texto de ayuda, que va a la
   izquierda. */
.campo-obligatorio-nota {
  font-size: 11px; margin-top: 10px; text-align: right;
}

/* La copia AUTOMÁTICA de la leyenda (FormModal y WizardEditor la renderizan
   siempre): encendida solo cuando el cuerpo contiene algún `req-marca`. Un
   formulario sin obligatorios no la muestra, y uno nuevo no puede olvidarla. */
.nota-obligatorio-auto { display: none; }
.modal:has(.req-marca) .nota-obligatorio-auto,
.wizard-main:has(.req-marca) .nota-obligatorio-auto { display: block; }

/* EL SELECTOR FILTRABLE tiene el mismo problema y no usa `::placeholder`: su
   texto de vacío —«— Selecciona —»— es un `<span>` normal. Iba en el gris de
   texto secundario, así que un campo sin elegir se leía como uno con valor.
   Las rayas ayudaban, pero el color es lo que se ve primero. */
.selbus-caja > .muted { color: var(--placeholder); }
/* El foco se marca con un anillo INTERIOR: un `outline` normal se sale de la
   celda y se encima con la vecina. */
.rj-celda:focus { box-shadow: inset 0 0 0 2px var(--color-primary); background: var(--color-primary-light); }
.rj-der .rj-celda { text-align: right; font-variant-numeric: tabular-nums; }
.rejilla-tabla tr.rj-mala td { background: var(--color-danger-soft); }
.rejilla-tabla tr.rj-error td {
  background: var(--color-danger-soft); color: var(--red-ink); font-size: 12px;
  padding: 6px 10px 8px 48px; border-bottom: 1px solid var(--line-2);
}
.rj-borrar {
  background: transparent; border: 0; cursor: pointer; color: var(--muted-2);
  padding: 4px; display: inline-flex; border-radius: 6px;
}
.rj-borrar:hover { color: var(--red); background: var(--color-danger-soft); }
.rj-borrar svg { width: 15px; height: 15px; }
.rejilla-pie {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 9px 12px; border-top: 1px solid var(--line);
  background: var(--color-surface-soft); flex-wrap: wrap;
}
.rj-ayuda { font-size: 11.5px; color: var(--muted); }
.rj-ayuda b { color: var(--ink-2); font-weight: 600; }
.rj-acciones { display: flex; gap: 8px; }
.rejilla-conteo {
  display: flex; gap: 18px; align-items: center; padding: 9px 12px;
  border-top: 1px solid var(--line); font-size: 12.5px; color: var(--muted);
}
.rejilla-conteo b { color: var(--ink); font-variant-numeric: tabular-nums; }
.rj-conteo-mal { display: inline-flex; align-items: center; gap: 6px; color: var(--red-ink); }
.rj-conteo-mal b { color: var(--red-ink); }
.rj-conteo-mal svg { width: 14px; height: 14px; }
.banner b { display: block; margin-bottom: 2px; }

/* ---------- misc ---------- */
.muted { color: var(--muted); font-size: 13px; }
.lock { color: var(--color-warning-text); }
.grid-2 { display: grid; grid-template-columns: 1fr 320px; gap: 18px; align-items: start; }
@media (max-width: 1000px) { .grid-2 { grid-template-columns: 1fr; } .shell { grid-template-columns: 64px minmax(0, 1fr); } .logo, .nav a span:not(.nav-ico), .sidebar .foot { display: none; } }
.spin { color: var(--muted); font-size: 14px; padding: 30px 0; }
.dl { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 14px; }
.dl dt { font-size: 11px; text-transform: uppercase; letter-spacing: 0.4px; color: var(--muted); }
.dl dd { margin: 3px 0 0; font-weight: 700; font-size: 14px; }
.modal-back { position: fixed; inset: 0; background: var(--color-overlay); display: grid; place-items: center; z-index: 50; padding: 20px; }
.modal { background: var(--panel); border-radius: 14px; max-width: 760px; width: 100%; max-height: 85vh; overflow: auto; box-shadow: 0 20px 60px var(--color-overlay-strong); }
.modal .modal-head { display: flex; justify-content: space-between; align-items: center; padding: 18px 20px; border-bottom: 1px solid var(--line); }
.modal .x { cursor: pointer; border: 0; background: none; font-size: 20px; color: var(--muted); }

/* ---------- formularios ---------- */
.form-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
/* ANGOSTO (teléfono, o ventana muy chica). Una sola columna: dos columnas
   en 375px son campos de ~150px reales. Los `!important` son a propósito:
   varios formularios traen `gridTemplateColumns`/`gridColumn` EN LÍNEA
   (estilos de escritorio) y sin ellos esta regla perdería justo donde
   importa. */
@media (max-width: 640px) {
  .form-grid { grid-template-columns: 1fr !important; }
  .form-grid > * { grid-column: auto !important; }

  /* La topbar cede en vez de desbordar: era lo que expandía el layout a
     589px y encogía TODA la app al 64% en el teléfono (revisión móvil,
     2026-09-03). El aviso de montos y el nombre/puesto se ocultan — el
     candado y el avatar se quedan, que son los que se tocan. */
  .topbar { padding: 10px 12px; gap: 8px; }
  .topbar .privado-aviso { display: none; }
  .topbar .user-btn-info { display: none; }

  /* Los GRUPOS DE BOTONES del encabezado (los `<div>` con flex en línea
     dentro de `.row-between`) no ceden: `.row-between` sí envuelve, pero el
     grupo entero es UN item de ~400px de mínimo, así que empuja el layout y
     «+ Nueva tarea» quedaba tras un scroll horizontal (dueño, 2026-09-03,
     tablero en celular). En angosto, el grupo también envuelve. */
  .row-between > div { flex-wrap: wrap; }

  /* 64px de padding lateral en una pantalla de 375 dejaban 247 útiles. */
  .content { padding: 14px 12px 48px; }
}
.form-grid label { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--muted); font-weight: 600; }
.form-grid input, .form-grid select {
  padding: 9px 11px; border: 1px solid var(--line); border-radius: 9px;
  font-size: 13px; color: var(--ink); background: var(--panel); outline: none;
  /* En una rejilla, un select NO se encoge por debajo de su opción más larga
     (min-width:auto): una opción larga desbordaba el modal con scroll
     horizontal — lo cazó el dueño en Tesorería con el campo Estado, que solo
     aparece al editar. Con min-width:0 el control se encoge y la lista
     desplegada sigue mostrando el texto completo. */
  min-width: 0; width: 100%;
}
.form-grid input:focus, .form-grid select:focus { border-color: var(--blue); }
table.form-tbl input {
  width: 100%; padding: 6px 8px; border: 1px solid var(--line); border-radius: 7px;
  font-size: 13px; outline: none; background: var(--panel);
}
table.form-tbl input:focus { border-color: var(--blue); }
table.form-tbl .x { font-size: 14px; color: var(--red); }

/* ---------- HUB de conocimiento (contenido markdown) ---------- */
.hub-content { font-size: 14px; color: var(--ink-2); line-height: 1.6; }
.hub-content h2 { font-size: 18px; color: var(--ink); margin: 18px 0 8px; letter-spacing: -0.1px; }
.hub-content h3 { font-size: 15px; color: var(--ink); margin: 14px 0 6px; text-transform: uppercase; letter-spacing: 0.4px; font-weight: 700; }
.hub-content h4 { font-size: 13px; color: var(--ink-2); margin: 10px 0 4px; font-weight: 700; }
.hub-content p { margin: 6px 0; }
.hub-content ul, .hub-content ol { margin: 6px 0 6px 22px; padding: 0; }
.hub-content li { margin: 3px 0; }
.hub-content code { background: var(--color-surface-soft); color: var(--blue-ink); padding: 1px 6px; border-radius: 4px; font-size: 12.5px; font-family: var(--ratio-font-mono); }
.hub-content .hub-link { color: var(--blue-ink); cursor: pointer; text-decoration: none; border-bottom: 1px dashed var(--blue-ink); }
.hub-content .hub-link:hover { background: var(--color-info-soft); }

/* ---------- Buscador global (dropdown del topbar) ---------- */
.search-drop {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 12px 40px var(--color-shadow-lg);
  z-index: 60; max-height: 460px; overflow-y: auto;
  padding: 6px 0;
}
.search-note { padding: 8px 14px; font-size: 12px; color: var(--muted); border-bottom: 1px solid var(--line); }
.search-note b { color: var(--ink-2); }
.search-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 8px 14px; background: none; border: 0;
  cursor: pointer; text-align: left; font: inherit;
  border-bottom: 1px solid var(--color-surface-soft);
}
.search-item:last-child { border-bottom: 0; }
.search-item:hover, .search-item.sel { background: var(--color-info-soft); }
.search-ico {
  width: 26px; height: 26px; flex-shrink: 0; display: grid; place-items: center;
  background: var(--color-surface-soft); border-radius: 8px; color: var(--muted); font-size: 14px;
}
.search-item.sel .search-ico, .search-item:hover .search-ico {
  background: var(--blue); color: var(--color-primary-text);
}
.search-body { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.search-title { color: var(--ink); font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-sub { color: var(--muted); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-kind {
  flex-shrink: 0; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.4px;
  color: var(--muted); padding: 2px 8px; background: var(--color-surface-soft); border-radius: 999px;
}

/* ---------- Campo de filtro genérico (label + input/select apilados) ---------- */
.fld { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--muted); font-weight: 600; min-width: 0; }
.fld input, .fld select {
  padding: 8px 11px; border: 1px solid var(--line); border-radius: 8px;
  font-size: 13px; color: var(--ink); background: var(--panel); outline: none; font-weight: 400;
}
.fld input:focus, .fld select:focus { border-color: var(--blue); }
.fld select:disabled { background: var(--color-row-stripe); color: var(--muted-2); }

/* ---------- Kanban de Tareas ---------- */
.kanban {
  display: flex; gap: 14px; overflow-x: auto; padding-bottom: 12px; align-items: stretch;
  height: calc(100vh - var(--kanban-viewport-offset, 300px));
  max-height: calc(100vh - var(--kanban-viewport-offset, 300px));
  min-height: 0;
}
.kanban-col {
  min-width: 260px; flex: 1; background: var(--color-row-stripe); border-radius: 12px; border: 1px solid var(--line);
  display: flex; flex-direction: column;
}
.kanban-col-head {
  padding: 10px 14px; font-weight: 700; font-size: 13px; color: var(--ink);
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  border-radius: 12px 12px 0 0; background: var(--panel);
}
.kanban-col-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kanban-collapse-btn {
  border: 1px solid var(--line); background: var(--color-surface-soft); color: var(--muted);
  width: 24px; height: 24px; border-radius: 999px; cursor: pointer;
  display: inline-grid; place-items: center; font: inherit; line-height: 1; flex: none;
}
.kanban-collapse-btn:hover { border-color: var(--blue); color: var(--blue); background: var(--color-info-soft); }
.kanban-col.kanban-col-collapsed {
  flex: 0 0 68px; min-width: 68px; overflow: hidden;
}
.kanban-col.kanban-col-collapsed .kanban-col-head {
  min-height: 100%; flex-direction: column; justify-content: flex-start; padding: 10px 8px;
}
.kanban-col.kanban-col-collapsed .kanban-col-title {
  writing-mode: vertical-rl; text-orientation: mixed; white-space: nowrap; max-height: 240px;
}
.kanban-col.kanban-col-collapsed .kanban-count { min-width: 24px; padding: 2px 6px; }
.kanban-count {
  min-width: 22px; text-align: center; background: var(--color-surface-soft); color: var(--muted);
  padding: 1px 8px; border-radius: 999px; font-size: 12px; font-weight: 600;
}
.kanban-body { display: flex; flex-direction: column; gap: 8px; padding: 10px; min-height: 120px; flex: 1; overflow-y: auto; }
.kanban-empty { color: var(--muted-2); font-size: 12px; padding: 8px 4px; text-align: center; }
.kanban-card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; box-shadow: 0 1px 2px var(--color-shadow-soft);
  transition: box-shadow 0.15s;
}
.kanban-card:hover { box-shadow: 0 4px 12px var(--color-shadow); }
.kanban-card.bloqueada { border-color: var(--red); background: var(--color-danger-soft); }
.kanban-card-title { font-weight: 600; color: var(--ink); font-size: 13px; margin-bottom: 6px; }
.kanban-card-tags { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 8px; }
.kanban-card-foot { display: flex; justify-content: space-between; align-items: center; }
.nested-kanban .kanban-col {
  flex: 0 0 var(--kanban-nested-width, 260px);
}
.nested-kanban .kanban-col.kanban-col-collapsed {
  flex: 0 0 68px;
}
.nested-kanban .kanban-body {
  display: grid; gap: 10px; align-items: stretch;
}
.nested-kanban .kanban-empty { grid-column: 1 / -1; }
.kanban-subboard {
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  overflow: hidden; box-shadow: 0 1px 2px var(--color-shadow-soft);
  display: flex; flex-direction: column; min-height: 100%;
}
.kanban-subhead {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 8px 10px; background: var(--color-surface-muted); color: var(--ink);
  font-size: 12px; font-weight: 800;
}
.kanban-subhead > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kanban-subhead .kanban-collapse-btn { width: 22px; height: 22px; font-size: 11px; }
.kanban-subbody { display: flex; flex-direction: column; gap: 8px; padding: 8px; flex: 1; }
.kanban-subboard.kanban-subboard-collapsed { min-height: 100%; }
.kanban-subboard.kanban-subboard-collapsed .kanban-subhead {
  min-height: 100%; flex-direction: column; justify-content: flex-start; padding: 10px 8px;
}
.kanban-subboard.kanban-subboard-collapsed .kanban-subhead > span:first-child {
  writing-mode: vertical-rl; text-orientation: mixed; white-space: nowrap; max-height: 220px;
}
.kanban-subboard.kanban-subboard-collapsed .kanban-count { min-width: 24px; padding: 2px 6px; }
.kanban-subbody .kanban-card { box-shadow: none; }
.rh-person-card { width: 100%; text-align: left; cursor: pointer; font-family: inherit; }
.rh-person-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
/* El organigrama crece con el contenido (multinivel): sin altura fija ni
   scroll interno — la página hace el scroll y nada se recorta. */
.rh-person-kanban { height: auto; max-height: none; align-items: flex-start; }
.rh-person-kanban .kanban-body { overflow-y: visible; }
.rh-person-kanban .kanban-subboard { min-height: 0; overflow: visible; }
.rh-person-kanban .kanban-body { align-items: start; }
.rh-person-kanban .kanban-subboard { flex: none; }
.rh-person-kanban .kanban-subbody { background: var(--color-surface-hover); }
.kanban-avatars { display: flex; gap: 4px; }
.avatar-sm {
  width: 26px; height: 26px; border-radius: 50%; background: var(--blue);
  color: var(--color-primary-text); display: inline-grid; place-items: center;
  font-size: 11px; font-weight: 700; border: 2px solid var(--panel); box-shadow: 0 0 0 1px var(--line);
}
.avatar-sm.more { background: var(--muted-2); }
.kanban-mover { display: flex; gap: 6px; margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--line); }
.kanban-add {
  padding: 8px; border: 1px dashed var(--line); background: transparent;
  color: var(--muted); border-radius: 8px; cursor: pointer; font-size: 12px;
}
.kanban-add:hover { border-color: var(--blue); color: var(--blue); background: var(--color-info-soft); }

/* ---------- Login ---------- */
.login-back {
  min-height: 100vh; display: grid; place-items: center;
  background: linear-gradient(135deg, var(--color-header-bg-alt) 0%, var(--color-sidebar-hover) 100%);
  padding: 20px;
}
.login-card {
  background: var(--panel); border-radius: 14px; padding: 32px; width: 100%; max-width: 380px;
  box-shadow: 0 20px 60px var(--color-overlay-strong);
  display: flex; flex-direction: column; gap: 14px;
}
.login-logo { display: flex; flex-direction: column; align-items: center; gap: 8px; color: var(--ink); text-align: center; letter-spacing: 0.5px; }
.login-logo img { width: 152px; max-width: 100%; height: auto; border-radius: var(--ratio-radius); }
.login-logo span { color: var(--gold); font-size: 13px; font-weight: 800; letter-spacing: 0.12em; }
.login-sub { color: var(--muted); text-align: center; font-size: 14px; margin-bottom: 4px; }

/* ---------- Menú de usuario en topbar ---------- */
.user-btn {
  display: flex; align-items: center; gap: 10px; padding: 4px 8px 4px 4px;
  background: none; border: 1px solid transparent; border-radius: 999px; cursor: pointer;
}
.user-btn:hover { background: var(--color-surface-subtle); border-color: var(--line); }
.user-btn-info { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; }
.user-btn-name { font-size: 13px; font-weight: 600; color: var(--ink); }
.user-btn-role { font-size: 11px; color: var(--muted); }
.user-menu {
  position: absolute; top: calc(100% + 6px); right: 0; min-width: 240px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 12px 40px var(--color-shadow-menu); z-index: 60;
}
.user-menu-item {
  display: block; width: 100%; padding: 10px 14px; background: none; border: 0;
  text-align: left; font: inherit; cursor: pointer; color: var(--ink-2); font-size: 13px;
}
.user-menu-item:hover { background: var(--color-surface-subtle); color: var(--ink); }

/* ---------- Toggle del sidebar (ocultar / mostrar) ---------- */
.shell.sidebar-hidden { grid-template-columns: 64px minmax(0, 1fr); }
.shell.sidebar-hidden .sidebar { display: flex; padding: 10px 8px 22px; align-items: center; }
.shell.sidebar-hidden .nav a span:not(.nav-ico),
.shell.sidebar-hidden .sidebar .foot { display: none; }
.shell.sidebar-hidden .logo { display: flex; padding: 0 0 10px; }
.shell.sidebar-hidden .logo img { width: 48px; height: 42px; border-radius: var(--ratio-radius-xs); }
.shell.sidebar-hidden .nav { width: 100%; align-items: center; }
.shell.sidebar-hidden .nav a { justify-content: center; padding: 10px 0; }
.shell.sidebar-hidden .nav-ico { width: 100%; }
.sidebar-toggle {
  align-self: flex-end; border: 1px solid var(--color-sidebar-border);
  background: var(--color-sidebar-hover); padding: 6px 10px;
  border-radius: 8px; cursor: pointer; color: var(--color-sidebar-text); font-size: 16px;
  margin: 0 0 6px; transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.sidebar-toggle:hover { background: var(--color-sidebar-active-bg); color: var(--color-header-text); border-color: var(--color-primary); }
.shell.sidebar-hidden .sidebar-toggle {
  align-self: center; width: 40px; height: 36px; padding: 0; display: grid; place-items: center;
}

/* ---------- Wizard editor (pantalla completa para documentos: OC, cotización, factura…) ---------- */
.wizard {
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); overflow: hidden;
  /* Altura FIJA al viewport: el contenido hace scroll interno y el footer
     (Cancelar/Continuar) queda siempre visible sin scroll de página. */
  display: flex; flex-direction: column; height: calc(100vh - 120px);
}
.wizard-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 20px 26px 16px; border-bottom: 1px solid var(--line);
}
.wizard-title { margin: 0; font-size: 22px; font-weight: 800; letter-spacing: -0.3px; }
.wizard-subtitle { color: var(--muted); font-size: 13px; margin-top: 4px; }
.wizard-crumbs { font-size: 14px; color: var(--muted); }
.wizard-crumb-link { color: var(--muted); cursor: pointer; }
.wizard-crumb-link:hover { color: var(--blue-ink); text-decoration: underline; }
.wizard-crumb-sep { margin: 0 4px; }
.wizard-crumb-current { color: var(--ink); font-weight: 700; }
.wizard-badges { display: flex; align-items: center; gap: 10px; flex: none; }
/* El bloque izquierdo del head: solo agrupa migas y subtitulo. El min-width
   deja que un titulo largo se comprima en vez de empujar los badges fuera. */
.wizard-title-block { min-width: 0; }
.wizard-folio {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px;
  background: var(--color-surface-soft); border: 1px solid var(--line); border-radius: 8px;
  padding: 6px 10px; color: var(--ink-2);
}
.wizard-steps {
  display: flex; align-items: center; gap: 4px;
  padding: 14px 26px; border-bottom: 1px solid var(--line); background: var(--color-surface-muted);
  overflow-x: auto;
}
.wizard-step {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 14px 6px 6px; border-radius: 999px;
  color: var(--muted-2); font-size: 13px; white-space: nowrap;
}
.wizard-step + .wizard-step { margin-left: 8px; }
.wizard-step-num {
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; font-weight: 700; font-size: 12px;
  background: var(--line); color: var(--muted-2); flex: none;
}
.wizard-step.active .wizard-step-num { background: var(--blue-ink); color: var(--color-primary-text); }
.wizard-step.active .wizard-step-label { color: var(--ink); font-weight: 700; }
.wizard-step.done .wizard-step-num { background: var(--green); color: var(--color-primary-text); }
.wizard-step.done .wizard-step-label { color: var(--ink-2); font-weight: 600; }
.wizard-step.clickable { cursor: pointer; }
.wizard-step.clickable:hover .wizard-step-label { color: var(--blue-ink); }
.wizard-body {
  flex: 1; padding: 24px 26px; background: var(--bg);
  overflow-y: auto; min-height: 0;   /* el scroll vive aquí, no en la página */
}
.wizard-body.with-side {
  display: grid; grid-template-columns: 1fr 320px; gap: 20px; align-items: start;
}
.wizard-main { min-width: 0; display: flex; flex-direction: column; gap: 16px; }
.wizard-side { position: sticky; top: 0; }
@media (max-width: 1100px) {
  .wizard-body.with-side { grid-template-columns: 1fr; }
  .wizard-side { position: static; }
}
.wizard-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 26px; border-top: 1px solid var(--line); background: var(--panel);
}
.wizard-foot-right { display: flex; align-items: center; gap: 10px; }

/* Tarjeta de sección dentro del wizard */
.wiz-section {
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 18px 20px;
}
.wiz-section h3 {
  margin: 0 0 14px; font-size: 15px; font-weight: 700; color: var(--ink);
}
.wiz-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px;
}
.wiz-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); }
.wiz-grid label > span { font-weight: 600; }
.wiz-grid input, .wiz-grid select, .wiz-grid textarea {
  padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  font-size: 13px; color: var(--ink); background: var(--panel);
}
.wiz-grid input:focus, .wiz-grid select:focus, .wiz-grid textarea:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px var(--color-primary-ring);
}

/* Panel lateral tipo "snapshot" (presupuesto, KPIs contextuales) */
.side-panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 16px; display: flex; flex-direction: column; gap: 14px;
}
.side-panel-title {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px;
  color: var(--muted); font-weight: 700;
}
.side-panel-row {
  display: flex; justify-content: space-between; font-size: 13px; color: var(--ink-2);
}
.side-panel-row .val { font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.side-panel-note {
  font-size: 12px; padding: 10px 12px; border-radius: 8px;
  background: var(--color-warning-light); color: var(--color-warning-text);
}
.side-panel-note.ok { background: var(--color-success-light); color: var(--green-ink); }
.side-panel-note.err { background: var(--color-danger-light); color: var(--red-ink); }
.budget-bar {
  height: 10px; border-radius: 999px; background: var(--color-border-subtle); overflow: hidden;
}
.budget-bar > span {
  display: block; height: 100%; background: var(--green); border-radius: 999px;
  transition: width 0.3s;
}
.budget-bar.warn > span { background: var(--amber); }
.budget-bar.over > span { background: var(--red); }

/* ===== UI-Editor (piloto) ===== */
.ue-campo { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--muted); font-weight: 600; }
.ue-campo input, .ue-campo select, .ue-campo textarea {
  padding: 7px 10px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--panel); color: var(--ink); font-size: 13px; font-family: inherit;
}
.ue-campo input:focus, .ue-campo select:focus, .ue-campo textarea:focus { border-color: var(--blue); outline: none; }
.ue-seccion { border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 8px; margin: 0; }
.ue-seccion legend { font-size: 12px; font-weight: 700; color: var(--ink-2); padding: 0 6px; }
.ue-nodo {
  display: flex; justify-content: space-between; align-items: center; gap: 6px;
  padding: 6px 8px; border-radius: 8px; cursor: pointer; font-size: 13px;
}
.ue-nodo:hover { background: var(--color-surface-subtle, rgba(0,0,0,.04)); }
.ue-nodo.sel { background: var(--blue-ink); color: var(--color-primary-text, #fff); }
.ue-nodo-acciones { display: none; gap: 2px; }
.ue-nodo:hover .ue-nodo-acciones { display: inline-flex; }
.ue-nodo-acciones button {
  border: none; background: none; cursor: pointer; font-size: 11px; color: inherit;
  opacity: .7; padding: 2px 4px; border-radius: 4px;
}
.ue-nodo-acciones button:hover { opacity: 1; background: rgba(0,0,0,.15); }
.ue-agregar {
  width: 100%; margin-top: 4px; padding: 6px 8px; border-radius: 8px;
  border: 1px dashed var(--line); background: none; color: var(--muted); font-size: 12px; cursor: pointer;
}
.ue-agregar.sm { font-size: 11px; padding: 4px 6px; }

/* Designer (/designer): mismo shell, acento distintivo en el sidebar */
.sidebar.designer-side { border-right: 3px solid var(--blue-ink); }
.sidebar.designer-side .logo span { color: var(--blue-ink); font-weight: 800; }

/* Modo Ejecutar del Designer (design → run) */
.tab.ue-run { color: var(--green); font-weight: 700; }
.tab.ue-run.active { background: var(--green); color: #fff; border-color: var(--green); }

/* Secciones plegables y editor de filtros del panel de propiedades */
details.ue-seccion > summary {
  cursor: pointer; font-size: 12px; font-weight: 700; color: var(--ink-2); user-select: none;
}
.ue-filtro input, .ue-filtro select {
  padding: 6px 8px; border-radius: 8px; border: 1px solid var(--line);
  background: var(--panel); color: var(--ink); font-size: 12px; font-family: inherit; min-width: 0;
}
.ue-filtro input:focus, .ue-filtro select:focus { border-color: var(--blue); outline: none; }
.ue-quitar { border: none; background: none; color: var(--muted); cursor: pointer; font-size: 12px; padding: 2px; }
.ue-quitar:hover { color: var(--red, #c0392b); }

/* Inputs compactos del editor de campos del wizard */
.ue-mini {
  padding: 5px 7px; border-radius: 7px; border: 1px solid var(--line);
  background: var(--panel); color: var(--ink); font-size: 12px; font-family: inherit; min-width: 0;
}
.ue-mini:focus { border-color: var(--blue); outline: none; }

/* ---------- selector buscable (NORMA de interfaz) ----------
   Todo selector alimentado por DATOS se teclea para filtrar. La regla, sus
   límites y el porqué están en components/SelectorBuscable.jsx; la hace cumplir
   backend/tests/test_selectores.py. */
.selbus { position: relative; }
.selbus-caja {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel); color: var(--ink); font: inherit; text-align: left;
  cursor: pointer;
}
.selbus-caja:disabled { opacity: 0.55; cursor: not-allowed; }
.selbus-caja:focus-visible { outline: 2px solid var(--blue-ink); outline-offset: 1px; }
.selbus-flecha { color: var(--muted); font-size: 11px; }
.selbus-pop {
  /* FIJO y en un portal sobre <body>: dentro del contenedor, cualquier
     `overflow` lo recortaba (pasó en la rejilla de alta masiva). Las
     coordenadas van inline, medidas desde la caja. El z-index queda sobre los
     modales (50) y los menús (60) porque un selector puede abrir DENTRO de
     cualquiera de los dos. */
  position: fixed; z-index: 70;
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18); overflow: hidden;
}
.selbus-filtro {
  width: 100%; border: 0; border-bottom: 1px solid var(--line); border-radius: 0;
  padding: 9px 10px; font: inherit; background: var(--panel); color: var(--ink);
}
.selbus-filtro:focus { outline: none; }
/* El alto acotado es la mitad del pedido: «reducir el alto de la lista para
   poder seleccionar el que se desea». Sin tope, filtrar de 900 a 200 sigue
   siendo una lista que tapa la pantalla. */
.selbus-lista { list-style: none; margin: 0; padding: 4px; max-height: 260px; overflow-y: auto; }
.selbus-op { padding: 7px 9px; border-radius: 6px; cursor: pointer; font-size: 13px; }
.selbus-op.hl { background: var(--color-surface-subtle); }
.selbus-op.sel { color: var(--blue-ink); font-weight: 600; }
.selbus-op.off { opacity: 0.45; cursor: not-allowed; }
.selbus-det { font-size: 11px; color: var(--muted); }
.selbus-pie { padding: 6px 10px; font-size: 11px; color: var(--muted); border-top: 1px solid var(--line); }

/* ---------- buscador de tabla ----------
   El dueño lo pidió como carencia general: «faltan filtros y buscadores en
   muchas tablas que se espera pueda llegar a miles». */
.buscador { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.buscador input {
  flex: 1; max-width: 460px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel); color: var(--ink); font: inherit;
}
/* La fila elegida se marca: con el detalle ABAJO y no al lado, sin esto se
   pierde de vista cuál de las filas se está mirando. */

/* ---------- barra de carga de taller ----------
   Escala relativa al máximo de la lista, no a un número fijo: «muchas piezas»
   significa cosas distintas en un taller de tornillos y en uno de moldes. */
.barra-carga { height: 8px; border-radius: 999px; background: var(--color-surface-subtle); overflow: hidden; }
.barra-carga > div { height: 100%; background: var(--blue-ink); border-radius: 999px; }

/* Renglones de CONCILIACION en el estado de cuenta. No son movimientos del
   banco: son la apertura declarada en el corte. Se distinguen a la vista porque
   confundirlos con una operacion real es justo el error que se quiere evitar. */
.tbl tr.fila-corte { background: var(--panel-2, rgba(127, 127, 127, .06)); }
.tbl tr.fila-corte td { font-style: italic; }


/* ==========================================================================
   MODO OSCURO
   Solo se reemplazan los tokens BASE. Los alias (--panel, --line, --ink, --blue…)
   no se repiten aqui: apuntan a estos, asi que se mueven solos. Por eso el
   archivo no crece al doble y no hay dos verdades que puedan desalinearse.

   El Manual de Estilo V1 es de modo claro y no legisla el oscuro. Lo que SI se
   conserva del manual es lo que da la identidad: el verde RATIO sigue siendo la
   accion, la jerarquia sigue por peso y caja, y el verde sigue sin entrar en
   parrafos largos. Lo que cambia es la neutralidad: en oscuro la superficie no
   puede ser #F3F5F7, y el Primary Dark #1F252B deja de servir de contraste
   contra el fondo porque SE VUELVE el fondo — de ahi que thead y barra suban a
   un gris mas claro en vez de mantener el valor del manual.
   ========================================================================== */
[data-theme="oscuro"] {
  --color-bg: #14181c;
  --color-surface: #1c2227;
  --color-surface-hover: #222a30;
  --color-surface-muted: #191f24;
  --color-surface-soft: #171c21;
  --color-surface-subtle: #232b31;
  /* La barra queda MAS oscura que las tarjetas, no mas clara: si no, deja de
     leerse como el marco de la aplicacion y compite con el contenido. */
  --color-sidebar: #0f1317;
  --color-sidebar-end: #0b0e11;
  --color-sidebar-hover: #1b2228;
  --color-sidebar-active-bg: rgba(127, 178, 57, 0.22);
  --color-sidebar-text: #b9c2c9;
  --color-sidebar-muted: #767f87;
  --color-sidebar-border: rgba(255, 255, 255, 0.07);

  /* No se calcula con opacidad sobre el texto: los campos tienen fondos
     distintos —tarjeta, rejilla, modal— y un gris translúcido cambia de
     aspecto en cada uno. Un color fijo se ve igual en todos.

     MEDIDO, porque «apenas por encima del fondo» resultó ser invisible. El
     valor anterior (#3a4249) daba 1.6:1 contra la superficie #1c2227 — por
     debajo del umbral de lectura, y el dueño lo reportó: en oscuro los
     placeholders no se veían. Este da 2.7:1.

     El número que importa no es ese sino la DISTANCIA con el texto escrito
     (#dde3e8, 12.6:1): sigue habiendo casi cinco veces más contraste en lo
     capturado que en la pista, que es la regla de este color — leerse si uno
     lo busca, nunca pasar por un valor ya insertado. */
  --placeholder: #5a636a;

  /* El verde de marca se mantiene: es la identidad. Solo se aclara un punto el
     de enfasis, porque #5E8F2E sobre fondo oscuro pierde legibilidad. */
  --color-primary: #7fb239;
  --color-primary-hover: #8fc247;
  --color-primary-light: rgba(127, 178, 57, 0.16);
  --color-primary-ring: rgba(127, 178, 57, 0.3);
  --color-primary-text: #10140f;

  /* thead y barras de encabezado: mas claras que la superficie para que la
     tabla siga teniendo cabeza visible. En claro es lo contrario. */
  --color-header-bg: #2a333a;
  --color-header-bg-alt: #323c44;
  --color-header-text: #f2f5f7;
  --color-header-muted: #c3ccd3;

  --color-row-stripe: #1f262c;
  --color-row-hover: #26302f;
  --color-row-selected: #2b3a26;

  --color-text: #dde3e8;
  --color-text-strong: #f2f5f7;
  --color-text-muted: #96a0a9;
  --color-text-light: #6f7981;
  --color-border: #313a42;
  --color-border-light: #2a333a;
  --color-border-subtle: #232b31;

  /* Semanticos: mismo significado, mas luminosidad. Los tonos de claro
     (#dc2626, #d97706) sobre fondo oscuro se leen como manchas apagadas, y el
     rojo es justo el que no puede perderse. Los «light/soft» pasan de pastel a
     velo translucido, que es como se tiñe sobre oscuro. */
  --color-success: #7cc95a;
  --color-success-light: rgba(124, 201, 90, 0.16);
  --color-success-soft: rgba(124, 201, 90, 0.09);
  --color-success-border: rgba(124, 201, 90, 0.35);
  --color-success-text: #9ad97b;
  --color-danger: #f0616a;
  --color-danger-light: rgba(240, 97, 106, 0.16);
  --color-danger-soft: rgba(240, 97, 106, 0.09);
  --color-danger-border: rgba(240, 97, 106, 0.35);
  --color-danger-text: #f88f96;
  --color-warning: #e69b28;
  --color-warning-hover: #f5b342;
  --color-warning-light: rgba(230, 155, 40, 0.17);
  --color-warning-soft: rgba(230, 155, 40, 0.09);
  --color-warning-text: #f0b866;
  --color-info: #5b93f5;
  --color-info-hover: #7aa8f7;
  --color-info-light: rgba(91, 147, 245, 0.17);
  --color-info-soft: rgba(91, 147, 245, 0.09);
  --color-info-text: #8fb4f8;
  --color-teal: #35b7d4;
  --color-purple: #a78bfa;
  --color-purple-light: rgba(167, 139, 250, 0.17);
  --color-purple-border: rgba(167, 139, 250, 0.4);
  --color-purple-dash: #c4b5fd;
  --color-purple-tint: rgba(167, 139, 250, 0.09);
  --color-warning-tint: rgba(230, 155, 40, 0.1);

  /* Sombras mas opacas: sobre oscuro una sombra al 4% no existe, y sin ella
     las tarjetas se pegan al fondo. */
  --color-overlay: rgba(0, 0, 0, 0.62);
  --color-overlay-strong: rgba(0, 0, 0, 0.55);
  --color-shadow-soft: rgba(0, 0, 0, 0.3);
  --color-shadow: rgba(0, 0, 0, 0.42);
  --color-shadow-menu: rgba(0, 0, 0, 0.55);
  --color-shadow-lg: rgba(0, 0, 0, 0.6);
}

/* El glifo de una empresa trae su color calculado en JS (un hash del nombre)
   con tinta oscura sobre pastel claro. En modo oscuro se apaga un poco para que
   no queden seis parches brillantes en la lista. */
[data-theme="oscuro"] .md-fila img,

/* Botón de modo de color, en la barra superior junto a la tarjeta de usuario. */
.tema-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 9px;
  background: var(--panel); border: 1px solid var(--line);
  color: var(--ink-2); cursor: pointer;
}
.tema-btn:hover { border-color: var(--color-primary); color: var(--color-primary-hover); }


/* ==========================================================================
   MODO DISCRETO — el dato se REEMPLAZA por ****, no se difumina
   Ver `src/privacidad.js`. Arranca ENCENDIDO en cada carga y no se recuerda.

   Empezo siendo `blur` y el dueño lo corrigio: «mejor que solo transformes todo
   lo que es dinero a ****». Tiene razon y el motivo es medible — un numero
   borroso SIGUE DICIENDO cuanto mide. Se ve si son tres cifras o siete, si hay
   signo de menos, si termina en ceros; con el ancho de la columna y un poco de
   contexto se adivina la magnitud, que es justo lo que se queria esconder. Y a
   suficiente aumento un blur se revierte. Una mascara de ancho fijo no filtra
   nada: todos los montos se ven iguales.

   COMO se hace: el texto real se vuelve transparente —no se borra, asi que la
   columna conserva su ancho y la tabla no salta al destapar— y la mascara va en
   un `::after` encima. El texto sigue en el DOM (nadie prometio criptografia;
   esto es un velo para una mirada ajena, no una defensa contra quien abre las
   herramientas del navegador), pero no se puede seleccionar ni copiar.

   QUE se tapa: SOLO DINERO. Lo dijo el dueño al ver la primera version: «solo
   aplicalo a dinero, no es necesario para telefonos u otros; pero todo lo que
   sea dinero, nominas, presupuestos etc.». La marca es la clase `.dinero`, y
   esta puesta en los ~156 lugares donde se renderiza un monto —se localizaron
   siguiendo las funciones `money()`/`money2()`, que son por donde pasa TODO el
   dinero de la aplicacion—. `.sensible` queda para un bloque de dinero que no
   es una celda, como una tarjeta de nomina completa.

   QUE NO: la primera version tapaba `.num` entero y eso barria cantidades,
   dias y conteos —«3 items», «18 pz», «9 dias de vacaciones»— que no son
   dinero y cuya ocultacion solo estorbaba. Tampoco nombres, folios, RFC,
   telefonos, fechas ni estados. Y los `input` jamas: tapar lo que estas
   escribiendo no es discrecion, es un error esperando.
   ========================================================================== */
[data-privado="1"] .dinero,
[data-privado="1"] .sensible {
  position: relative;
  /* Transparente y NO `display:none`: el hueco conserva su tamaño, asi que
     destapar no reacomoda la tabla. */
  color: transparent !important;
  user-select: none;
}
[data-privado="1"] .dinero::after,
[data-privado="1"] .sensible::after {
  content: "****";
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 2px;
  pointer-events: none;
}
/* Los montos van alineados a la derecha en las tablas, asi que su mascara
   tambien: a la izquierda se leeria la columna desalineada. */
[data-privado="1"] .num.dinero::after,
[data-privado="1"] .dinero.derecha::after { right: 0; }
[data-privado="1"] .dinero:not(.num):not(.derecha)::after,
[data-privado="1"] .sensible::after { left: 0; }

/* Los campos de captura nunca. */
[data-privado="1"] input,
[data-privado="1"] textarea,
[data-privado="1"] select { color: var(--ink) !important; user-select: auto; }
[data-privado="1"] input::after,
[data-privado="1"] textarea::after { content: none; }
/* Una celda que solo contiene un `input` no se enmascara: se estaria tapando el
   campo con el que se trabaja. */
[data-privado="1"] .num:has(input)::after { content: none; }
[data-privado="1"] .num:has(input) { color: var(--ink) !important; }

/* Aviso de que los datos ESTAN A LA VISTA. Va al reves de la primera version,
   que resaltaba el modo discreto: si lo normal es estar tapado, resaltarlo lo
   trata como excepcion y el aviso vive encendido siempre — a los dos dias deja
   de leerse. Lo que merece color es la condicion temporal: los montos expuestos. */
.privado-aviso {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; letter-spacing: .03em;
  color: var(--color-warning-text); background: var(--color-warning-light);
  border-radius: 999px; padding: 3px 9px; white-space: nowrap;
}
.tema-btn.alerta,
.chip-filter.alerta {
  background: var(--color-warning-light); border-color: var(--color-warning);
  color: var(--color-warning-text);
}


/* ---------- filas de dato: etiqueta a la izquierda, valor a la derecha -------
   Preferencia del dueño (2026-07-30): «me gusta mucho el estilo de separar con
   bordes finos los campos o secciones, hace ver elegante y distribuido el front
   end; utilizar eso preferentemente cuando sea posible y aplique».

   Es la misma idea que ya separa las columnas de la tira de datos duros, ahora
   entre renglones. Una linea de 1px del color mas tenue del tema: separa sin
   dibujar una reja, que es lo que pasaria con el borde normal. El ULTIMO renglon
   no lleva linea — una raya suelta antes del borde de la tarjeta se lee como un
   renglon vacio que no cargo. */
.filas-dato > .fila-dato {
  display: flex; justify-content: space-between; gap: 12px;
  font-size: 13px; padding: 7px 0;
  border-bottom: 1px solid var(--color-border-subtle);
}
.filas-dato > .fila-dato:last-child { border-bottom: 0; padding-bottom: 0; }
.filas-dato > .fila-dato:first-child { padding-top: 0; }
.fila-dato > .etiqueta { color: var(--muted); white-space: nowrap; }
.fila-dato > .valor { text-align: right; word-break: break-word; }

/* ---------- maestro-detalle de empresas ------------------------------------
   La maqueta que pidió el dueño para Clientes y Proveedores: la lista COMPLETA
   a la izquierda, angosta, y todo el resto del ancho para el detalle. Antes el
   detalle iba abajo de una tabla a todo lo ancho, y había que bajar la vista
   para leerlo.

   La lista es angosta A PROPÓSITO: solo tiene que dejar reconocer y elegir
   —glifo, nombre, país, saldo—. Todo lo demás cabe mejor en el panel grande. */
.maestro-detalle {
  display: grid;
  grid-template-columns: minmax(230px, 300px) minmax(0, 1fr);
  gap: 16px; align-items: stretch;
}
/* Plegada: la lista se reduce a su lomo y la ficha toma el ancho. Es el mismo
   gesto que pliega el menú de navegación, y el dueño lo pidió con las mismas
   palabras — «por si llegamos a necesitarlo, ganemos el espacio». */
.maestro-detalle.plegado { grid-template-columns: 40px minmax(0, 1fr); }
@media (max-width: 900px) {
  .maestro-detalle, .maestro-detalle.plegado { grid-template-columns: 1fr; }
}

/* La lista llega hasta el FONDO de la ventana en vez de cortarse donde acaban
   sus filas: lo que sobraba era espacio muerto, y en una lista de compañías el
   espacio es filas visibles. Se queda fija al recorrer el detalle, así que
   elegir la siguiente no obliga a volver arriba. */
.md-lista {
  position: sticky; top: 12px;
  display: flex; flex-direction: column;
  /* El alto lo pone JS con `usarAltoRestante`, que mide donde empieza la lista.
     Aqui solo queda el respaldo por si el hook no alcanzo a medir. */
  max-height: calc(100vh - 24px);
  overflow: hidden;
}
/* El bloque de filas es el que crece y el que hace scroll; el buscador y el pie
   se quedan quietos arriba y abajo. */
.md-filas { flex: 1; min-height: 0; overflow-y: auto; padding: 4px; margin: -4px;
            scrollbar-width: thin; scrollbar-color: var(--color-border) transparent; }
.md-filas::-webkit-scrollbar { width: 8px; }
.md-filas::-webkit-scrollbar-track { background: transparent; }
.md-filas::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 999px; }

/* El lomo de la lista plegada: solo el botón para volver a abrirla y el conteo
   girado, para que no quede una columna vacía sin explicación. */
.md-lomo {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 9px 0;
}
.md-lomo .cuenta {
  writing-mode: vertical-rl; font-size: 10.5px; color: var(--muted);
  letter-spacing: .05em; text-transform: uppercase; font-weight: 600;
}
.md-plegar {
  background: none; border: 0; color: var(--muted); cursor: pointer;
  padding: 3px 5px; border-radius: 6px; font-size: 13px; line-height: 1;
}
.md-plegar:hover { background: var(--color-surface-subtle); color: var(--ink); }
.md-fila {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 10px; cursor: pointer;
  border: 1px solid transparent;
}
.md-fila:hover { background: var(--color-surface-subtle); }
.md-fila.sel {
  background: var(--color-row-selected);
  border-color: var(--color-primary);
  box-shadow: inset 3px 0 0 var(--color-primary);
}
.md-fila .nom { font-weight: 600; font-size: 13px; line-height: 1.25;
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Tira de datos duros bajo el encabezado. Es la respuesta de un vistazo: RFC,
   país, categoría, crédito y saldo sin abrir ninguna pestaña. */
.tira-kpi {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.tira-kpi > div { padding: 12px 16px; border-right: 1px solid var(--line); }
.tira-kpi > div:last-child { border-right: 0; }
.tira-kpi dt { font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
               color: var(--muted); font-weight: 600; margin-bottom: 3px; }
.tira-kpi dd { margin: 0; font-size: 14px; font-weight: 600; color: var(--ink); }

/* ---------- portada ----------------------------------------------------------
   Dos columnas: lo que exige una acción manda y ocupa el ancho; los números que
   solo informan van a un lado, en una línea cada uno. Tratarlos igual —tarjetas
   del mismo tamaño— era lo que hacía que la portada no dijera nada. */
.inicio-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 14px; align-items: start;
}
@media (max-width: 900px) { .inicio-grid { grid-template-columns: 1fr; } }

.pendiente {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 9px 4px; background: none; border: 0; border-bottom: 1px solid var(--line);
  font: inherit; text-align: left; cursor: pointer;
}
.pendiente:last-child { border-bottom: 0; }
.pendiente:hover { background: var(--color-surface-subtle); }
.pendiente .n { font-size: 19px; font-weight: 600; min-width: 36px; text-align: right; }
.pendiente .n.red { color: var(--red-ink); }
.pendiente .n.amber { color: var(--color-warning-text); }
.pendiente .tit { display: block; font-weight: 600; font-size: 13px; color: var(--ink); }
.pendiente .sub { display: block; font-size: 11.5px; }

.modulos { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 8px; }
.modulos button {
  display: flex; align-items: center; gap: 7px; background: var(--panel);
  border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px;
  font: inherit; font-size: 12.5px; font-weight: 600; color: var(--ink);
  cursor: pointer; text-align: left;
}
.modulos button:hover { border-color: var(--color-primary); }
.modulos .ico { color: var(--muted); display: flex; }

.cifra { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px;
         padding: 5px 0; border-bottom: 1px solid var(--line); }
.cifra:last-child { border-bottom: 0; }
/* Los números de contexto se agrupan por módulo y su bloque tiene tope de
   altura: son treinta y pico y no pueden estirar la portada sin fin.

   El hueco a la derecha es para la barra de desplazamiento: sin él se monta
   encima de las cifras, que quedan pegadas y se leen encimadas. Y el de abajo
   para que la última fila no muera contra el borde de la tarjeta. */
.cifras-scroll {
  max-height: calc(100vh - 300px); overflow-y: auto;
  padding-right: 12px; padding-bottom: 4px;
  /* Barra fina y del color del tema, no la gris del sistema pegada al texto. */
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
}
.cifras-scroll::-webkit-scrollbar { width: 8px; }
.cifras-scroll::-webkit-scrollbar-track { background: transparent; }
.cifras-scroll::-webkit-scrollbar-thumb {
  background: var(--color-border); border-radius: 999px;
}
.cifras-scroll::-webkit-scrollbar-thumb:hover { background: var(--muted-2); }
/* La última cifra de cada grupo tampoco debe tocar el título del siguiente. */
.cifras-scroll > div:last-child { margin-bottom: 0 !important; }
.cifras-modulo {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  padding: 4px 0; font: inherit; font-size: 10.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .05em; color: var(--muted); cursor: pointer;
}
.cifras-modulo:hover { color: var(--blue-ink); }

/* El cuerpo de un cubo respira, salvo cuando trae una tabla: la `.tbl` ya trae
   su propio relleno y sumarlos deja la columna despegada del borde de la
   tarjeta, que es justo la diferencia que se nota al comparar con Compras. */
.cubo-cuerpo { padding: 4px 20px 10px; }
.cubo-cuerpo > .tbl-wrap { margin: 0 -20px -10px; }

/* El interruptor de confidenciales: un chip que GRITA cuando esta encendido.
   Ambar y no rojo: rojo es error/peligro en este sistema; esto es un estado
   deliberado que conviene notar, no una falla. */
.chip-confidencial {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--panel); color: var(--muted); font: inherit; font-size: 12.5px;
  font-weight: 600; cursor: pointer;
}
.chip-confidencial.on {
  background: var(--amber, #d97706); border-color: var(--amber, #d97706);
  color: #fff;
}
/* ==========================================================================
   KIOSKO - pantallas de TV sin sesion. Todo el bloque lee TOKENS --kz-* y el
   tema solo intercambia valores: claro = papel y paneles blancos (como la
   version clara del mockup del dueno), oscuro = grafito. La CABECERA es
   grafito en los dos temas, igual que en el mockup: es marca, no superficie.
   ========================================================================== */
.kiosko {
  --kz-fondo: #eef1ef; --kz-panel: #fff; --kz-carta: #f4f6f4;
  --kz-borde: #d7ddda; --kz-tinta: #172025; --kz-suave: #68757a;
  --kz-verde: #4c932d; --kz-ambar: #b87815; --kz-rojo: #c04a44;
  --kz-info: #3d7dae;
  min-height: 100vh; background: var(--kz-fondo); color: var(--kz-tinta);
  padding: 16px 20px 28px; font-size: 15px;
  display: flex; flex-direction: column; gap: 12px;
}
[data-theme="oscuro"] .kiosko {
  --kz-fondo: #1a2024; --kz-panel: #202629; --kz-carta: #262d31;
  --kz-borde: #333d42; --kz-tinta: #eef1ef; --kz-suave: #8fa0a6;
  --kz-verde: #9ad46c; --kz-ambar: #f2b544; --kz-rojo: #ff8a80;
  --kz-info: #7db4dd;
}
.kiosko-cabeza {
  background: #202629; color: #eef1ef; border-radius: 14px; padding: 12px 18px;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  box-shadow: 0 8px 22px rgba(29, 40, 35, .10);
}
.kiosko-marca { display: flex; align-items: center; gap: 12px; }
.kiosko-logo {
  /* El logo real de RATIO (verde sobre transparente); antes era una loseta
     verde con una R, que el dueño pidió reemplazar. */
  width: 46px; height: 46px; object-fit: contain; flex: none;
}
.kiosko-marca h1 { margin: 0; font-size: 20px; letter-spacing: .8px; }
.kiosko-marca p { margin: 3px 0 0; color: #b9c5c8; font-size: 11px; }
.kiosko-reloj { text-align: right; background: #30383c; border: 1px solid #465157;
  border-radius: 10px; padding: 8px 12px; min-width: 150px; }
.kiosko-reloj strong { display: block; font-size: 17px; }
.kiosko-reloj span { color: #abb7bb; font-size: 10px; }
.kiosko-boton {
  height: 52px; min-width: 220px; border: 0; border-radius: 11px; cursor: pointer;
  background: linear-gradient(135deg, #78be43, #4c932d); color: #13200e;
  font-weight: 900; font-size: 15px; padding: 0 18px;
}
.kiosko-boton:disabled { background: #3a444a; color: #b9c5c8; cursor: default; }
.kiosko-aviso { font-size: 22px; color: var(--kz-suave); }
.kiosko-vacio { color: var(--kz-suave); font-size: 15px; padding: 18px; text-align: center; }
/* El selector de tema vive en la cabecera grafito, asi que sus chips son
   oscuros en los dos temas. */
.kiosko-tema { display: flex; gap: 4px; background: #30383c; border: 1px solid #465157;
  border-radius: 10px; padding: 4px; }
.kiosko-tema button { border: 0; background: transparent; color: #abb7bb;
  border-radius: 7px; padding: 6px 10px; font-size: 11px; font-weight: 700; cursor: pointer; }
.kiosko-tema button.activo { background: #78be43; color: #14200f; }

/* tareas: dos columnas */
.kiosko-columnas { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; flex: 1; min-height: 0; }
.kiosko-col { background: var(--kz-panel); border: 1px solid var(--kz-borde);
  border-radius: 14px; padding: 14px; display: flex;
  flex-direction: column; min-height: 0; border-top: 5px solid #65747b; }
.kiosko-col.rojo { border-top-color: #df5b55; }
.kiosko-col.ambar { border-top-color: #f2b544; }
/* Sin fecha: informativo, no urgencia (dueño, 2026-09-05). */
.kiosko-col.info { border-top-color: #5b9bd5; }
.kiosko-col-cabeza { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.kiosko-col-cabeza h2 { margin: 0; font-size: 17px; letter-spacing: 1px; }
.kiosko-cuenta { background: var(--kz-carta); border: 1px solid var(--kz-borde);
  border-radius: 999px; padding: 4px 14px; font-size: 17px; font-weight: 800; }
.kiosko-lista { overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }
.kiosko-tarea { background: var(--kz-carta); border: 1px solid var(--kz-borde); border-radius: 10px;
  padding: 10px 14px; display: flex; justify-content: space-between; gap: 12px; align-items: center; }
.kt-cuerpo strong { display: block; font-size: 16px; }
.kt-meta { color: var(--kz-suave); font-size: 12px; }
.kt-lado { text-align: right; flex: none; }
.kt-quien { display: block; font-size: 12.5px; color: var(--kz-tinta); opacity: .85; }
.kt-dias { font-size: 14px; font-weight: 800; color: var(--kz-suave); }
.kt-dias.cerca { color: var(--kz-ambar); }
.kt-dias.tarde { color: var(--kz-rojo); }

/* asistencia */
.kiosko-resumen { display: grid; grid-template-columns: 1.5fr .8fr .8fr; gap: 12px; }
.kiosko-panel { background: var(--kz-panel); border: 1px solid var(--kz-borde);
  border-radius: 14px; padding: 14px 16px; }
.kiosko-panel.semaforo { display: grid; grid-template-columns: 1fr 135px; gap: 14px;
  align-items: center; border-top: 5px solid #f2b544; }
.kiosko-panel.semaforo.listo { border-top-color: #78be43; }
.k-ceja { font-size: 10px; letter-spacing: 1.1px; text-transform: uppercase; color: var(--kz-suave); font-weight: 800; }
.k-titulo { font-size: 24px; font-weight: 900; margin: 6px 0 4px; }
.k-titulo.ok { color: var(--kz-verde); }
.k-titulo.espera { color: var(--kz-ambar); }
.k-desc { font-size: 12px; color: var(--kz-suave); line-height: 1.3; }
.k-metricas { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-top: 10px; }
.k-metrica { background: var(--kz-carta); border: 1px solid var(--kz-borde); border-radius: 8px; padding: 6px 9px; }
.k-metrica span { display: block; font-size: 9px; color: var(--kz-suave); text-transform: uppercase; }
.k-metrica strong { font-size: 19px; }
.k-anillo { width: 128px; height: 128px; border-radius: 50%; display: grid; place-items: center; position: relative; }
.k-anillo:before { content: ""; position: absolute; inset: 13px; border-radius: 50%; background: var(--kz-panel); }
.k-anillo > div { position: relative; text-align: center; }
.k-anillo strong { display: block; font-size: 32px; }
.k-anillo span { font-size: 9px; text-transform: uppercase; color: var(--kz-suave); }
.k-minis { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 10px; }
.k-minis.dos { grid-template-columns: repeat(2, 1fr); }
.k-mini { background: var(--kz-carta); border: 1px solid var(--kz-borde); border-radius: 8px; padding: 9px 6px; text-align: center; }
.k-mini strong { display: block; font-size: 23px; }
.k-mini span { font-size: 9px; color: var(--kz-suave); text-transform: uppercase; }
.k-mini.ok strong { color: var(--kz-verde); }
.k-mini.mal strong { color: var(--kz-rojo); }
.k-mini.alerta strong { color: var(--kz-ambar); }
.k-mini.info strong { color: var(--kz-info); }
.k-campeon strong { display: block; font-size: 18px; margin-top: 4px; }
.k-campeon span { font-size: 12px; color: var(--kz-suave); }
.k-fila-cabeza { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.k-leyenda { display: flex; gap: 12px; font-size: 10px; color: var(--kz-suave); }
.pto { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 5px; }
.pto.arrived { background: #78be43; } .pto.late { background: #f2b544; }
.pto.absent { background: #4b91c8; } .pto.pending { background: #65747b; }
.k-personas { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 6px; }
.k-persona { background: var(--kz-carta); border: 1px solid var(--kz-borde); border-radius: 8px; padding: 8px 10px;
  border-left: 4px solid #65747b; min-width: 0; }
.k-persona.arrived { border-left-color: #78be43; }
.k-persona.late { border-left-color: #f2b544; }
.k-persona.absent { border-left-color: #4b91c8; opacity: .8; }
.k-persona strong { display: block; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.k-persona span { font-size: 11px; color: var(--kz-suave); }
.k-historial { height: 180px; display: flex; align-items: end; gap: 8px; padding: 18px 4px 22px; }
.k-barra-caja { flex: 1; height: 100%; display: flex; align-items: end; justify-content: center; position: relative; }
.k-barra { width: 70%; max-width: 38px; border-radius: 5px 5px 2px 2px; position: relative; min-height: 6px; }
.k-barra.ok { background: #78be43; } .k-barra.mal { background: #df5b55; }
.k-barra span { position: absolute; top: -16px; left: 50%; transform: translateX(-50%); font-size: 10px; font-weight: 800; }
.k-barra-caja label { position: absolute; bottom: -20px; font-size: 10px; color: var(--kz-suave); }
.kiosko-toast { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  background: #202629; border-left: 5px solid #78be43; color: #fff;
  padding: 12px 16px; border-radius: 9px; font-size: 13px; box-shadow: 0 12px 30px rgba(0,0,0,.35); }
@media (max-width: 1100px) {
  .kiosko-resumen { grid-template-columns: 1fr; }
  .kiosko-columnas { grid-template-columns: 1fr; }
}

/* ANTI-QUEMADO: la pasada de limpieza. Funde a negro y una franja tenue
   recorre la pantalla ejercitando los pixeles parejo (ver antiquemado.jsx).
   El fondo es negro REAL a proposito: en un OLED negro = pixel apagado,
   que es el unico descanso de verdad. */
.kiosko-barrido {
  position: fixed; inset: 0; z-index: 999; background: #000;
  animation: kz-fundido 12s ease-in-out both;
}
.kiosko-barrido-franja {
  position: absolute; top: 0; bottom: 0; width: 18vw;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.06), transparent);
  animation: kz-franja 12s linear both;
}
@keyframes kz-fundido { 0% { opacity: 0; } 8% { opacity: 1; } 92% { opacity: 1; } 100% { opacity: 0; } }
@keyframes kz-franja { from { left: -20vw; } to { left: 120vw; } }

/* La CLAVE de una opcion del selector: el id visible, a la izquierda y en
   tabular para que una columna de numeros alinee. Separada por el mismo
   borde fino de 1px que la norma usa entre campos. */
.selbus-con-clave { display: flex; gap: 10px; align-items: flex-start; }
.selbus-clave {
  flex: none; min-width: 40px; text-align: right;
  font-variant-numeric: tabular-nums; color: var(--muted); font-size: 12px;
  border-right: 1px solid var(--line); padding-right: 8px; padding-top: 1px;
}

/* ==========================================================================
   TABLERO DE LA JUNTA MATUTINA — 4K de 65" y monitor de PC, SIN SCROLL.
   ==========================================================================

   La escala vive en `vmin`, no en pixeles: la misma hoja sirve de 24" a 65"
   sin una sola media query de tipografia, porque todo crece con la pantalla.
   Un `font-size: 14px` que se lee bien en el monitor es ilegible a cuatro
   metros; `1.1vmin` se lee igual en los dos.

   El LAYOUT es una rejilla de alto fijo (100vh) con filas en `fr`: nada se
   sale, y lo que sobra se acota dentro de su panel — las listas dicen cuantas
   quedaron fuera en vez de crecer.

   Los colores salen de los tokens del sistema; los `--j-*` son solo el puente
   para que el modo claro y el oscuro cambien de un lugar. */
.junta {
  --j-fondo: var(--bg, #eef1ef);
  --j-panel: var(--panel, #fff);
  --j-carta: var(--color-surface-subtle, #f4f6f4);
  --j-borde: var(--line, #d7ddda);
  --j-tinta: var(--ink, #172025);
  --j-suave: var(--muted, #68757a);
  --j-verde: var(--green, #4c932d);
  --j-ambar: var(--amber, #b87815);
  --j-rojo: var(--red, #c04a44);
  --j-info: var(--blue-ink, #3d7dae);

  position: fixed; inset: 0; z-index: 50;
  background: var(--j-fondo); color: var(--j-tinta);
  font-size: clamp(11px, 1.05vmin, 30px);
  padding: 1vmin 1.2vmin;
  display: grid; gap: 0.9vmin;
  /* LAS PROPORCIONES SON DEL MOCKUP DEL DUEÑO, no una interpretación: doce
     columnas porque son las que dejan expresar sus tres fracciones exactas
     —2/3, 1/3 y los cuartos de la última fila— sin números raros.

       fila 1   condición de arranque (2/3) · resumen del día y del mes (1/3)
       fila 2   historial de 30 días (1/3) · el personal con sus glifos (2/3)
       fila 3   vencidas y próximas se reparten la MITAD; la otra mitad es
                para capturar, «similar a la idea de ingresar tareas masivas»

     Los altos siguen la misma jerarquía: la fila 3 es la que trabaja, así que
     es la que más pesa. */
  grid-template-columns: repeat(12, 1fr);
  /* EL 36% ARRIBA, el resto para las tareas — decisión del dueño. Las
     fracciones se escriben sumando 100 para que se lean como los porcentajes
     que son: 20+16 de contexto, 64 de trabajo.

     `minmax(0, …)` no es adorno: sin él una fila crece si su contenido pide
     más y se lleva el porcentaje entero por delante, que es justo lo que la
     pantalla sin scroll no puede permitirse. */
  grid-template-rows: auto minmax(0, 20fr) minmax(0, 16fr) minmax(0, 64fr);
  grid-template-areas:
    "cabeza    cabeza    cabeza    cabeza    cabeza    cabeza    cabeza    cabeza    cabeza   cabeza   cabeza   cabeza"
    "semaforo  semaforo  semaforo  semaforo  semaforo  semaforo  semaforo  semaforo  resumen  resumen  resumen  resumen"
    "historial historial historial historial personal  personal  personal  personal  personal personal personal personal"
    "vencidas  vencidas  vencidas  proximas  proximas  proximas  sinfecha  sinfecha  captura  captura  captura  captura";
  overflow: hidden;
}
/* MODO PARED: sin sesión no hay captura, así que las dos listas se reparten
   la fila entera — una TV de solo lectura debe usar ese espacio en mostrar
   más pendientes, no en dejar un hueco. */
.junta.pared {
  grid-template-areas:
    "cabeza    cabeza    cabeza    cabeza    cabeza    cabeza    cabeza   cabeza   cabeza   cabeza   cabeza   cabeza"
    "semaforo  semaforo  semaforo  semaforo  semaforo  semaforo  semaforo semaforo resumen  resumen  resumen  resumen"
    "historial historial historial historial personal  personal  personal personal personal personal personal personal"
    "vencidas  vencidas  vencidas  vencidas  proximas  proximas  proximas proximas sinfecha sinfecha sinfecha sinfecha";
}
[data-theme="oscuro"] .junta {
  --j-fondo: #1a2024; --j-panel: #202629; --j-carta: #262d31;
  --j-borde: #333d42; --j-tinta: #eef1ef; --j-suave: #8fa0a6;
  --j-verde: #9ad46c; --j-ambar: #f2b544; --j-rojo: #ff8a80; --j-info: #7db4dd;
}
/* TV de la junta ESPERANDO el gafete de un supervisor (dueño, 2026-08-25):
   pantalla completa, sin tablero, hasta que una tarjeta autorizada la abra. */
.junta.junta-espera {
  display: flex; align-items: center; justify-content: center;
  grid-template-areas: none;
}
.junta-espera-centro {
  display: flex; flex-direction: column; align-items: center; gap: 2.4vmin;
  text-align: center; color: var(--j-tinta);
}
.junta-espera-centro .junta-logo { height: 9vmin; opacity: 0.95; }
.junta-espera-centro h1 { font-size: 5vmin; letter-spacing: 0.06em; margin: 0; }
.junta-espera-msg { font-size: 2.6vmin; color: var(--j-suave); margin: 0; }
.junta-espera-reloj { text-align: center; }
.junta-espera-reloj strong { display: block; font-size: 4vmin; font-variant-numeric: tabular-nums; }
.junta-espera-reloj span { font-size: 1.8vmin; color: var(--j-suave); text-transform: capitalize; }
.junta-espera-aviso {
  margin-top: 1.6vmin; padding: 1vmin 2vmin; border-radius: 1vmin;
  background: var(--j-carta); border: 1px solid var(--j-borde);
  color: var(--j-ambar); font-size: 2vmin;
}

/* La cabecera es grafito en los dos temas: es la franja de marca. */
.junta-cabeza {
  grid-area: cabeza; background: #202629; color: #eef1ef;
  border-radius: 1vmin; padding: 0.8vmin 1.4vmin;
  display: flex; align-items: center; justify-content: space-between; gap: 1.4vmin;
}
.junta-marca { display: flex; align-items: center; gap: 1.2vmin; min-width: 0; }
.junta-logo {
  width: 4vmin; height: 4vmin; object-fit: contain; flex: none;
}
.junta-marca h1 { margin: 0; font-size: 2.1vmin; letter-spacing: 0.06em; }
.junta-marca p { margin: 0.3vmin 0 0; color: #b9c5c8; font-size: 1.15vmin; }
.junta-cabeza-der { display: flex; align-items: center; gap: 1.2vmin; flex: none; }
.junta-reloj {
  background: #30383c; border: 1px solid #465157; border-radius: 0.9vmin;
  padding: 0.7vmin 1.2vmin; text-align: center;
}
.junta-reloj strong { display: block; font-size: 2.4vmin; font-variant-numeric: tabular-nums; }
.junta-reloj span { color: #abb7bb; font-size: 1.05vmin; }
.junta-boton {
  border: 0; border-radius: 0.9vmin; cursor: pointer; padding: 1.1vmin 1.8vmin;
  background: linear-gradient(135deg, #78be43, #4c932d); color: #13200e;
  font-weight: 900; font-size: 1.5vmin; font-family: inherit;
}
.junta-boton.hecho, .junta-boton:disabled {
  background: transparent; border: 1px solid #f2b544; color: #f2b544; cursor: default;
}
/* `span.junta-boton.hecho` («Terminada 09:24») no es botón: hereda la caja
   para que la fila no se descuadre, pero necesita la alineación que el
   navegador solo le da a los controles. */
span.junta-boton { display: inline-flex; align-items: center; }
/* TERMINAR cierra la junta y manda la TV al visor de tareas. Va en ámbar, no
   en verde: el verde de al lado es «empezar» y estos dos botones conviven un
   rato en la misma fila — que se distingan de un vistazo importa más en una
   pared de 65" que la simetría. */
.junta-boton.terminar {
  background: linear-gradient(135deg, #f2b544, #c98a1c); color: #241a06;
}
.junta .kiosko-tema { padding: 0.35vmin; border-radius: 0.8vmin; }
.junta .kiosko-tema button { font-size: 1.05vmin; padding: 0.55vmin 0.9vmin; border-radius: 0.6vmin; }
/* Quién manda la pantalla: bloqueada (ámbar, invita a pasar el gafete) o a
   nombre de alguien (verde, y clicable para bloquear al terminar). */
.junta-sesion {
  border-radius: 0.8vmin; padding: 0.7vmin 1.1vmin; font-size: 1.15vmin;
  font-weight: 800; font-family: inherit; white-space: nowrap;
  background: rgba(120, 190, 67, 0.16); border: 1px solid #78be43;
  color: #9ad46c; cursor: pointer;
}
.junta-sesion.bloqueada {
  background: transparent; border-color: #f2b544; color: #f2b544; cursor: default;
}
.junta-salir {
  background: transparent; border: 1px solid #465157; color: #b9c5c8;
  border-radius: 0.8vmin; padding: 0.8vmin 1vmin; cursor: pointer; font-family: inherit;
}

/* Los paneles: un solo dibujo para los seis. */
.junta-panel {
  background: var(--j-panel); border: 1px solid var(--j-borde);
  border-radius: 1vmin; padding: 1.1vmin 1.4vmin;
  min-height: 0; min-width: 0; display: flex; flex-direction: column;
}
.junta-panel.semaforo {
  grid-area: semaforo; display: grid;
  grid-template-columns: 1fr auto; gap: 1.4vmin; align-items: center;
  border-top: 0.45vmin solid var(--j-ambar);
}
.junta-panel.semaforo.listo { border-top-color: var(--j-verde); }
.junta-resumen { grid-area: resumen; }
.junta-personal { grid-area: personal; }
.junta-historial { grid-area: historial; }

.j-ceja {
  font-size: 1.05vmin; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--j-suave); font-weight: 800;
}
.j-titulo { font-size: 2.9vmin; font-weight: 900; margin: 0.5vmin 0 0.4vmin; line-height: 1.05; }
.j-titulo.ok { color: var(--j-verde); }
.j-titulo.espera { color: var(--j-ambar); }
.j-desc { font-size: 1.2vmin; color: var(--j-suave); line-height: 1.3; }
.j-metricas { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.6vmin; margin-top: 1vmin; }
.j-dato {
  background: var(--j-carta); border: 1px solid var(--j-borde);
  border-radius: 0.7vmin; padding: 0.6vmin 0.8vmin;
}
.j-dato span { display: block; font-size: 0.95vmin; color: var(--j-suave); text-transform: uppercase; }
.j-dato strong { font-size: 2vmin; font-variant-numeric: tabular-nums; }
.j-anillo {
  width: 13vmin; height: 13vmin; border-radius: 50%;
  display: grid; place-items: center; position: relative; flex: none;
}
.j-anillo:before {
  content: ""; position: absolute; inset: 1.3vmin; border-radius: 50%;
  background: var(--j-panel);
}
.j-anillo > div { position: relative; text-align: center; }
.j-anillo strong { display: block; font-size: 3.4vmin; font-variant-numeric: tabular-nums; }
.j-anillo span { font-size: 0.95vmin; text-transform: uppercase; color: var(--j-suave); }

.j-minis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.6vmin; margin-top: 0.7vmin; }
.j-minis.tres { grid-template-columns: repeat(3, 1fr); }
.j-mini {
  background: var(--j-carta); border: 1px solid var(--j-borde);
  border-radius: 0.7vmin; padding: 0.8vmin 0.4vmin; text-align: center;
}
.j-mini strong { display: block; font-size: 2.6vmin; font-variant-numeric: tabular-nums; }
.j-mini span { font-size: 0.9vmin; color: var(--j-suave); text-transform: uppercase; }
.j-mini.ok strong { color: var(--j-verde); }
.j-mini.mal strong { color: var(--j-rojo); }
.j-mini.alerta strong { color: var(--j-ambar); }
.j-mini.info strong { color: var(--j-info); }
/* El panel de resumen lleva DOS bloques de indicadores (hoy y el mes) y al
   ajustar la fila superior al 36% dejo de caber por 23px: sus alturas venian
   del contenido. Ahora los dos bloques se REPARTEN lo que haya, que es lo
   que corresponde en una pantalla de alto fijo. */
.junta-resumen .j-minis { flex: 1; min-height: 0; }
.junta-resumen .j-mini { display: flex; flex-direction: column; justify-content: center; padding: 0.4vmin; }

/* El personal en INICIALES: lo que se lee de lejos es el color del borde. */
.j-fila-cabeza {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1vmin; margin-bottom: 0.7vmin; flex: none;
}
.j-fila-cabeza h2 { margin: 0; font-size: 1.7vmin; letter-spacing: 0.06em; }
.j-leyenda { display: flex; gap: 0.9vmin; font-size: 0.95vmin; color: var(--j-suave); }
.j-pto { display: inline-block; width: 0.8vmin; height: 0.8vmin; border-radius: 50%; margin-right: 0.4vmin; }
.j-pto.arrived { background: var(--j-verde); }
.j-pto.late { background: var(--j-ambar); }
.j-pto.absent { background: var(--j-info); }
.j-pto.pending { background: var(--j-suave); }
.j-personas {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(6.5vmin, 1fr));
  gap: 0.6vmin; align-content: start; overflow: hidden;
}
.j-persona {
  background: var(--j-carta); border: 1px solid var(--j-borde);
  /* El estado va ARRIBA: `.j-personas` recorta por abajo (overflow hidden) y
     con dos filas el borde inferior de la segunda desaparecía — visto en la
     TV el 2026-08-24. Arriba nunca se recorta y es el mismo acento que ya
     usan las listas del kiosko. */
  border-top: 0.4vmin solid var(--j-suave);
  border-radius: 0.7vmin; padding: 0.7vmin 0.3vmin; text-align: center; min-width: 0;
}
.j-persona.a_tiempo { border-top-color: var(--j-verde); }
.j-persona.retardo { border-top-color: var(--j-ambar); }
.j-persona.ausencia { border-top-color: var(--j-info); opacity: 0.65; }
.j-persona strong { display: block; font-size: 1.8vmin; letter-spacing: 0.03em; }
.j-persona span {
  display: block; font-size: 0.9vmin; color: var(--j-suave);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Las listas de pendientes */
.junta-lista.rojo { grid-area: vencidas; border-top: 0.45vmin solid var(--j-rojo); }
.junta-lista.ambar { grid-area: proximas; border-top: 0.45vmin solid var(--j-ambar); }
/* SIN FECHA (dueño, 2026-09-05): lo capturado al vuelo que aún no tiene
   plazo. En azul informativo — no es una urgencia, es trabajo por repartir. */
.junta-lista.info { grid-area: sinfecha; border-top: 0.45vmin solid var(--j-info); }
.j-cuenta {
  background: var(--j-carta); border: 1px solid var(--j-borde);
  border-radius: 999px; padding: 0.2vmin 1.1vmin;
  font-size: 1.7vmin; font-weight: 800; font-variant-numeric: tabular-nums;
}
.j-tareas { display: flex; flex-direction: column; gap: 0.5vmin; overflow: hidden; flex: 1; min-height: 0; }
.j-tarea {
  background: var(--j-carta); border: 1px solid var(--j-borde);
  border-radius: 0.7vmin; padding: 0.7vmin 0.9vmin;
  display: grid; grid-template-columns: 1fr auto auto; gap: 0.9vmin; align-items: center;
}
.j-tarea strong {
  display: block; font-size: 1.35vmin; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.j-tarea-meta {
  display: block; font-size: 1vmin; color: var(--j-suave);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.j-tarea-lado { text-align: right; }
.j-plazo { display: block; font-size: 1.15vmin; font-weight: 800; color: var(--j-suave); }
.j-plazo.hoy { color: var(--j-ambar); }
.j-plazo.tarde { color: var(--j-rojo); }
.j-quien { display: block; font-size: 1vmin; color: var(--j-suave); }
.j-lista {
  border: 0; border-radius: 0.6vmin; cursor: pointer; font-family: inherit;
  background: var(--j-verde); color: #fff;
  padding: 0.7vmin 1.3vmin; font-size: 1.2vmin; font-weight: 800;
}
.j-pendiente, .j-estado-chico {
  font-size: 1vmin; color: var(--j-suave); border: 1px dashed var(--j-borde);
  border-radius: 0.6vmin; padding: 0.5vmin 0.8vmin; white-space: nowrap;
}
.j-mas { flex: none; margin-top: 0.6vmin; font-size: 1.05vmin; color: var(--j-suave); text-align: center; }
.j-vacio { color: var(--j-suave); font-size: 1.2vmin; padding: 1.5vmin; text-align: center; }

/* La captura de la junta */
.junta-captura { grid-area: captura; }
.j-capturadas { font-size: 1.05vmin; color: var(--j-suave); }
.j-fila-mas, .j-guardar {
  border-radius: 0.6vmin; cursor: pointer; font-family: inherit;
  font-size: 1.15vmin; font-weight: 800; padding: 0.6vmin 1.2vmin;
}
.j-fila-mas { background: transparent; border: 1px solid var(--j-borde); color: var(--j-tinta); }
.j-guardar { background: var(--j-verde); border: 0; color: #fff; }
.j-guardar:disabled { background: var(--j-borde); color: var(--j-suave); cursor: default; }
.j-error { color: var(--j-rojo); font-size: 1.1vmin; margin-bottom: 0.5vmin; }
/* La rejilla del sistema (RejillaCaptura) dentro del tablero: hereda la
   escala vmin y hace su propio scroll interno, para que la pantalla no lo
   necesite. Antes había aquí una rejilla ad-hoc; se retiró cuando el dueño
   pidió usar la del alta masiva — dos rejillas para lo mismo divergen. */
.j-rejilla-caja { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.j-rejilla-caja .rejilla { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.j-rejilla-caja .rejilla-scroll { flex: 1; min-height: 0; overflow: auto; }
.junta .rejilla-tabla { font-size: 1.15vmin; }
.junta .rejilla-tabla th { font-size: 0.95vmin; }
.junta .rj-celda, .junta .selbus-caja {
  font-size: 1.15vmin; padding: 0.5vmin 0.6vmin;
}
.junta .rejilla-pie { font-size: 1vmin; padding-top: 0.6vmin; }
.junta .rejilla-pie .btn { font-size: 1vmin; padding: 0.45vmin 0.9vmin; }

.junta-toast {
  position: fixed; left: 50%; bottom: 2vmin; transform: translateX(-50%);
  background: #202629; color: #fff; border-left: 0.4vmin solid #78be43;
  padding: 1.1vmin 1.6vmin; border-radius: 0.8vmin; font-size: 1.3vmin;
  box-shadow: 0 1vmin 3vmin rgba(0, 0, 0, 0.35); z-index: 60;
}
.j-aviso { font-size: 2.2vmin; color: var(--j-suave); }

/* MONITOR DE PC en vertical u horizontal chico: la rejilla de tres columnas
   no cabe con dignidad, asi que se apila en dos y se permite el scroll — en
   un monitor si existe el gesto, en la TV no. */
@media (max-width: 1100px), (max-height: 620px) {
  .junta, .junta.pared {
    position: static; grid-template-columns: 1fr 1fr;
    grid-template-rows: repeat(6, auto);
    grid-template-areas:
      "cabeza    cabeza"
      "semaforo  resumen"
      "historial historial"
      "personal  personal"
      "vencidas  proximas"
      "captura   captura";
    overflow: auto; font-size: 13px;
  }
  .junta .j-ceja, .junta .j-desc, .junta .j-quien, .junta .j-tarea-meta { font-size: 11.5px; }
  .junta .j-titulo { font-size: 22px; }
  .junta .j-anillo { width: 110px; height: 110px; }
  .junta .j-anillo strong { font-size: 28px; }
  .junta .j-mini strong, .junta .j-dato strong { font-size: 20px; }
  .junta .j-tarea strong { font-size: 13.5px; }
  .junta .j-rej-fila input, .junta .j-rej-fila select,
  .junta .selbus-caja { font-size: 13px; padding: 6px 8px; }
}

/* El historial del mes en modo PARED: ocupa el lugar de la captura. Barras
   con la misma escala vmin que el resto del tablero. */
.j-historial {
  flex: 1; min-height: 0; display: flex; align-items: flex-end;
  gap: 0.35vmin; padding: 1.8vmin 0.2vmin 2vmin;
}
.j-barra-caja {
  flex: 1; height: 100%; display: flex; align-items: flex-end;
  justify-content: center; position: relative; min-width: 0;
}
.j-barra {
  width: 78%; max-width: 2.2vmin; border-radius: 0.4vmin 0.4vmin 0.15vmin 0.15vmin;
  position: relative; min-height: 0.6vmin;
}
.j-barra.ok { background: var(--j-verde); }
.j-barra.mal { background: var(--j-rojo); }
/* Los días SIN junta (dueño, 2026-09-08): muñones al ras, cada uno con su
   porqué — hábil sin junta en rojo apagado, descanso apenas visible, y lo
   que aún no ocurre casi vacío. La gráfica cuenta el mes entero. */
.j-barra.norealizada { background: var(--j-rojo); opacity: 0.3; }
.j-barra.descanso { background: var(--j-suave); opacity: 0.25; }
.j-barra.vacia { background: var(--j-borde); opacity: 0.4; }
.j-barra-caja.clicable { cursor: pointer; }
.j-barra-caja.clicable:hover .j-barra { filter: brightness(1.25); }
/* Las flechas ◀ ▶ del mes (dueño, 2026-09-08): recorren meses anteriores. */
.j-mes-flecha {
  background: none; border: 1px solid var(--j-borde); color: var(--j-suave);
  border-radius: 0.4vmin; cursor: pointer; line-height: 1;
  font-size: 1.1vmin; padding: 0.25vmin 0.6vmin;
}
.j-mes-flecha:hover:not(:disabled) { color: inherit; border-color: var(--j-suave); }
.j-mes-flecha:disabled { opacity: 0.35; cursor: default; }
.j-barra span {
  position: absolute; top: -1.6vmin; left: 50%; transform: translateX(-50%);
  font-size: 0.95vmin; font-weight: 800; font-variant-numeric: tabular-nums;
}
.j-barra-caja label {
  position: absolute; bottom: -1.8vmin; font-size: 0.95vmin; color: var(--j-suave);
}


/* ─── Diálogo de ENVIAR una OC al proveedor ─────────────────────────────────
 *
 * Dos columnas: el documento que se va y el correo con el que se va. El PDF
 * ocupa la mayor parte porque es lo que hay que revisar — es la última
 * oportunidad de corregir algo antes del punto de no retorno.
 */
.env-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 18px; align-items: start; }
.env-doc { min-width: 0; max-height: 62vh; overflow-y: auto; }
/* Alto fijo y no `auto`: un visor de PDF sin alto declarada colapsa a cero.
   60vh deja ver una página completa sin que el modal desborde la pantalla. */
.env-pdf { width: 100%; height: 42vh; border: 1px solid var(--line); border-radius: 8px;
           background: var(--panel-2, var(--panel)); }
.env-pdf-cargando { display: grid; place-items: center; font-size: 13px; }
.env-correo { display: grid; gap: 10px; min-width: 0; }
.env-correo label { display: grid; gap: 4px; font-size: 12px; font-weight: 600; }
.env-correo input, .env-correo textarea { font-weight: 400; width: 100%; }
.env-resumen { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 14px;
               padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; }
.env-resumen dt { font-size: 11px; color: var(--muted); text-transform: uppercase;
                  letter-spacing: .02em; }
.env-resumen dd { margin: 0; font-size: 13px; }
/* El adjunto se ve como un adjunto: un renglón con su icono y su nombre, como
   en cualquier cliente de correo. Dicho con texto se leería como una promesa. */
.env-adjunto { display: flex; align-items: center; gap: 8px; padding: 8px 10px;
               border: 1px dashed var(--line); border-radius: 8px; font-size: 12px; }

/* En un monitor angosto las dos columnas se apilan; el PDF baja de alto para
   que el formulario siga alcanzable sin recorrer media pantalla. */
@media (max-width: 900px) {
  .env-grid { grid-template-columns: 1fr; }
  .env-pdf { height: 42vh; }
}

/* ─── TablaDatos: orden acumulable y filtros por columna ────────────────────
 *
 * La gemela de `RejillaCaptura`: aquélla captura filas, ésta las lee.
 */
.td-envoltura { display: grid; gap: 8px; }
.td-barra { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.td-conteo { font-size: 12px; display: flex; align-items: center; gap: 10px; }
/* El aviso de datos parciales va en ámbar: no es un error, es una advertencia
   sobre lo que el número NO dice. */
.td-parcial { display: inline-flex; align-items: center; gap: 4px;
              color: var(--color-warning-text); font-weight: 600; }
.td-acciones { display: flex; gap: 8px; align-items: center; }

/* El encabezado se vuelve dos controles: ordenar (todo el texto) y filtrar. */
.td-th { display: flex; align-items: center; gap: 4px; justify-content: inherit; }
.td-tabla th.num .td-th { justify-content: flex-end; }
.td-orden { background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
            color: inherit; display: inline-flex; align-items: center; gap: 4px; }
/* El header es OSCURO en ambos temas: el hover aclara al texto fuerte del
   header (blanco), no al `--ink` oscuro que se perdía sobre el fondo. */
.td-orden:hover { color: var(--color-header-text); }
.td-orden.activo { font-weight: 700; }
/* Aviso de orden activo para las tablas que reusan solo el encabezado (el
   listado de OCs, por ejemplo): sin la barra de `TablaDatos` no habría de
   dónde quitarlo, y un orden que no se sabe cómo deshacer se siente roto. */
/* Un renglón dado de baja: sigue ahí —hace falta para entender el histórico—
   pero no compite por la atención con los vigentes. */
.td-tabla tr.td-inactiva { opacity: .5; }
/* Lo contrario: un renglón que reclama atención —una muestra que debió volver
   y no volvió—. Fondo y no color de texto, para que se vea de reojo. */
.td-tabla tr.td-vencida > td { background: var(--color-danger-soft); }
/* El renglón de alta: se separa de los datos porque no es uno de ellos. */
.td-tabla tr.td-pie > td { background: var(--bg-soft, transparent);
                           border-top: 2px solid var(--line); }
/* Arranque: mientras el servidor confirma si la sesión guardada sigue viva.
   Sin texto a propósito — «Cargando…» duraría menos de lo que se tarda en
   leerlo, y en la conexión buena no llega ni a verse. */
.arranque { min-height: 100vh; display: grid; place-items: center;
            background: var(--bg); }
.arranque img { width: 120px; opacity: .35; }

/* ── EL COTIZADOR ─────────────────────────────────────────────────────────
   El tipo de cambio vive en el encabezado y no en un paso: se fija una vez y
   queda a la vista, porque el importe de cada partida en dólares depende de él. */
.cot-encabezado { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
                  padding: 10px 14px; margin-bottom: 12px;
                  background: var(--color-surface-subtle, var(--bg-soft));
                  border: 1px solid var(--line); border-radius: var(--ratio-radius); }
.cot-encabezado-edit { align-items: flex-end; }
/* Los cinco precios de banco en un renglón y las tres referencias oficiales en
   otro, con un borde fino entre ellos. No es adorno: son datos de distinta
   naturaleza —a los oficiales nadie te vende un dólar— y en la fuente vienen
   revueltos en las mismas columnas. La línea es lo que impide que se vuelvan a
   leer como una sola lista. */
.cot-fila-paridad { display: flex; gap: 12px; flex-wrap: wrap;
                    align-items: flex-end; }
.cot-fila-oficial { align-items: center; padding-top: 10px;
                    border-top: 1px solid var(--line-soft, var(--line)); }
.cot-fila-oficial .cot-et { margin-right: 4px; }
.cot-ancho { flex-basis: 100%; }
/* EL PANEL LATERAL: la cadena del precio mientras se captura. Sin él hay que
   llegar al último paso para saber qué hizo un costo, y volver. */
.cot-papel { display: block; font-size: 10px; color: var(--muted);
             font-weight: 400; text-transform: none; letter-spacing: 0; }
.cot-panel-pie > div { display: flex; flex-direction: column; }

/* La ficha de lectura del paso Estructura: tres cifras y una línea fina. */
.cot-ficha { display: flex; gap: 28px; flex-wrap: wrap; padding: 10px 14px;
             border: 1px solid var(--line); border-radius: var(--ratio-radius);
             background: var(--color-surface-subtle, var(--bg-soft)); }

/* Donde estaba el botón «Recalcular». Ocupa su lugar a propósito: si el hueco
   se cerrara, la fila de campos se recorrería al guardar y parecería otra
   pantalla. */
.cot-recalculo { display: flex; align-items: flex-end; font-size: 12px;
                 color: var(--muted); padding-bottom: 8px; }

.cot-pct { width: 80px; text-align: right; font: inherit; padding: 4px 6px;
           border: 1px solid var(--line); border-radius: var(--ratio-radius-sm);
           background: var(--color-surface); color: var(--ink); }

.cot-etapa { width: 100%; font: inherit; padding: 4px 6px;
             border: 1px solid var(--line); border-radius: var(--ratio-radius-sm);
             background: var(--color-surface); color: var(--ink); }
.cot-condiciones { margin: 6px 0 0 20px; font-size: 12.5px; color: var(--muted); }
.cot-condiciones li { margin-bottom: 4px; }

.cot-opcional { display: inline-flex; align-items: center; gap: 5px;
                font-size: 11px; color: var(--muted); cursor: pointer; }
/* Un importe que no suma se ve distinto del que sí: tacharlo mentiría (el
   precio es real), atenuarlo dice lo cierto — está, pero fuera del total. */
.cot-no-suma { color: var(--muted); font-weight: 400; }

.cot-mover { display: inline-flex; gap: 2px; }
.cot-mover .x { font-size: 12px; line-height: 1; padding: 2px 5px; }
.cot-mover .x:disabled { opacity: .3; cursor: default; }

/* ── La gráfica del resumen ────────────────────────────────────────────────
   Una barra apilada y no un pastel: aquí se compara cuánto pesa cada capa
   contra el precio, y eso es una longitud, no un ángulo. */
.cot-apilada { display: flex; height: 26px; margin-top: 10px; overflow: hidden;
               border-radius: var(--ratio-radius-sm);
               border: 1px solid var(--line); }
.cot-tramo { height: 100%; }
/* Los colores dicen QUÉ ES cada cosa: costo en azul, dinero financiero en
   ámbar, margen en verde. La intensidad separa material de indirecto sin
   inventar un color nuevo para algo que es de la misma naturaleza. */
.cot-tramo.materiales, .cot-punto.materiales,
.cot-prop-barra.nacional { background: var(--blue); }
.cot-tramo.indirectos, .cot-punto.indirectos { background: var(--blue-ink);
                                               opacity: .55; }
.cot-tramo.intereses, .cot-punto.intereses,
.cot-prop-barra.importado { background: var(--amber); }
.cot-tramo.fijos, .cot-punto.fijos { background: var(--teal); }
.cot-tramo.utilidad, .cot-punto.utilidad { background: var(--green); }

.cot-leyenda { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 10px;
               font-size: 12px; }
.cot-clave { display: inline-flex; align-items: center; gap: 6px; }
.cot-clave b { font-variant-numeric: tabular-nums; }
.cot-clave em { color: var(--muted); font-style: normal; }
.cot-punto { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
.cot-corte { margin-top: 10px; padding-top: 8px; font-size: 12px;
             color: var(--muted);
             border-top: 1px solid var(--line-soft, var(--line)); }

.cot-proporcion { display: grid; gap: 8px; margin-top: 10px; }
.cot-prop-reng { display: grid; align-items: center; gap: 10px;
                 grid-template-columns: 84px 1fr auto 48px; font-size: 12px; }
.cot-prop-pista { height: 12px; background: var(--bg-soft, var(--color-surface));
                  border: 1px solid var(--line); border-radius: 6px;
                  overflow: hidden; }
.cot-prop-barra { height: 100%; }
.cot-prop-reng b { font-variant-numeric: tabular-nums; }
.cot-prop-reng em { font-style: normal; text-align: right; }

/* Botón de solo icono: cuadrado, para que cuatro seguidos formen una tira
   pareja en vez de cajas de anchos distintos. El nombre vive en el `title`. */
.icono-solo { padding: 5px 7px; margin-right: 4px; line-height: 1; }
.icono-solo svg { display: block; }

/* El «?» de ayuda. Pequeño y en gris: acompaña a la etiqueta, no compite con
   ella. Antes esto era un párrafo encima de la captura — se lee una vez y
   estorba las mil siguientes. */
.ayuda { display: inline-flex; align-items: center; justify-content: center;
         width: 14px; height: 14px; border-radius: 50%;
         border: 1px solid var(--line); color: var(--muted);
         font-size: 9px; font-weight: 700; line-height: 1; cursor: help;
         text-transform: none; letter-spacing: 0;
         /* ALINEADO CON EL TÍTULO, no colgando de él. `vertical-align: middle`
            lo centraba contra la línea completa —incluida la parte que baja de
            las letras— y con un título en mayúsculas de 11px eso lo dejaba
            medio renglón abajo. `text-bottom` lo asienta en la base del texto,
            que es donde el ojo espera un signo al lado de una palabra.
            El margen va en `em` para que crezca con la etiqueta. */
         vertical-align: text-bottom; margin-left: 0.45em; }
/* Un título con ayuda deja de ser `display: block` mientras la tenga: si no, el
   «?» cae al renglón de abajo en las etiquetas que son bloque. */
.cot-et:has(.ayuda) { display: inline-flex; align-items: baseline; }
/* Y dentro de un `<label>`, que apila sus hijos en columna para dejar el campo
   debajo del título, el «?» se iba a su propio renglón. `.rotulo` los junta en
   un solo hijo del label, y ahí sí van uno al lado del otro. */
.rotulo { display: inline-flex; align-items: baseline; }
/* EL «?» NO DEBE MOVER SU CAMPO. Mide 14px contra los 13 de la línea de texto,
   y ese pixel de más empujaba el campo hacia abajo: en una rejilla de tres
   columnas, el único apartado con ayuda quedaba dos pixeles más bajo que sus
   vecinos, y eso se lee como un descuadre aunque sea mínimo.
   El primer intento fue encoger el icono a altura cero y dejar que el dibujo
   desbordara. Funcionaba para la altura y descolocaba el dibujo siete pixeles.
   La salida correcta es la contraria: que TODOS los rótulos tengan un renglón
   ya suficientemente alto, con o sin ayuda. Así el icono no cambia nada. */
.wiz-grid label { line-height: 1.5; }
.ayuda:hover { border-color: var(--blue); color: var(--blue); }

.cot-guardado { font-size: 12px; color: var(--muted); align-self: center; }

.cot-galeria { display: grid; gap: 12px; margin-top: 10px;
               grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.cot-imagen { margin: 0; border: 1px solid var(--line);
              border-radius: var(--ratio-radius); overflow: hidden;
              background: var(--color-surface); }
.cot-imagen img { display: block; width: 100%; height: 140px;
                  object-fit: contain; background: var(--bg-soft, transparent);
                  border-bottom: 1px solid var(--line); }
.cot-imagen figcaption { padding: 8px; display: grid; gap: 6px; }
.cot-imagen input { width: 100%; font: inherit; font-size: 12px; padding: 4px 6px;
                    border: 1px solid var(--line);
                    border-radius: var(--ratio-radius-sm);
                    background: var(--color-surface); color: var(--ink); }
.cot-imagen-pie { display: flex; justify-content: space-between;
                  align-items: center; font-size: 11px; }

.cot-panel { font-size: 13px; }
.cot-panel-tit { font-size: 11px; font-weight: 600; letter-spacing: .08em;
                 text-transform: uppercase; color: var(--muted);
                 margin-bottom: 10px; }
.cot-panel-reng { display: flex; justify-content: space-between; gap: 10px;
                  align-items: baseline; padding: 5px 0; }
.cot-panel-reng span { display: flex; flex-direction: column; }
.cot-panel-reng small { color: var(--muted); font-size: 11px; }
.cot-panel-reng b { font-variant-numeric: tabular-nums; }
.cot-panel-reng.fuerte { font-size: 15px; }
.cot-panel-reng.fuerte b { font-size: 17px; }
/* Línea fina, no espacio: separa la base del costo de las capas de margen, que
   es la división que explica por qué el precio no es una suma. */
.cot-panel-sep { border-top: 1px solid var(--line); margin: 6px 0; }
.cot-panel-nota { font-size: 12px; color: var(--muted); margin-top: 10px;
                  padding: 8px 10px; border: 1px solid var(--line);
                  border-radius: var(--ratio-radius-sm); }
.cot-panel-pie { margin-top: 14px; padding-top: 10px;
                 border-top: 1px solid var(--line); display: flex;
                 justify-content: space-between; align-items: baseline; }

.cot-tabla-dolar td, .cot-tabla-dolar th { padding: 5px 8px; }
.cot-tr-total td { border-top: 1px solid var(--line); font-weight: 600; }
.cot-lista-fuera { margin: 4px 0 0 18px; font-size: 12px; color: var(--muted); }

.cot-lectura { font-size: 12px; padding: 8px 10px; border-radius: var(--ratio-radius-sm);
               background: var(--color-surface); border: 1px solid var(--line); }
.cot-et { font-size: 11px; font-weight: 600; letter-spacing: .08em;
          text-transform: uppercase; color: var(--muted); display: block; }
.cot-tc { font-size: 20px; font-variant-numeric: tabular-nums; }
/* Sin paridad, lo importado se cuenta sin convertir. No se esconde: el precio
   va a salir bajo y sin aviso nadie sabría por qué. */
.cot-alerta { display: inline-flex; align-items: center; gap: 6px; font-size: 12px;
              color: var(--amber-ink, var(--amber)); }
.cot-campo { display: flex; flex-direction: column; gap: 4px; font-size: 12px;
             color: var(--muted); min-width: 110px; }
.cot-campo input, .cot-campo select { font: inherit; padding: 6px 8px;
             border: 1px solid var(--line); border-radius: var(--ratio-radius-sm);
             background: var(--color-surface); color: var(--ink); }

/* Una pestaña por subcuenta, con su importe: una subcuenta vacía es la que se
   olvida, y el cero se tiene que ver. */
.cot-pestanas { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.cot-sp { font: inherit; font-size: 13px; padding: 6px 12px; border-radius: 999px;
          cursor: pointer; border: 1px solid var(--line);
          background: var(--color-surface); color: var(--muted);
          display: inline-flex; align-items: center; gap: 8px; }
.cot-sp:hover { color: var(--ink); border-color: var(--muted); }
/* Tinta y superficie INVERTIDAS: en claro sale oscura con letra clara, en
   oscuro al revés. Con la letra fija en blanco, en modo oscuro quedaba blanco
   sobre blanco (`--color-primary-dark` no existe y caía en `--ink`). */
.cot-sp.activa { background: var(--ink); border-color: transparent;
                 color: var(--color-surface); font-weight: 600; }
.cot-n { font-size: 11px; opacity: .75; font-variant-numeric: tabular-nums; }

.cot-pie { display: flex; justify-content: space-between; align-items: flex-end;
           gap: 16px; margin-top: 14px; padding-top: 12px;
           border-top: 1px solid var(--line); }
.cot-total { font-size: 20px; font-variant-numeric: tabular-nums; }

.cot-mandos { display: grid; gap: 14px; margin-bottom: 16px;
              grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

/* La cadena del gross-up: cada término con su porqué, para que el cotizador
   pueda EXPLICAR el precio y no solo darlo. */
.cot-cadena { border: 1px solid var(--line); border-radius: var(--ratio-radius);
              overflow: hidden; }
.cot-reng { display: flex; justify-content: space-between; align-items: baseline;
            gap: 16px; padding: 10px 14px; border-bottom: 1px solid var(--line-soft, var(--line));
            border-left: 3px solid transparent; }
.cot-reng:last-child { border-bottom: 0; }
.cot-reng small { display: block; color: var(--muted); font-size: 12px; }
.cot-reng b { font-size: 15px; font-variant-numeric: tabular-nums; }
.cot-reng.costo { border-left-color: var(--blue-ink); }
.cot-reng.capa { border-left-color: var(--amber-ink, var(--amber)); }
.cot-reng.total { border-left-color: var(--green-ink); background: var(--bg-soft); }
.cot-reng.total b { font-size: 20px; }

.cot-resumen { display: flex; flex-direction: column; gap: 16px; }
.cot-cifras { display: grid; gap: 12px;
              grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.cot-cifra { border: 1px solid var(--line); border-radius: var(--ratio-radius);
             padding: 12px 14px; }
.cot-cifra b { display: block; margin-top: 4px; font-size: 20px;
               font-variant-numeric: tabular-nums; }
.cot-cifra.destacada { border-color: var(--green-ink); }
.cot-expo { border: 1px solid var(--line); border-radius: var(--ratio-radius);
            padding: 12px 14px; }
.cot-expo-barras { display: grid; gap: 10px; margin-top: 8px;
                   grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.cot-barra { border-left: 3px solid var(--blue-ink); padding-left: 10px; }
.cot-barra.importado { border-left-color: var(--amber-ink, var(--amber)); }
.cot-barra b { display: block; font-size: 17px; font-variant-numeric: tabular-nums; }
.cot-sub-lista { border: 1px solid var(--line); border-radius: var(--ratio-radius); }
.cot-sub-reng { display: flex; justify-content: space-between; padding: 8px 14px;
                border-bottom: 1px solid var(--line-soft, var(--line)); font-size: 14px; }
.cot-sub-reng:last-child { border-bottom: 0; }

/* El tipo de cotización: dos opciones grandes, con su explicación. Un combo de
   dos valores esconde justo lo que hay que entender para elegir. */
.cot-tipo { display: grid; gap: 10px; margin-top: 6px;
            grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.cot-op { font: inherit; text-align: left; cursor: pointer; padding: 12px 14px;
          border: 1px solid var(--line); border-radius: var(--ratio-radius);
          background: var(--color-surface); color: var(--ink); }
.cot-op b { display: block; }
.cot-op small { color: var(--muted); }
.cot-op.activa { border-color: var(--green-ink); box-shadow: inset 3px 0 0 var(--green-ink); }
.cot-agregar { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap;
               margin-bottom: 14px; }
.cot-reng-agr { display: flex; justify-content: space-between; align-items: center;
                gap: 14px; padding: 10px 14px;
                border-bottom: 1px solid var(--line-soft, var(--line)); }
.cot-reng-agr:last-child { border-bottom: 0; }
.cot-reng-agr small { display: block; color: var(--muted); font-size: 12px; }
.cot-reng-cifras { display: flex; align-items: center; gap: 14px; }
.cot-reng-cifras b { font-variant-numeric: tabular-nums; }
/* La simple cambió después de agruparse: no se corrige sola, pero se dice. */
.cot-desfasada { color: var(--amber-ink, var(--amber)); }

/* Subpestañas: navegación de segundo nivel. Se distinguen de las pestañas de
   la pantalla por ser más chicas y por marcar con fondo en vez de subrayado —
   dos subrayados en dos renglones no dicen cuál manda. */
.subpestanas { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0 14px;
               padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.subpestana { display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
              font: inherit; font-size: 13px; padding: 5px 12px; border-radius: 999px;
              border: 1px solid var(--line); background: transparent;
              color: var(--muted); }
.subpestana:hover { color: var(--ink); border-color: var(--muted); }
.subpestana.activa { background: var(--color-primary, var(--blue-ink));
                     border-color: transparent;
                     color: var(--color-primary-text, #fff); font-weight: 600; }
.subpestana-n { font-size: 11px; opacity: .75; }
/* El cero se marca: es el catálogo que falta capturar, no un detalle. */
.subpestana-n.cero { opacity: 1; color: var(--red-ink, var(--red)); font-weight: 700; }
.subpestana.activa .subpestana-n.cero { color: inherit; }

.td-orden-activo { display: flex; align-items: center; gap: 8px; margin: 6px 0;
                   font-size: 12px; color: var(--muted); }
/* El número de prioridad, pequeño y pegado a la flecha: dice en qué orden se
   aplican las columnas sin robar espacio al encabezado. */
.td-flecha { font-size: 10px; letter-spacing: -.5px; }
.td-flecha sup { font-size: 9px; margin-left: 1px; }

.td-filtro-caja { position: relative; display: inline-flex; }
.td-filtro { background: none; border: 0; padding: 2px; cursor: pointer;
             color: var(--muted); display: inline-flex; opacity: .5; }
.td-filtro:hover { opacity: 1; }
.td-filtro.activo { opacity: 1; color: var(--color-header-text); }

/* El menú vive en un PORTAL sobre <body>, con posición del viewport calculada
 * en JS. Anclado dentro del <th> se cortaba: el contenedor de la tabla tiene
 * overflow y una columna estrecha a la izquierda no da ancho suficiente.
 * `z-index` alto por la misma razón que el selector: tiene que quedar sobre la
 * tabla, sobre su contenedor y sobre cualquier panel lateral. */
.td-menu { position: fixed; z-index: 120;
           background: var(--panel); border: 1px solid var(--line);
           border-radius: 10px; box-shadow: 0 12px 32px var(--color-overlay-strong);
           padding: 8px; display: grid; gap: 6px; font-weight: 400;
           font-size: 13px; text-align: left; }

/* El rango «de / a»: etiqueta a la izquierda, campo ocupando el resto. */
.td-rango-campo { display: grid; grid-template-columns: 28px 1fr; align-items: center;
                  gap: 8px; font-size: 12px; }
.td-rango-campo input { width: 100%; }
.td-pie { font-size: 11px; line-height: 1.35; }
.td-busca { width: 100%; font-size: 12px; }
.td-todos { display: flex; gap: 6px; }
/* Alto tope con scroll: una columna con 300 valores distintos no puede
   desbordar la pantalla. */
.td-valores { max-height: 240px; overflow-y: auto; display: grid; gap: 1px; }
.td-valor { display: flex; align-items: center; gap: 6px; font-size: 12px;
            padding: 3px 4px; border-radius: 6px; cursor: pointer; }
.td-valor:hover { background: var(--color-hover, rgba(127,127,127,.08)); }
.td-valor input { margin: 0; }
.td-valor span:nth-of-type(1) { flex: 1; min-width: 0; overflow: hidden;
                                text-overflow: ellipsis; white-space: nowrap; }
.td-n { font-size: 11px; }

/* ── CONTACTOS DE UNA EMPRESA ──────────────────────────────────────────────
   Era una `<table>` sin encabezado con el nombre, el correo y una «x». Se leía
   como una lista de datos sueltos y no había forma de corregir nada: solo dar
   de alta y borrar.

   Ahora cada contacto es una FILA con tres zonas —quién es, cómo se le
   contacta, qué se puede hacer— separadas por una línea fina. La línea es la
   norma del dueño para separar sin espacio de más, y aquí hace falta: son
   varias personas seguidas y sin ella se leen como un párrafo. */
.contactos { display: grid; }
.contacto { display: grid; grid-template-columns: 1fr auto auto; gap: 12px;
            align-items: center; padding: 9px 2px;
            border-top: 1px solid var(--line-soft, var(--line)); }
.contacto:first-child { border-top: 0; }
.contacto:hover { background: var(--color-surface-hover, transparent); }
/* El que se está editando se marca: con el formulario abajo, sin esto hay que
   recordar a cuál se le dio clic. */
.contacto.editando { background: var(--color-surface-subtle, var(--bg-soft));
                     box-shadow: inset 2px 0 0 var(--blue); }
.contacto-quien { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
                  min-width: 0; }
.contacto-quien .muted { font-size: 12px; }
.contacto-datos { display: grid; gap: 2px; font-size: 12px; text-align: right;
                  min-width: 0; }
.contacto-datos a { color: var(--blue-ink, var(--blue)); text-decoration: none;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.contacto-datos a:hover { text-decoration: underline; }
.contacto-acciones { display: flex; gap: 2px; }
/* Las acciones aparecen al pasar el ratón, pero NO se esconden del todo: en
   táctil no hay hover, y un botón que solo existe con ratón no existe. */
.contacto-acciones .x { opacity: .45; }
.contacto:hover .contacto-acciones .x,
.contacto-acciones .x:focus-visible { opacity: 1; }

.contacto-form { margin-top: 12px; padding-top: 12px;
                 border-top: 1px solid var(--line); }

/* ── LO QUE UNA COMPAÑÍA PRESTA POR OMISIÓN ────────────────────────────────
   Etiqueta a la izquierda y valor a la derecha, con línea fina entre renglones.
   No es una tabla: son pares sueltos que se comprueban de un vistazo, y una
   tabla les pondría un encabezado que no dice nada. */
.dflt { display: grid; }
.dflt-reng { display: grid; grid-template-columns: 150px 1fr; gap: 12px;
             align-items: baseline; padding: 7px 0; font-size: 13px;
             border-top: 1px solid var(--line-soft, var(--line)); }
.dflt-reng:first-child { border-top: 0; }
.dflt-reng .cot-et { margin: 0; }

/* La tarjeta de una cuenta bancaria. */
.cuenta.editando { box-shadow: inset 2px 0 0 var(--blue); }
.cuenta-dato { display: grid; grid-template-columns: 90px 1fr; gap: 8px;
               align-items: baseline; font-size: 12.5px; padding: 2px 0; }
.cuenta-dato .cot-et { margin: 0; }
.cuenta-dato .x { padding: 0 4px; opacity: .4; }
.cuenta-dato:hover .x { opacity: 1; }

/* ─── Barra de «hay versión nueva» ─────────────────────────────────────────
   Solo se ve cuando hay captura viva que impide recargar en automático.
   Fija abajo y no arriba: arriba taparía el encabezado del wizard, que es
   justo donde está trabajando quien la ve. */
.barra-actualizacion {
  position: fixed; left: 50%; bottom: 14px; transform: translateX(-50%);
  z-index: 300; display: flex; align-items: center; gap: 12px;
  background: var(--panel, #1d2428); color: var(--ink, #e8edef);
  border: 1px solid var(--linea, #3a444a); border-radius: 10px;
  padding: 10px 14px; font-size: 13px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .35);
}


/* ── El aviso de error de Blazor ─────────────────────────────────────────────
 *
 * ESTABA VISIBLE SIEMPRE. Su regla de ocultarlo vivía en el `app.css` de la
 * plantilla de Blazor, que aquí se sustituyó por el CSS del ERP —el mismo
 * `styles.css` del React, sin tocarle una línea—, y con él se fue la regla.
 * Resultado: un «Ocurrió un error inesperado» permanente al pie de cada
 * pantalla, sin que hubiera ningún error.
 *
 * Es el precio de reusar el diseño ajeno, y se paga una vez: lo que la
 * plantilla daba por hecho hay que traerlo a mano. Se queda aquí y no en un
 * archivo aparte para que el siguiente lo encuentre junto a lo demás.
 */
#blazor-error-ui {
  display: none;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 1000;
  padding: .6rem 1.25rem;
  background: var(--danger-bg, #fee2e2);
  color: var(--danger-fg, #7f1d1d);
  box-shadow: 0 -1px 2px rgba(0, 0, 0, .2);
}

#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: .75rem;
  top: .5rem;
}
