/* =====================================================================
   EKKLESIA · Design System
   Lenguaje: sobrio. Neutros + un acento, y el acento es una sola escala de
   azul medianoche derivada del azul Renacer: el menú lateral, el botón lleno
   y las marcas salen de la misma familia. El color solo aparece cuando
   comunica ESTADO; una cifra nunca se pinta por ser cifra.
   Tipografía: Schibsted Grotesk (interfaz) y JetBrains Mono (datos).

   Todo vive en TOKENS. Cambiar la piel de la aplicación es cambiar el
   bloque :root, no repintar pantallas. Ninguna pantalla debe escribir un
   color, un radio o una sombra a mano.

   Orden del archivo:
     1 · Tokens
     2 · Base
     3 · Componentes (cabecera, menú, tarjetas, tablas, botones, formularios)
     4 · Bandeja del día («Hoy»): tarjeta de tarea y opciones
     5 · Ficha en panel lateral
     6 · Capas, modales y responsivo
     7 · Normalización de utilidades Tailwind heredadas
   ===================================================================== */

/* ---------------------------- 1 · TOKENS ---------------------------- */
:root{
  /* Una sola escala de azul medianoche para TODA la aplicación, de la más
     profunda a la más clara. El menú, el botón lleno y las marcas salen de
     acá, así que se leen como la misma familia y no como dos azules:
       900 #071129  menú lateral
       800 #0e2a63  acción y marcas  (el acento)
       700 #173a80  hover de la acción
       100 #eef1f8  tinte del acento (opción elegida)
     `--renacer` queda como el azul institucional literal, para donde haga
     falta la marca exacta; la interfaz usa la escala.

     --acc      = el acento (texto, marcas, borde y fondo del botón lleno)
     --acc-ink  = la tinta que va ENCIMA del acento
     --acc-sf   = tinte suave del acento (opción elegida, fondo de ícono)
     --acc-bd   = borde del acento sin llegar a fondo (tarjeta abierta)
     --acc-nav  = la marca sobre el chrome del menú */
  --renacer:#003399; --renacer-dark:#002266; --renacer-hover:#173a80;
  /* --renacer-sf/--renacer-bd: mismo criterio que --acc-sf/--acc-bd (lavado
     muy claro para el fondo, tono medio para el filete), derivados del
     #003399 de arriba — no un color nuevo. Faltaban porque hasta ahora
     --renacer solo se usaba como texto/borde sólido (`.ek-app`, `.btn-primary`
     al hover), nunca como superficie de botón con tinte. */
  --renacer-sf:#e7ecfb; --renacer-bd:#aec3ee;
  --acc:#0e2a63; --acc-ink:#ffffff; --acc-sf:#eef1f8; --acc-bd:#c6cee0;
  --acc-nav:#7fa6ff;
  --dan-bd:#fecdd3; --dan-sf:#fff1f3;
  --warn-bd:#fde3c2; --warn-sf:#fff8ee;

  /* Superficies y tinta */
  --bg:#f5f6f8;        /* fondo de la aplicación */
  --sf:#ffffff;        /* superficie de tarjetas */
  --sf2:#fafafb;       /* campos, cabeceras de tabla */
  --sf3:#f2f3f6;       /* hover, pistas de barra */
  --ln:#e4e7ec;        /* borde de tarjeta y campo */
  --ln2:#edeff3;       /* separador de tabla */
  --ink:#14161b;       /* tinta principal */
  --ink2:#3d424d;      /* tinta de párrafo */
  --mut:#767c88;       /* texto secundario */
  --fnt:#9ca1ab;       /* texto terciario */

  /* Estados. Son semánticos: no se personalizan por campus ni se usan
     para decorar. Si algo lleva estos colores, algo está pasando. */
  --ok:#067a55; --warn:#b45309; --danger:#c11b45; --purple:#6d28d9;

  /* Los estados como SUPERFICIE, no sólo como tinta. `--ok`, `--warn` y
     `--danger` de arriba son tinta: con eso un aviso sólo puede ser un punto
     de color, nunca una caja. `--dan-sf`/`--dan-bd` ya existían por el modal
     de borrar; esto completa la familia para los otros dos.
     Siguen siendo SEMÁNTICOS: una caja ámbar dice que algo pasa, no decora. */
  --ok-sf:#e9f7f1;   --ok-bd:#b7e2d1;
  --warn-sf:#fdf5e7; --warn-bd:#f0d9a8;

  /* Los siete tonos del GRUPO OBJETIVO. Son los mismos de EK_AV_TONOS en
     includes/ui.php, que hasta ahora sólo vivían en PHP: por eso el avatar
     era lo único que podía usarlos. Acá abajo cualquier cosa que hable del
     grupo objetivo —un chip, el borde de una fila— puede tomar el MISMO
     color, sin una segunda tabla que se desincronice de aquélla.
     ⚠️ Si cambias uno, cambia el de EK_AV_TONOS: son un solo juego. */
  --gob-jm-sf:hsl(332 74% 94%); --gob-jm-ink:hsl(332 54% 40%);
  --gob-am-sf:hsl(344 40% 91%); --gob-am-ink:hsl(344 46% 31%);
  --gob-jh-sf:hsl(196 72% 92%); --gob-jh-ink:hsl(196 66% 29%);
  --gob-ah-sf:hsl(219 44% 91%); --gob-ah-ink:hsl(219 48% 31%);
  --gob-mt-sf:hsl(265 52% 94%); --gob-mt-ink:hsl(265 44% 40%);
  --gob-tn-sf:hsl(158 46% 90%); --gob-tn-ink:hsl(158 52% 26%);
  --gob-nn-sf:hsl(18 58% 92%);  --gob-nn-ink:hsl(18 54% 34%);

  /* Sombra TEÑIDA con el acento, para lo que se eleva de verdad: la acción
     llena y la tarjeta que encabeza una pantalla. Es la misma sombra de
     siempre, en la familia del azul en vez de negro puro —el negro puro es
     lo que la hace ver barata—. No reemplaza a `--sh`: esa sigue siendo la
     de todas las tarjetas, y si TODO se eleva no se eleva nada. */
  --sh-acc:0 1px 2px rgba(14,42,99,.10), 0 6px 16px -6px rgba(14,42,99,.28);

  /* Los mismos cuatro estados, SOBRE FONDO OSCURO. Los de arriba están
     calibrados contra superficie clara: #067a55 sobre el medianoche del
     menú (#071129) es prácticamente invisible, así que un punto de estado
     en la cabecera del riel no se leería. Misma familia, subida en
     luminosidad hasta que contrasta. No son colores nuevos ni un segundo
     juego semántico: son estos mismos, en el chrome oscuro.
     El precedente es --acc-nav, que existe por exactamente este motivo. */
  --ok-nav:#34d399; --warn-nav:#fbbf24; --dan-nav:#fb7185;

  /* WhatsApp. Única excepción a la regla del acento único: el botón que abre
     un chat va en el verde de WhatsApp porque así se reconoce sin leerlo. No
     uses estos tokens para nada que no abra WhatsApp. */
  --wa:#25d366; --wa-hover:#1da851; --wa-ink:#0b2e1c;
  --wa-sf:rgba(37,211,102,.10); --wa-bd:rgba(37,211,102,.45);

  /* Mismo trato que WhatsApp arriba, para el botón que abre un video de
     YouTube: la marca se reconoce por su rojo sin tener que leer el
     ícono. Tampoco es un color de estado — no uses esto para nada que no
     abra un video. */
  --yt:#ff0000; --yt-hover:#cc0000;
  --yt-sf:rgba(255,0,0,.10); --yt-bd:rgba(255,0,0,.45);

  /* Chrome del menú lateral: azul medianoche, el navy de marca bajado casi a
     tinta. Cambiar el menú entero es cambiar estos seis tokens y nada más
     (ver `docs/menu_azul.html` para las variantes que se compararon).
     Sobre este azul profundo el velo blanco SÍ se lee, así que el activo se
     marca con velo + barra de acento celeste. Si el menú pasara a un azul
     saturado (#002266 o el degradado de marca), el velo dejaría de leerse:
     ahí hay que invertir —pastilla blanca con tinta azul— poniendo
     `--nav-act-bg:#fff`, `--nav-act-ink:#002266` y el atributo
     `data-invertido` en los ítems activos del layout. */
  --nav:#071129; --nav-ink:rgba(255,255,255,.64); --nav-on:#ffffff;
  --nav-ln:rgba(255,255,255,.09); --nav-grp:rgba(255,255,255,.38);
  --nav-hov:rgba(255,255,255,.07);
  --nav-act-bg:rgba(255,255,255,.09); --nav-act-ink:#ffffff;
  /* Guía del árbol del submenú: más presente que --nav-ln (que es para
     separar bloques) pero por debajo del texto, para que ordene sin gritar. */
  --nav-gui:rgba(255,255,255,.17);

  /* Tipografía */
  --sans:'Schibsted Grotesk','Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;

  /* Radios y sombras: discretas. Una tarjeta es una superficie, no un globo. */
  --r-sm:7px; --r:10px; --r-lg:10px;
  --sh:0 1px 2px rgba(16,24,40,.06);
  --sh-card:0 1px 2px rgba(16,24,40,.06);
  --sh-lg:0 12px 34px -10px rgba(16,24,40,.28);
  --sh-open:0 4px 16px -6px rgba(14,42,99,.20);

  /* Movimiento */
  --ease:cubic-bezier(.22,1,.36,1);
  --t-fast:120ms; --t:200ms; --t-slow:280ms;

  /* Medidas del armazón */
  /* 272 y no 250: «Bodega y Donaciones» llegaba justo al borde y el submenú
     indentado quedaba estrecho. Son 22px que al contenido no le hacen falta. */
  /* 272 y no 250: «Bodega y Donaciones» llegaba justo al borde y el submenú
     indentado quedaba estrecho. Son 22px que al contenido no le hacen falta.

     ⚠️ --top-h manda a la vez sobre la barra superior Y sobre la barra de
     marca del menú, y eso es a propósito: sus filetes inferiores forman UNA
     línea horizontal continua a lo ancho de la pantalla. Si se le da más
     aire al logo subiendo solo la del menú, esa línea se parte y se nota. */
  --side-w:272px; --top-h:82px; --pad:22px; --gap:14px;
  /* Alto de la barra de estado inferior. Hermano de --top-h y por el mismo
     motivo: el armazón lo reserva en UN solo lugar. 30px es lo que una línea
     de 11px necesita para respirar sin pedir una franja. */
  --bot-h:38px;
  /* Barra de navegación inferior de la superficie MÓVIL (§9.2). Hermana de
     --top-h/--bot-h por el mismo motivo: el armazón la reserva en un solo
     lugar y ninguna pantalla se acuerda de dejarle espacio a mano. */
  --nav-bot-h:56px;
  /* Alto de la acción principal fija del teléfono. Es un token y no un
     padding suelto porque <main> tiene que restarlo de su espacio: si el
     botón crece y el token no, la última fila queda tapada. */
  --cta-h:46px;

  /* Escala de capas: cuanto más interrumpe algo, más arriba va. */
  --z-sticky:3; --z-nav:40; --z-rail:45; --z-drawer-o:88; --z-drawer:89;
  --z-modal:90; --z-toast:300;
  /* El FAB de ayuda es presencia PERMANENTE: compite con el chrome, no con
     un diálogo. Va sobre la barra superior y el menú (--z-nav) para que
     arrastrarlo arriba no lo esconda bajo la búsqueda, y BAJO el velo del
     riel (--z-rail): con un riel abierto la pantalla está atenuada a
     propósito, y un botón encendido flotando sobre ese velo invita a un
     clic que el velo se come. El popover que abre es siempre hijo de un
     clic que acaba de ocurrir y nunca puede quedar tapado por lo que lo
     disparó —incluido un modal—, así que va justo sobre --z-modal. */
  --z-fab:41; --z-pop:91;
  /* El velo de carga tapa TODO lo de esta pantalla —incluido un riel abierto—
     porque la pantalla se está yendo; y la barra de progreso va todavía más
     arriba, sobre el propio velo. Ver includes/loader.php. */
  --z-load:400; --z-load-bar:401;
  /* Velo del cierre por inactividad (includes/barra_estado.php). Va sobre todo
     lo de la pantalla salvo el velo de carga: cuando ese aparece la sesión ya
     se está yendo y esto sobra.
     El cronómetro NO necesita capa: desde que vive en la barra de estado está
     en el flujo, no encima de nada. */
  --z-sesion-velo:350;
}

/* ----------------------------- 2 · BASE ----------------------------- */
*{ font-family:var(--sans); }
body{ background:var(--bg); color:var(--ink2); margin:0; font-size:13.5px; line-height:1.5;
  -webkit-font-smoothing:antialiased; }
:focus-visible{ outline:2px solid var(--acc); outline-offset:2px; border-radius:3px; }
.ek-mono{ font-family:var(--mono); font-variant-numeric:tabular-nums; }

/* Rótulo pequeño. Antes era versalita negrita; ahora es texto tranquilo:
   un rótulo rotula, no compite con el dato. */
.micro{ font-size:12px; font-weight:500; color:var(--mut); letter-spacing:0; text-transform:none; }

/* Título de pantalla o de bloque. */
.h1r{ font-weight:600; color:var(--ink); text-transform:none; letter-spacing:-.02em; }

/* ------------------------- 3 · COMPONENTES ------------------------- */

/* Superficie. `glass-card` conserva el nombre porque lo usan todas las
   pantallas, pero ya no es vidrio: es una hoja con un borde de 1px. */
.glass-card{ background:var(--sf); border:1px solid var(--ln); border-radius:var(--r);
  box-shadow:var(--sh-card); }

/* Cinta de cifras: una sola superficie dividida por filetes, en vez de
   tarjetas sueltas que dejan huérfanas al reflujo. Asume 5 cifras. */
/* `--kpi-n` la escribe ek_kpis() con el número real de celdas: con el RBAC
   filtrando cifras por perfil una cinta puede traer 3 y no 5. El 5 es el
   respaldo por si alguien escribe la clase a mano. */
.ek-kpis{ display:grid; grid-template-columns:repeat(var(--kpi-n,5),1fr); background:var(--sf);
  border:1px solid var(--ln); border-radius:var(--r); box-shadow:var(--sh); overflow:hidden; }
.ek-kpi{ padding:14px 16px; min-width:0; }
/* El filete va entre celdas, nunca al final: con el RBAC filtrando cifras
   por perfil la cinta puede traer 3 o 4, no siempre 5. */
.ek-kpi:not(:last-child){ border-right:1px solid var(--ln); }
.ek-kpi-lb{ font-size:12px; color:var(--mut); }
.ek-kpi-fg{ font-family:var(--mono); font-size:27px; font-weight:500; letter-spacing:-.02em;
  color:var(--ink); line-height:1.2; margin:6px 0 3px; font-variant-numeric:tabular-nums; }
.ek-kpi-nt{ font-size:11.5px; color:var(--mut); display:flex; align-items:center; gap:6px; }
.ek-kpi-nt .pt{ width:6px; height:6px; border-radius:99px; background:currentColor; flex-shrink:0; }
.ek-kpi-nt.w{ color:var(--warn); }
.ek-kpi-nt.k{ color:var(--ok); }
.ek-kpi-nt.d{ color:var(--danger); }

/* Cifra suelta (pantallas antiguas). La cifra va en tinta; el color de
   estado, si corresponde, va en la nota de abajo. */
.kpi-num{ font-family:var(--mono); font-variant-numeric:tabular-nums; color:var(--ink);
  font-weight:500; letter-spacing:-.02em; }
.kpi-ico{ width:36px; height:36px; border-radius:var(--r-sm); display:flex; align-items:center;
  justify-content:center; font-size:14px; background:var(--sf3); color:var(--ink2); }

/* Botones */
.btn, .btn-primary, .btn-secondary, .btn-accion{
  display:inline-flex; align-items:center; justify-content:center; gap:7px; height:34px;
  padding:0 14px; border-radius:var(--r-sm); border:1px solid transparent; font-size:12.5px;
  font-weight:600; text-transform:none; letter-spacing:0; cursor:pointer; white-space:nowrap;
  transition:background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); }
/* 5 · La sombra del botón lleno, teñida de azul. Es el único botón lleno de
   la pantalla, así que es lo único que tiene derecho a levantarse; con la
   sombra negra genérica se leía pegado al papel. */
.btn-primary{ background:var(--acc); color:var(--acc-ink); box-shadow:var(--sh-acc); }
.btn-primary:hover{ background:var(--renacer-hover); }
.btn-secondary, .btn-quiet{ background:var(--sf); border-color:var(--ln); color:var(--ink2); }
.btn-secondary:hover, .btn-quiet:hover{ border-color:var(--mut); color:var(--ink); }
/* Acción de fila: azul, pero NO llena. Es el único estilo de botón que va
   dentro de una tabla, y va siempre el mismo: antes convivían llenos y
   neutros para acciones equivalentes («Llamar y anotar» lleno, «Derivar»
   gris) y la fila no dice cuál pesa más. Lleno se reserva para el botón de
   la cabecera de la tarjeta, que es uno por pantalla: veinte botones llenos
   en una lista compiten entre sí y ninguno destaca. */
.btn-accion{ background:var(--sf); border-color:var(--acc-bd); color:var(--acc); }
.btn-accion:hover{ background:var(--acc-sf); border-color:var(--acc); }
/* Acción de fila RELEVANTE: la que la fila existe para ofrecer (derivar la
   visita, elevar la solicitud, entregar la caja). Una por fila, nunca dos.
   Se distingue por TINTE Y BORDE, no por relleno sólido.

   ⚠️ Esto era azul lleno y estaba mal a escala. La regla decía «una por
   fila», y se cumplía — pero una fila por solicitud son doce botones azules
   apilados, y el resultado es un muro que tapa la información: el ojo va a
   la columna de botones en vez de ir al estado y a la urgencia, que es lo
   que hay que leer. El relleno sólido queda reservado a UN botón por
   pantalla, el de la barra superior (.ek-bar-cta). */
.btn-accion.k{ background:var(--acc-sf); border-color:var(--acc); color:var(--acc); font-weight:600; }
.btn-accion.k:hover{ background:var(--acc-bd); border-color:var(--acc); }
/* Variante de MARCA (Solicitudes de ayuda, ago 2026): el botón que APRUEBA
   —la decisión, no un paso más de la cadena— usa el azul institucional
   (`--renacer`, #003399) en vez del acento de siempre (`--acc`, azul
   medianoche): son notoriamente distintos, así que «Aprobar Solicitud» se
   distingue de «Elevar a Gracia» sin inventar un color nuevo ni tocar la
   columna «Urgencia», que sigue siendo donde se lee la urgencia. Rojo quedó
   descartado a propósito: en este sistema ya significa peligro/rechazo, y
   el botón que aprueba una ayuda no puede leerse como el que la niega.
   Sigue siendo tinte y borde, nunca relleno sólido — ver la nota de arriba
   sobre `.btn-accion.k`, que rige igual acá. */
.btn-accion.renacer{ background:var(--renacer-sf); border-color:var(--renacer); color:var(--renacer); font-weight:600; }
.btn-accion.renacer:hover{ background:var(--renacer-bd); border-color:var(--renacer); }
.btn-danger{ background:var(--sf); border-color:var(--dan-bd); color:var(--danger); }
.btn-danger:hover{ background:var(--dan-sf); }

/* WhatsApp. Verde de WhatsApp, no el azul de marca: es el único botón que
   sale de la aplicación hacia otra, y se reconoce por el color antes que por
   el texto. `.btn-wa` es el lleno (ficha, cabecera); `.btn-accion.wa` es el
   discreto de fila, que sigue la misma regla que el resto de las filas. */
.btn-wa{ background:var(--wa); border-color:var(--wa); color:var(--wa-ink); box-shadow:var(--sh); }
.btn-wa:hover{ background:var(--wa-hover); border-color:var(--wa-hover); color:#fff; }
.btn-accion.wa{ background:var(--sf); border-color:var(--wa-bd); color:var(--wa-hover); }
.btn-accion.wa:hover{ background:var(--wa-sf); border-color:var(--wa); }
/* Mismo discreto de fila, para el botón que abre el video de una reunión.
   Deshabilitado (la reunión no tiene video) queda en gris, no en rojo
   apagado: `:disabled` de arriba sólo baja la opacidad, y un rojo al 45%
   sigue leyéndose como «hay algo acá». El :hover se cancela porque una
   fila sin video no reacciona al mouse. */
.btn-accion.yt{ background:var(--sf); border-color:var(--yt-bd); color:var(--yt-hover); }
.btn-accion.yt:hover:not(:disabled){ background:var(--yt-sf); border-color:var(--yt); }
.btn-accion.yt:disabled{ border-color:var(--ln); color:var(--mut); }

/* ---------------------------------------------------------------------
   MINIATURA DE YOUTUBE (`.ek-ytmin`) — el bloque de video de la ficha
   «Ver» de una reunión. Es un `<div>`, no un `<a>`: la prédica puede
   terminar incrustada (un `<iframe>` de YT.Player adentro, sin enlace
   envolvente) o, si YouTube bloquea ese video —los cultos de esta
   iglesia cantan alabanza con derechos y el dueño de esa música a veces
   bloquea el embed, ver la nota larga en
   modulos/reuniones/reuniones.php—, cae a miniatura + enlace, que es lo
   que este componente muestra por defecto mientras se decide una cosa u
   otra. Se parece a un reproductor a propósito —16:9 y botón de play
   rojo— porque es lo que la gente reconoce; el pie con la flecha de
   «se abre afuera» es lo que evita que la promesa sea falsa cuando
   termina en modo miniatura. --------------------------------------- */
.ek-ytmin{ display:block; border-radius:var(--r-sm);
  overflow:hidden; border:1px solid var(--ln); background:#000;
  transition:border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.ek-ytmin:hover{ border-color:var(--yt); box-shadow:0 0 0 3px var(--yt-sf); }
.ek-ytmin img{ display:block; transition:opacity var(--t-fast) var(--ease); }
.ek-ytmin:hover img{ opacity:.82; }
/* El botón de play, centrado sobre la miniatura. Crece un punto al pasar
   el mouse: es la única señal de que la tarjeta entera es pulsable. */
.ek-ytmin-play{ position:absolute; inset:0; display:flex; align-items:center;
  justify-content:center; font-size:58px; color:var(--yt);
  text-shadow:0 2px 14px rgba(0,0,0,.55); pointer-events:none;
  transition:transform var(--t-fast) var(--ease); }
.ek-ytmin:hover .ek-ytmin-play{ transform:scale(1.08); }
/* El pie dice ADÓNDE lleva. Un play sobre una miniatura promete
   reproducción acá mismo; esta línea es la que corrige esa expectativa
   antes del clic, en vez de después con un error. */
.ek-ytmin-pie{ display:flex; align-items:center; gap:7px; padding:9px 12px;
  background:var(--sf2); border-top:1px solid var(--ln);
  font-size:12.5px; font-weight:600; color:var(--ink); }
.ek-ytmin-pie i{ color:var(--mut); font-size:11px; }
@media (prefers-reduced-motion:reduce){
  .ek-ytmin:hover .ek-ytmin-play{ transform:none; }
}
.btn-text{ background:transparent; border:0; color:var(--acc); height:auto; padding:0 3px;
  text-decoration:none; }
.btn-text:hover{ text-decoration:underline; }
/* Un botón inhabilitado se ve inhabilitado. Antes cada pantalla lo resolvía
   con una utilidad suelta (`disabled:opacity-40`) y el que se olvidaba dejaba
   un botón que parece disponible y no hace nada. */
.btn:disabled, .btn-primary:disabled, .btn-secondary:disabled,
.btn-accion:disabled, .btn-danger:disabled{ opacity:.45; cursor:default; }
.btn-primary:disabled:hover{ background:var(--acc); }
.btn-sm{ height:30px; padding:0 11px; font-size:12px; }
.btn-lg{ height:46px; padding:0 18px; font-size:14.5px; border-radius:var(--r); }
.ek-icb{ width:34px; height:34px; border-radius:var(--r-sm); border:1px solid var(--ln);
  background:var(--sf2); color:var(--ink2); cursor:pointer; display:grid; place-items:center;
  font-size:12.5px; flex-shrink:0; }
.ek-icb:hover{ color:var(--ink); background:var(--sf3); }

/* Menú de usuario (cabecera): identidad, perfiles y salida.
   Los perfiles van en `.tag` neutros y el vigente en acento: acá el punto de
   color significa ESTADO, así que pintar cada perfil de un color distinto
   —como en Custody— rompería el lenguaje. La jerarquía la hace el acento. */
.ek-menu-wrap{ position:relative; }
.ek-menu{ position:absolute; right:0; top:calc(100% + 9px); width:280px; padding:6px;
  background:var(--sf); border:1px solid var(--ln); border-radius:var(--r);
  box-shadow:var(--sh-lg); z-index:var(--z-nav); display:none; }
.ek-menu.ek-open{ display:block; }
/* Los dos paneles nuevos de la barra —mis mensajes y los números
   desconocidos— llevan filas de dos líneas, no ítems de menú de una: 280px
   les dejan el texto en tres renglones. */
.ek-menu-ancho{ width:388px; }
/* Un mensaje ya leído se apaga; el que falta leer queda en tinta normal.
   Es la única diferencia entre los dos, y no hace falta más. */
.ek-msg-leido b{ font-weight:400; color:var(--ink2); }
.ek-msg-leido{ opacity:.72; }
/* Las filas de números desconocidos dentro del panel: sin el filete de
   borde a borde que llevan en un cuerpo ancho. Más aire que el original
   (9px/9px): con 340px de panel el teléfono partía en dos líneas contra
   la insignia «Abierta» y los dos botones quedaban pegados al texto. */
.ek-menu .wa-desc{ padding:12px 13px; gap:11px; }
.ek-menu .wa-desc-nm{ flex-wrap:wrap; gap:6px; row-gap:4px; }
.ek-menu .wa-desc-ac{ flex-direction:column; gap:7px; margin-top:2px; }
.ek-menu-id{ padding:11px 11px 13px; border-bottom:1px solid var(--ln2); margin-bottom:6px; }
.ek-menu-nm{ font-size:13.5px; font-weight:600; color:var(--ink); }
.ek-menu-cg{ font-size:12px; color:var(--mut); margin-top:1px; }
.ek-menu-lb{ font-size:11px; color:var(--fnt); margin:12px 0 6px; }
.ek-menu-pf{ display:flex; flex-wrap:wrap; gap:5px; }
a.tag{ text-decoration:none; }
.ek-menu-pf .tag{ cursor:pointer; }        /* los perfiles son elegibles */
.ek-menu-pf .tag:hover{ border-color:var(--acc-bd); color:var(--ink); }
.ek-menu-pf .tag.on{ background:var(--acc-sf); border-color:var(--acc-bd); color:var(--acc); }
.ek-menu-dt{ display:flex; align-items:flex-start; gap:9px; margin-top:12px; padding:8px 10px;
  background:var(--sf2); border:1px solid var(--ln); border-radius:var(--r-sm); }
.ek-menu-dt > i{ color:var(--fnt); font-size:11px; margin-top:3px; flex-shrink:0; }
.ek-menu-dt div{ min-width:0; }
.ek-menu-dt b, .ek-menu-dt span{ display:block; font-family:var(--mono); font-size:11px;
  font-weight:400; color:var(--mut); line-height:1.55; }
.ek-menu-dt span{ color:var(--fnt); }
/* ⚠️ `.ek-mi` es el MISMO ítem cuando no navega sino que abre un modal, o
   sea un <button>. Comparte la regla en vez de copiarla: un ítem que se
   ve distinto de sus hermanos se lee como otra cosa. Y necesita apagar la
   piel propia del botón (fondo, borde, tipografía, ancho), que un <a> no
   trae. No se reusó `.ek-out`, que además de ser sólo para <a> significa
   la opción ROJA —cerrar sesión—, no «un ítem cualquiera». */
.ek-menu a, .ek-menu .ek-mi{ display:flex; align-items:center; gap:10px; padding:8px 11px;
  border-radius:var(--r-sm); font-size:13px; color:var(--ink2); text-decoration:none; }
.ek-menu .ek-mi{ width:100%; background:none; border:0; font-family:inherit;
  text-align:left; cursor:pointer; }
.ek-menu a i, .ek-menu .ek-mi i{ width:15px; text-align:center; color:var(--fnt); font-size:12.5px; }
.ek-menu a:hover, .ek-menu .ek-mi:hover{ background:var(--sf3); color:var(--ink); }
.ek-menu-hr{ height:1px; background:var(--ln2); margin:5px 9px; }
.ek-menu a.ek-out, .ek-menu a.ek-out i{ color:var(--danger); }
.ek-menu a.ek-out:hover{ background:var(--dan-sf); }

/* Campos */
.inp, .ek-fld{ background:var(--sf2); border:1px solid var(--ln); border-radius:var(--r-sm);
  padding:.55rem .7rem; font-size:13px; font-weight:400; color:var(--ink); width:100%;
  outline:none; transition:border-color var(--t-fast) var(--ease); box-sizing:border-box; }
/* 4 · El foco, a color. Era sólo un borde un poco más oscuro: en un
   formulario de trece campos el foco es la única pista de dónde estás
   parado, y un gris apenas distinto no la da. El anillo va en el TINTE del
   acento, no en el acento: a 3px un azul pleno grita más que el campo. */
.inp:focus, .ek-fld:focus{ border-color:var(--acc); background:var(--sf);
  box-shadow:0 0 0 3px var(--acc-sf); }
.inp::placeholder{ color:var(--mut); }
.ek-lbl{ display:block; font-size:12px; color:var(--mut); margin-bottom:5px; }

/* Estado: punto + palabra. El punto es EXCLUSIVO del estado; un dato
   (el nombre de un GC, un alimento) va en `.tag`, sin punto. */
.chip{ display:inline-flex; align-items:center; gap:7px; font-size:12.5px; font-weight:500;
  text-transform:none; letter-spacing:0; padding:3px 10px; border-radius:99px;
  background:var(--sf); border:1px solid var(--ln); color:var(--ink2); }
.chip::before{ content:''; width:7px; height:7px; border-radius:99px; background:var(--dot,var(--mut));
  flex-shrink:0; }
.chip.ek-ok{ --dot:var(--ok); }
.chip.ek-warn{ --dot:var(--warn); }
.chip.ek-danger{ --dot:var(--danger); }
.chip.ek-acc{ --dot:var(--acc); }
.chip i{ display:none; }              /* el punto ya dice de qué se trata */

/* Tira de chips como FILTRO (Solicitudes de ayuda): el mismo `.chip`, pero
   enlace clicable y con conteo. El activo NO se distingue solo por el
   punto de color -- borde, fondo y peso, el mismo lenguaje de `.ek-rango.on`
   -- para que se note aunque no se distingan esos tonos. */
.ek-chips{ display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin:0 0 13px; }
.ek-chips .chip{ text-decoration:none; cursor:pointer; }
.ek-chips .chip:hover{ background:var(--sf2); }
.ek-chips .chip b{ font-family:var(--mono); font-weight:600; margin-left:1px; }
.ek-chips .chip.on{ border-color:var(--ink2); background:var(--sf2); color:var(--ink); font-weight:600; }
/* white-space:nowrap por lo mismo que .ek-est más abajo: con altura fija
   (23px) y sin esto, dos palabras en una columna angosta parten el texto en
   dos líneas y la segunda se sale del pill redondeado — se ve descuadrado,
   no envuelto. */
.tag{ display:inline-flex; align-items:center; height:23px; padding:0 9px; border-radius:99px;
  border:1px solid var(--ln); background:var(--sf2); font-size:12px; color:var(--ink2);
  white-space:nowrap; }
/* Celda ACOTADA: el contenido se trunca con «…» en vez de estirar la columna.
   Para datos de texto libre que pueden venir largos —el nombre de una
   cobertura son hasta 45 caracteres, «(Adultos) Pres Alexis Morales & Cherly
   Peters»— y que a ancho libre se comen el espacio de las columnas que sí hay
   que leer. Pon el nombre completo en el `title` de la celda: truncar sin
   dejar forma de leerlo entero es esconder el dato.

   ⚠️ `.tag` es inline-flex y ahí `text-overflow` no hace nada; por eso acá
   pasa a inline-block, con `line-height` a mano para recuperar el centrado
   vertical que le daba flex. */
.ek-cel-corta{ max-width:250px; }
.ek-cel-corta .tag{ display:inline-block; max-width:100%; overflow:hidden;
  text-overflow:ellipsis; line-height:21px; }
.ek-cel-corta .ek-sb{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Un estado se lee de un tirón: partir «En revisión» en dos líneas dentro de
   una celda lo convierte en dos palabras sueltas. */
.ek-est{ display:inline-flex; align-items:center; gap:7px; font-size:12.5px; font-weight:500;
  color:var(--ink2); white-space:nowrap; }
.ek-est .pt{ width:7px; height:7px; border-radius:99px; background:var(--mut); flex-shrink:0; }
.ek-est.w .pt{ background:var(--warn); }
.ek-est.a .pt{ background:var(--acc); }
.ek-est.k .pt{ background:var(--ok); }
.ek-est.d .pt{ background:var(--danger); }

/* Tablas */
table.dt{ width:100%; border-collapse:collapse; }
table.dt thead th{ background:var(--sf); color:var(--mut); text-transform:none; font-size:12px;
  font-weight:500; letter-spacing:0; padding:0 13px 9px; text-align:left;
  border-bottom:1px solid var(--ln); white-space:nowrap; }
table.dt tbody td{ padding:0 13px; height:46px; font-size:13.5px; border-bottom:1px solid var(--ln2); }
table.dt tbody tr:hover{ background:var(--sf2); }
table.dt tbody tr:last-child td{ border-bottom:0; }
/* Fila que abre algo al pincharla (EK.filaClic()): el realce de hover
   (sección 8, table.dt tbody tr:hover más abajo) ya es de TODA fila; lo que
   falta es el cursor —sin él nadie sospecha que la fila responde— y el
   anillo de foco para quien navega con teclado. Genérica —cualquier tabla
   con `data-id` en la fila la hereda— porque ya son varias pantallas
   distintas las que la usan. */
table.dt tbody tr[data-id]{ cursor:pointer; }
table.dt tbody tr[data-id]:focus-visible{ outline:2px solid var(--acc); outline-offset:-2px; }
/* Fila en CERO: no es «poco», es «nada», y la acción que exige es distinta
   —conseguirlo antes de armar, no completar lo que falta—. Una barra vacía se
   lee igual que una barra casi vacía, así que el nivel se dice también con
   superficie y con la palabra («Sin stock» en el .ek-est de la fila): el color
   nunca queda como única señal. El filete a la izquierda es lo que la hace
   encontrable barriendo la tabla con la vista. */
table.dt tbody tr.ek-fila-cero{ background:var(--dan-sf); box-shadow:inset 3px 0 0 var(--danger); }
table.dt tbody tr.ek-fila-cero:hover{ background:var(--dan-sf); }
table.dt tbody tr.ek-fila-cero td{ border-bottom-color:var(--dan-bd); }
/* Columna de cifras: nunca se parte. «hace 15 días» en dos líneas ocupa el
   doble de alto y se lee peor que estrechando otra columna. */
table.dt td.num, table.dt th.num{ font-family:var(--mono); font-variant-numeric:tabular-nums;
  text-align:right; white-space:nowrap; }
.ek-nm{ display:block; font-size:13.5px; font-weight:600; color:var(--ink); }
.ek-sb{ display:block; font-family:var(--mono); font-size:11.5px; color:var(--mut); }

/* Aviso: una barra de estado a la izquierda, un motivo y una salida. */
.ek-note{ display:flex; align-items:flex-start; gap:14px; padding:14px 16px; background:var(--sf);
  border:1px solid var(--ln); border-left:3px solid var(--warn); border-radius:var(--r);
  box-shadow:var(--sh); }
.ek-note.d{ border-left-color:var(--danger); }
.ek-note-tt{ font-size:13.5px; font-weight:600; color:var(--ink); }
.ek-note-tx{ font-size:12.5px; color:var(--mut); margin-top:2px; }

/* Segmentos y pestañas */
.ek-segs{ display:inline-flex; gap:2px; padding:3px; background:var(--sf2);
  border:1px solid var(--ln); border-radius:var(--r-sm); }
.ek-segs button{ border:0; background:transparent; cursor:pointer; padding:5px 12px;
  border-radius:5px; font-size:12px; font-weight:500; color:var(--mut); }
.ek-segs button:hover{ color:var(--ink); }
.ek-segs button.on{ background:var(--sf); color:var(--ink); font-weight:600; box-shadow:var(--sh); }

/* ---- Pestañas de NAVEGACIÓN (`.ek-tabs`) ----------------------------
   Distintas de `.ek-segs` y no intercambiables: aquel es un control de 2 o
   3 opciones cortas y equivalentes (un período, una vista) que caben
   siempre; esto es una tira de N destinos con nombre largo —las clases de
   un curso, con su fecha— que puede no caber y que son ENLACES, no
   botones: cada una es una URL a la que se puede volver.

   Por eso llevan `overflow-x:auto` en vez de envolver en varias líneas: una
   tira de pestañas en tres filas deja de leerse como una tira y empuja la
   tabla fuera de la pantalla. La activa se marca con la barra de acento
   abajo, el mismo gesto que el menú lateral usa para «acá estás». */
.ek-tabs{ display:flex; gap:2px; overflow-x:auto; border-bottom:1px solid var(--ln);
  margin-bottom:calc(var(--gap) * -1 + 2px); }
.ek-tabs::-webkit-scrollbar{ height:6px; }
.ek-tabs::-webkit-scrollbar-thumb{ background:var(--ln); border-radius:3px; }
.ek-tab{ display:inline-flex; align-items:center; gap:7px; padding:9px 14px; flex-shrink:0;
  font-size:12.5px; font-weight:500; color:var(--mut); text-decoration:none; white-space:nowrap;
  border-bottom:2px solid transparent; margin-bottom:-1px;
  transition:color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); }
.ek-tab:hover{ color:var(--ink); }
.ek-tab.on{ color:var(--acc); font-weight:600; border-bottom-color:var(--acc); }
.ek-tab i{ font-size:11px; }
/* Nota al costado del nombre («por dictar»): matiza sin competir. */
.ek-tab-nt{ font-size:10.5px; color:var(--fnt); font-weight:400; }

/* ---- Segmentado VIVO (`.ek-seg-ind`) --------------------------------
   La variante de arriba marca lo elegido con una sombra de 1px sobre gris
   casi blanco: la pista no se hunde, la pastilla no se eleva y el cambio no
   se ve moverse. Acá el relieve es real y el indicador es UN elemento que se
   desplaza —con `background` en cada botón el cambio es un corte, no un
   gesto—.

   Es OPT-IN a propósito: `.ek-segs` a secas lo usan los selectores de período
   de los dos paneles y de «Administrar grupos», que no tienen indicador ni
   nivel. Cambiar la clase base los rompería a los tres.

   El indicador lo INYECTA `EK.segs()` (assets/ekklesia-ui.js), que además lo
   mide: el ancho de cada botón depende del texto —«Sí» y «No» no miden lo
   mismo— y eso no se puede escribir en CSS. Basta con poner la clase. */
.ek-segs.ek-seg-ind{ position:relative; gap:0; padding:4px; border-radius:11px;
  background:var(--sf3); border-color:transparent;
  box-shadow:inset 0 1px 2px rgba(20,22,27,.07); }
.ek-segs.ek-seg-ind button{ position:relative; z-index:1; padding:7px 16px; font-size:13px;
  border-radius:8px; display:inline-flex; align-items:center; gap:7px;
  transition:color var(--t-fast) var(--ease); }
/* El fondo del botón elegido se va: ahora lo pone el indicador. */
.ek-segs.ek-seg-ind button.on{ background:transparent; box-shadow:none; }
.ek-segs.ek-seg-ind button i{ font-size:11px; opacity:.5;
  transition:opacity var(--t-fast) var(--ease); }
.ek-segs.ek-seg-ind button.on i{ opacity:1; }
.ek-segs.ek-seg-ind .ek-seg-pt{ position:absolute; z-index:0; top:4px; bottom:4px;
  border-radius:8px; background:var(--sf); box-shadow:var(--sh);
  transition:left .2s cubic-bezier(.4,0,.2,1), width .2s cubic-bezier(.4,0,.2,1),
             background .2s ease, box-shadow .2s ease; }

/* El NIVEL de la respuesta elegida. No es decoración: un «no autoriza que la
   contactemos» significa que a esa persona no se la va a poder contactar
   nunca, y eso es un estado. Un «no oró por primera vez» no es una alarma y
   por eso queda en el acento, neutro.

   El nivel lo declara el MARCADO (`data-niv-si` / `data-niv-no` en el
   segmentado, con las mismas letras que `.ek-est`: k · a · w · d) y el JS
   sólo copia el que corresponde a la opción elegida. El CSS no lo adivina:
   el mismo componente tiene que servir para una pregunta neutra.

   ⚠️ El color NUNCA es la única señal: estos botones llevan ícono siempre.
   Quien no distinga estos tonos ve el ✓ y el ⃠ igual. */
.ek-segs.ek-seg-ind[data-niv="k"] button.on{ color:var(--ok); }
.ek-segs.ek-seg-ind[data-niv="k"] .ek-seg-pt{ background:var(--ok-sf);
  box-shadow:inset 0 0 0 1px var(--ok-bd); }
.ek-segs.ek-seg-ind[data-niv="w"] button.on{ color:var(--warn); }
.ek-segs.ek-seg-ind[data-niv="w"] .ek-seg-pt{ background:var(--warn-sf);
  box-shadow:inset 0 0 0 1px var(--warn-bd); }
.ek-segs.ek-seg-ind[data-niv="d"] button.on{ color:var(--danger); }
.ek-segs.ek-seg-ind[data-niv="d"] .ek-seg-pt{ background:var(--dan-sf);
  box-shadow:inset 0 0 0 1px var(--dan-bd); }
.ek-segs.ek-seg-ind[data-niv="a"] button.on{ color:var(--acc); }
.ek-segs.ek-seg-ind[data-niv="a"] .ek-seg-pt{ background:var(--acc-sf);
  box-shadow:inset 0 0 0 1px var(--acc-bd); }

/* Marca en la cabecera del menú.
   La institución va primero y el sistema queda debajo: quien entra trabaja
   para la iglesia, no para Ekklesia. El emblema NO lleva placa blanca —ya
   trae su propio disco— y el wordmark se pinta blanco por filtro cuando el
   archivo disponible es el arte negro sobre fondo transparente. */
/* El logo va centrado en la barra: es lo único que hay ahí, así que
   alinearlo a la izquierda dejaba un vacío raro a la derecha. */
.ek-brand{ display:flex; align-items:center; justify-content:center; gap:11px;
  height:var(--top-h); padding:0 16px;
  border-bottom:1px solid var(--nav-ln); flex-shrink:0; text-decoration:none; }
/* El logo es lo único que hay en la barra de marca, así que se lleva casi
   todo el alto disponible (--top-h menos un respiro arriba y abajo). Antes
   eran 25px porque «Ekklesia» le robaba una línea debajo. */
.ek-brand-wm{ display:block; height:42px; width:auto; max-width:100%; object-fit:contain;
  object-position:center; }
.ek-brand-mk{ width:30px; height:30px; object-fit:contain; flex-shrink:0; }
/* Pinta de blanco el arte de un logo y conserva su transparencia. Sirve para
   los dos logos institucionales porque los dos son de un solo color sobre
   fondo transparente: en el emblema el azul se vuelve blanco y la R, que es
   un calado, deja ver el azul del menú. Ojo: si algún día el archivo trae
   varios colores o texto blanco horneado, este filtro lo aplasta todo. */
.ek-inv{ filter:brightness(0) invert(1); }
/* ---------------------------------------------------------------------
   Marca de agua del área de trabajo.

   El mismo gesto del login —el emblema enorme, saliéndose por una esquina—
   pero acá el fondo es claro, así que se usa el emblema A COLOR con muy
   poca opacidad: sobre `--bg` el azul se apaga hasta un gris azulado. La
   versión blanca no serviría, se perdería en el claro.

   Va como BACKGROUND, no como pseudo-elemento. Un ::before con
   `position:fixed` es una caja posicionada y, por orden de pintado, queda
   ENCIMA de las tarjetas —que son estáticas—, así que el emblema se veía
   atravesando los gráficos. Un fondo pinta siempre detrás del contenido y
   no toca la escala ek-z-*.

   Y va en ek-shell, NO en <main>. La marca tiene que quedarse quieta
   mientras el contenido scrollea, y la forma directa de conseguirlo
   —`background-attachment:fixed` sobre <main>— obliga al navegador a
   repintar el fondo en cada cuadro de scroll. ek-shell mide justo la
   ventana (h-screen) y no scrollea, así que el fondo ya está quieto por
   construcción y sale gratis. <main> queda transparente para dejarlo ver.

   La opacidad viene horneada en el alfa del PNG (logo-renacer-agua.png):
   `opacity` no se puede aplicar a una capa de fondo por separado.
   ------------------------------------------------------------------- */
.ek-shell{
  background-color:var(--bg);
  background-image:url("/assets/img/logo-renacer-agua.png");
  background-repeat:no-repeat;
  background-position:right -150px bottom -190px;
  background-size:560px 560px;
}
.ek-main{ background:transparent; }
/* En pantallas chicas el contenido ocupa todo el ancho y la marca solo
   estorbaría detrás del texto. */
@media (max-width:900px){ .ek-shell{ background-image:none; } }

.ek-brand-tx{ min-width:0; }
.ek-brand-nm{ font-size:13.5px; font-weight:600; color:var(--nav-on); line-height:1.15;
  letter-spacing:-.01em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ek-brand-sb{ font-size:10.5px; color:var(--nav-grp); line-height:1.2; margin-top:2px; }

/* Menú lateral */
/* line-height explícito: un <button> no hereda el del body, y sin esto los
   ítems del menú quedan de dos alturas distintas (enlace 36px, botón 32px). */
/* box-sizing explícito: los destinos simples son <a> y las categorías son
   <button>. El navegador le da border-box al botón pero content-box al
   enlace, así que con width:100% los enlaces sumaban los 22px del padding
   y se salían 2px del menú. Los ítems tienen que medir todos lo mismo. */
.ek-nav{ display:flex; align-items:center; gap:11px; width:100%; padding:11px 12px; border:0;
  margin-bottom:3px;
  box-sizing:border-box;
  background:transparent; border-radius:var(--r-sm); color:var(--nav-ink); font-size:13px;
  line-height:1.5; font-weight:500; cursor:pointer; text-align:left; text-decoration:none;
  transition:background var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.ek-nav i{ width:15px; font-size:12.5px; text-align:center; opacity:.7; }
/* RBAC: lo que el perfil no alcanza se oculta con [hidden]. Hace falta
   declararlo porque `display:flex`/`block` de las reglas de arriba le gana al
   display:none que el navegador aplica al atributo. */
.ek-nav[hidden], .ek-sub[hidden], .ek-sub a[hidden]{ display:none; }
.ek-nav:hover{ color:var(--nav-on); background:var(--nav-hov); }
.ek-nav.ek-active{ color:var(--nav-act-ink); background:var(--nav-act-bg);
  box-shadow:inset 2px 0 var(--acc-nav); }
.ek-nav.ek-active i{ opacity:1; }
.ek-nav.ek-active::before{ content:none; }
/* Cuando el activo se resuelve invirtiendo (pastilla clara), la barra de
   acento sobra: la pastilla ya es la marca más fuerte de la lista. Y el
   contador tiene que invertirse con ella, o queda blanco sobre blanco. */
.ek-nav.ek-active[data-invertido]{ box-shadow:none; }
.ek-nav.ek-active[data-invertido] .ek-ct{ background:rgba(0,0,0,.09); color:var(--nav-act-ink); }
.ek-nav .ek-ct{ margin-left:auto; font-family:var(--mono); font-size:11px; color:var(--nav-on);
  background:rgba(255,255,255,.14); border-radius:99px; padding:1px 7px; }
.ek-nav .ek-ch{ margin-left:auto; font-size:10px; opacity:.5; transition:transform 180ms var(--ease); }
.ek-nav[aria-expanded="true"] .ek-ch{ transform:rotate(90deg); opacity:.9; }
/* Rama ABIERTA ≠ pantalla ACTIVA, y son dos cosas distintas que el menú
   tiene que poder decir a la vez: `.ek-active` es «acá estás», esto es
   «esta es la rama que estás mirando». Antes abrir una categoría solo
   giraba un chevron de 10px al 50 % de opacidad, así que el menú no
   acusaba recibo del clic y el resalte se quedaba en la pantalla anterior.
   No se reusó `.ek-active` a propósito: pintarlo al abrir haría que el
   menú mienta sobre dónde estás parado. */
.ek-nav[aria-expanded="true"]{ color:var(--nav-on); }
.ek-nav[aria-expanded="true"]:not(.ek-active){ background:var(--nav-hov); }
.ek-nav[aria-expanded="true"] i{ opacity:1; }
/* El anillo de foco del menú va en el azul CLARO. El global usa `--acc`
   (#0e2a63), que sobre el medianoche del menú (#071129) es casi el mismo
   color: quien navega con teclado no veía dónde estaba parado. Es el mismo
   ajuste que ya hacían las pantallas de acceso sobre su fondo azul. */
.ek-side :focus-visible{ outline-color:var(--acc-nav); }
/* Las pantallas de una categoría cuelgan de una guía, como un árbol: una
   línea vertical y un conector por ítem. Es un conector y NO un punto a
   propósito — en este sistema el punto de color significa estado, y un
   punto acá lo diluiría. */
.ek-sub{ display:none; padding:5px 0 12px; position:relative; }
.ek-sub.ek-open{ display:block; }
.ek-sub-gp{ font-size:10px; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:var(--nav-grp); padding:8px 11px 4px 32px; }
.ek-sub a{ display:block; position:relative; padding:8px 11px 8px 32px; margin-bottom:2px; border-radius:var(--r-sm);
  color:var(--nav-ink); text-decoration:none; font-size:12.5px; }
.ek-sub a::before{ content:''; position:absolute; left:20px; top:calc(50% - 1px); width:7px;
  height:2px; border-radius:1px; background:var(--nav-gui);
  transition:background var(--t-fast) var(--ease), width var(--t-fast) var(--ease); }
/* ⚠️ La guía vertical se dibuja POR ÍTEM, no como una sola línea del bloque.
   Con una línea única (`.ek-sub::before`, de top:6px a bottom:14px) había que
   adivinar la altura del último ítem para saber dónde cortarla, y no se
   adivinó: sobraban 17px —media fila— colgando bajo el último conector, una
   línea suelta que no conectaba con nada. Por ítem, el último corta en su
   propio centro y da igual cuántas líneas ocupe su nombre.
   El -2px de arriba y abajo cubre el `margin-bottom` del vecino: sin eso la
   guía sale punteada, con un corte por fila. */
.ek-sub a::after{ content:''; position:absolute; left:19px; width:1px;
  top:-2px; bottom:-2px; background:var(--nav-gui); }
.ek-sub a:last-child::after{ bottom:auto; height:calc(50% + 2px); }
.ek-sub a:hover{ color:var(--nav-on); background:var(--nav-hov); }
.ek-sub a:hover::before{ background:var(--nav-ink); }
.ek-sub a.ek-active{ color:var(--nav-act-ink); background:var(--nav-act-bg); font-weight:500; }
.ek-sub a.ek-active::before{ background:var(--acc-nav); width:9px; left:18px; }

/* Bloque de contenido: superficie + cabecera con título, bajada y acciones.
   Es la unidad de toda pantalla de Registros, así que vive en el sistema y
   no se rearma a mano en cada página. */
.ek-card{ background:var(--sf); border:1px solid var(--ln); border-radius:var(--r);
  box-shadow:var(--sh); padding:17px; }
/* ⚠️ `.ek-kpis` entra en la misma cadena: sin ella, una cinta de cifras
   que sigue a una tarjeta —o que una tarjeta sigue a ella— queda pegada
   borde con borde, cero espacio, y se lee como una sola ficha rota en
   vez de tres superficies distintas. `.ek-hero` no entra acá porque ya
   trae su propio margin-bottom (sección 8g) y sumar los dos duplicaría
   el espacio. */
.ek-card + .ek-card, .ek-card + .ek-kpis, .ek-kpis + .ek-card{ margin-top:var(--gap); }
/* …salvo dentro de una rejilla, donde la separación ya la pone el `gap`:
   si no, la segunda tarjeta de la fila baja y la fila queda descuadrada. */
.ek-g2 > .ek-card, .ek-g3 > .ek-card{ margin-top:0; }
.ek-card-hd{ display:flex; align-items:center; justify-content:space-between; gap:12px;
  flex-wrap:wrap; margin-bottom:13px; }
/* 1 · Tarjeta con ACENTO (`.ek-card-acc`). La tarjeta que encabeza una
   pantalla —el formulario de registrar, no las doce de una lista— deja de
   ser un rectángulo blanco: la cabecera se lava con el tinte del acento y un
   riel de 3px la sostiene por el costado. Así tiene un arriba.

   Es OPT-IN porque el sistema tiene tarjetas por todas partes: si todas se
   lavan, ninguna destaca y el efecto se vuelve papel tapiz. Va en UNA por
   pantalla, la misma que lleva el único botón lleno.

   `overflow:hidden` es lo que recorta el riel contra el radio de la esquina;
   sin eso el filete sobresale por arriba y por abajo. Y el lavado se pone en
   el pseudo-elemento y no en `background` de la cabecera porque `.ek-card-hd`
   ya tiene `margin-bottom` y el degradado tiene que llegar hasta el borde de
   la tarjeta, no hasta donde termina el texto. */
.ek-card.ek-card-acc{ position:relative; overflow:hidden; box-shadow:var(--sh-acc); }
.ek-card.ek-card-acc::before{ content:''; position:absolute; z-index:0; inset:0 0 auto 0;
  height:96px; background:linear-gradient(180deg,var(--acc-sf),transparent);
  pointer-events:none; }
/* Sin riel de acento al costado. Lo tuvo un rato y se descartó: en esta
   pantalla la tarjeta ocupa casi todo el ancho, así que el filete no marca
   una tarjeta entre otras —no hay otras— y se lee como el borde de un aviso,
   que es lo que significa en `.ek-note`. El lavado de la cabecera ya le da
   un arriba, que era todo lo que hacía falta. */
/* El contenido tiene que quedar ENCIMA del lavado: los pseudo-elementos son
   cajas posicionadas y por orden de pintado van sobre los hijos sin z-index.
   Es la misma trampa que ya se pagó con la marca de agua de `.ek-shell`. */
.ek-card.ek-card-acc > *{ position:relative; z-index:2; }
.ek-card-tt{ font-size:14.5px; font-weight:600; color:var(--ink); letter-spacing:-.01em; }
.ek-card-sb{ font-size:12.5px; color:var(--mut); margin-top:1px; }
.ek-filters{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.ek-fld-in{ display:flex; align-items:center; gap:7px; height:34px; padding:0 9px 0 11px;
  background:var(--sf2); border:1px solid var(--ln); border-radius:var(--r-sm); min-width:0; }
.ek-fld-in i{ color:var(--mut); font-size:11.5px; }
.ek-fld-in select, .ek-fld-in input{ border:0; background:transparent; font-size:12.5px;
  color:var(--ink); min-width:0; outline:none; }
.ek-fld-in input::placeholder{ color:var(--mut); }
.ek-fld-in .ek-sep{ color:var(--fnt); font-size:11px; }
/* El icono nativo del input[type=date] es azul de sistema y pesa más que el
   dato: se apaga al tono de los demás iconos del filtro. */
.ek-fld-in input[type=date]::-webkit-calendar-picker-indicator{
  opacity:.45; cursor:pointer; padding:0; margin:0; }
.ek-fld-in input[type=date]:hover::-webkit-calendar-picker-indicator{ opacity:.8; }

/* Atajos de período. Es un filtro, no un estado: sin punto de color, y el
   activo se marca con el acento en tinta, no con relleno. */
.ek-rangos{ display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin:-4px 0 13px; }
.ek-rango{ font-size:11.5px; font-weight:500; color:var(--mut); text-decoration:none;
  padding:4px 10px; border-radius:99px; border:1px solid transparent; }
.ek-rango:hover{ background:var(--sf2); color:var(--ink); }
.ek-rango.on{ color:var(--acc); border-color:var(--ln2); background:var(--sf2); font-weight:600; }
/* Aclara qué se está mirando cuando el período lo puso el sistema y no la
   persona: si no, «123 de 3.786» se lee como que faltan datos. */
.ek-rango-nt{ font-size:11px; color:var(--fnt); margin-left:2px; }
.ek-rango-sep{ color:var(--ln2); font-size:11px; }

/* Situación en una celda: dos líneas y corta. La historia completa se abre en
   el riel; la tabla está para comparar filas, no para leer párrafos. */
.ek-sit{ display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden; font-size:12.5px; color:var(--mut); max-width:34ch; }
/* Un tiempo de espera que ya se pasó del corte. Solo el dato, no la fila. */
.ek-tarde{ color:var(--warn); font-weight:600; }
/* Acción que niega: se distingue sin gritar, y nunca es el botón lleno. */
.btn-accion.ek-no{ color:var(--danger); }
.btn-accion.ek-no:hover{ background:var(--dan-sf); border-color:var(--dan-bd); }

/* Paginador. Números, no solo «anterior/siguiente»: con miles de filas hay
   cientos de páginas y avanzar de a una no es navegar. Ver ek_paginas(). */
.ek-pag{ display:flex; align-items:center; justify-content:center; gap:4px;
  flex-wrap:wrap; padding-top:10px; }
.ek-pag-b{ display:inline-flex; align-items:center; justify-content:center;
  min-width:30px; height:30px; padding:0 8px; border-radius:var(--r-sm);
  font-size:12.5px; font-weight:500; color:var(--mut); text-decoration:none;
  border:1px solid transparent; }
.ek-pag-b:hover{ background:var(--sf2); color:var(--ink); }
.ek-pag-b.on{ background:var(--acc); border-color:var(--acc); color:#fff; font-weight:600; }
.ek-pag-b.off{ color:var(--ln2); pointer-events:none; }
.ek-pag-x{ color:var(--fnt); font-size:12px; padding:0 2px; }
/* «1–15 de 36», el rótulo que escribe EK.paginar() a la izquierda de la barra.
   Va en mono porque son cifras, y absorbe el espacio sobrante (`margin-right:
   auto`) para que los botones queden centrados igual que en la paginación del
   servidor: si no, la barra entera se corría a la derecha y las dos versiones
   se veían distintas. En pantalla angosta se calla —la barra de botones es lo
   que hay que poder tocar—. */
.ek-pag-inf{ font-family:var(--mono); font-size:11.5px; color:var(--mut);
  margin-right:auto; padding-left:2px; }
@media (max-width:640px){ .ek-pag-inf{ display:none; } }
/* Los botones que pinta el JS son <button>, no <a>: hay que neutralizar el
   estilo de formulario que el navegador les da. */
button.ek-pag-b{ font:inherit; font-size:12.5px; cursor:pointer; }
button.ek-pag-b.off{ cursor:default; }

.ek-tbl-ft{ display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding-top:12px; font-size:12px; color:var(--mut); }
/* =====================================================================
   MAPA (Leaflet) · la piel de la casa sobre teselas ajenas
   =====================================================================
   Las teselas de OpenStreetMap vienen a todo color —parques verdes, calles
   amarillas, agua celeste— y en esta aplicación EL COLOR SIGNIFICA ESTADO:
   el verde de un parque compite con el verde de «entregada» a dos
   centímetros, y el pin deja de saltar. El mapa es el CONTEXTO; lo que hay
   que leer son los puntos.

   Se filtran las teselas en vez de cambiar de proveedor: un servicio de
   teselas grises es una dependencia externa más que aprobar, y el filtro es
   una línea de CSS que no agrega ninguna. `sepia + hue-rotate` las lleva al
   azul de la casa; el `brightness` compensa que gris puro sobre fondo claro
   se ve sucio.

   ⚠️ El filtro va en `.leaflet-tile-pane` y NO en el contenedor: sobre el
   contenedor se llevaría por delante los pines, los popups y los clusters
   —que son justamente lo que tiene que conservar su color de estado— y el
   mapa entero quedaría de un solo tono, que es lo contrario de lo buscado.
   ===================================================================== */
.ek-mapa{ border:1px solid var(--ln); border-radius:var(--r); overflow:hidden;
  background:var(--sf2); }
.ek-mapa .leaflet-tile-pane{
  filter:grayscale(1) sepia(.55) hue-rotate(176deg) saturate(.75) brightness(1.04) contrast(.94);
}
.ek-mapa .leaflet-container{ font-family:var(--sans); background:var(--sf2); }
.ek-mapa .leaflet-popup-content-wrapper{ border-radius:14px; border:1px solid var(--ln);
  box-shadow:var(--sh-lg); font-family:var(--sans); }
.ek-mapa .leaflet-popup-content{ margin:12px 14px; font-size:12px; line-height:1.5; }
/* Los controles de zoom heredan el botón de la casa en vez del gris de la
   librería. */
.ek-mapa .leaflet-bar a{ color:var(--ink); border-color:var(--ln); }
.ek-mapa .leaflet-bar a:hover{ background:var(--sf2); }
/* La atribución tiene que seguir siendo legible: es una obligación de
   licencia de OpenStreetMap, no un adorno que se pueda apagar. */
.ek-mapa .leaflet-control-attribution{ background:rgba(255,255,255,.82);
  font-size:10px; color:var(--mut); }
/* El agrupador de pines viene en verde / amarillo / naranja —los tres
   colores que acá significan «bien», «se está enfriando» y «urgente»—. Un
   grupo de puntos no es un estado: es una CANTIDAD, así que va en la escala
   del acento y el número adentro en blanco. */
.ek-mapa .marker-cluster{ background:var(--acc-sf); }
.ek-mapa .marker-cluster div{ background:var(--acc); color:#fff;
  font-family:var(--sans); font-weight:800; font-size:12px; }
.ek-mapa .marker-cluster-medium div{ background:#12408f; }
.ek-mapa .marker-cluster-large div{ background:#071129; }
.ek-pin{ font-size:26px; filter:drop-shadow(0 2px 3px rgba(15,23,42,.35)); }

/* Miniatura de una evidencia de entrega, antes de subirla. La foto ES la
   prueba de que la caja llegó, y el momento de ver que salió movida es
   mientras la persona sigue en la puerta — con el nombre del archivo
   («IMG_4821.jpg») eso no se puede saber. Cuadrada y recortada para que ocho
   fotos de proporciones distintas formen una grilla pareja. */
.ek-evi{ position:relative; width:74px; height:74px; border-radius:var(--r-sm);
  overflow:hidden; border:1px solid var(--ln); background:var(--sf2); flex:0 0 auto; }
.ek-evi img, .ek-evi video{ width:100%; height:100%; object-fit:cover; display:block; }
.ek-evi-x{ position:absolute; top:3px; right:3px; width:20px; height:20px; padding:0;
  display:flex; align-items:center; justify-content:center; cursor:pointer;
  border:0; border-radius:999px; background:rgba(7,17,41,.72); color:#fff; font-size:10px; }
.ek-evi-x:hover{ background:var(--danger); }
/* El peso va sobre un velo: sobre una foto clara, texto blanco sin fondo
   desaparece. */
.ek-evi-kb{ position:absolute; left:0; right:0; bottom:0; padding:2px 4px;
  background:linear-gradient(to top, rgba(7,17,41,.78), transparent);
  color:#fff; font-family:var(--mono); font-size:9.5px; text-align:center; }

/* Filtro que gobierna un PANEL entero (no una tabla): va sobre la cinta de
   cifras, alineado a la DERECHA y con su rótulo escrito.
   Antes era un <select> suelto pegado al margen izquierdo, justo encima de la
   primera celda de la cinta: a esa distancia y con ese ancho se leía como una
   tarjeta de KPI rota, no como un control —«totalmente desalineado sobre los
   KPI»—. A la derecha no compite con ninguna celda, y el rótulo evita que un
   desplegable solo tenga que adivinarse. La nota explicativa se queda a la
   izquierda, donde sí se lee de corrido. */
.ek-panel-fil{ display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  justify-content:flex-end; margin:var(--gap) 0 10px; }
.ek-panel-fil .ek-panel-fil-nt{ margin-right:auto; text-align:left; max-width:52ch; }
@media (max-width:720px){
  .ek-panel-fil{ justify-content:stretch; }
  .ek-panel-fil .ek-panel-fil-nt{ margin-right:0; }
}
/* La barra de filtros como TARJETA. Cuando los filtros gobiernan la pantalla
   ENTERA —una tabla y además sus estadísticas— no pueden vivir en el
   `.ek-card-hd` de una de las dos: ahí dirían que filtran sólo esa. Y sueltos
   sobre el fondo (como `.ek-panel-fil`, que es para un panel sin tabla) tres o
   cuatro controles con sus rótulos se leen como piezas desparramadas.

   ⚠️ `position:relative` + `z-index` NO son decorativos, y sin ellos hay un
   bug real: `.ek-anim > *` (sección 8) le aplica `animation:…both` a CADA hijo
   de `<main>`, y eso convierte a cada uno en su PROPIO contexto de
   apilamiento. Entre contextos hermanos con `z-index:auto` gana el ORDEN DEL
   DOM, así que el desplegable de un `.ek-combo` —z-index 89, pero encerrado en
   el contexto de su tarjeta— quedaba DEBAJO de la cinta de cifras que va justo
   después. Medido con `elementFromPoint` en la zona de solape: ganaba
   `.ek-kpi`, no el desplegable. Es la misma trampa de orden de pintado ya
   pagada con `.ek-shell` y `.ek-card-acc`.
   El 5 es de la escala baja (`--z-sticky:3`) a propósito: esto tiene que
   ganarle a sus hermanos del contenido, nunca al menú, a un riel ni a un
   modal. */
.ek-filtros{ position:relative; z-index:5; padding:12px 14px; }
/* Los controles miden un poco más que en una cabecera de tabla: acá son el
   control principal de la pantalla, no un accesorio de una tarjeta. */
.ek-filtros .ek-fld-in{ height:36px; }
/* El nombre de una cobertura o de un GC es largo («(Adultos) Alejandro
   Gonzalez & Sandra Villalobos»): sin tope, un solo control se lleva toda la
   fila y los otros dos se apilan debajo. Con tope, los tres entran en una
   línea y el nombre se corta con puntos suspensivos, que es lo que hace el
   `<select>` nativo de todos modos. */
.ek-filtros .ek-fld-in > select{ max-width:230px; text-overflow:ellipsis; }
/* El desplegable del combo se ancla al `.ek-fld-in`, que es angosto: se le
   deja crecer hasta donde el nombre completo del GC se lee. */
.ek-filtros .ek-combo-lst{ min-width:320px; }
@media (max-width:720px){
  .ek-filtros .ek-fld-in > select{ max-width:none; }
  .ek-filtros .ek-fld-in{ flex:1 1 100%; }
  .ek-filtros .ek-combo-lst{ min-width:0; }
}

.ek-g2{ display:grid; grid-template-columns:1fr 1fr; gap:var(--gap); align-items:start; }
.ek-g3{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--gap); align-items:start; }
/* Contenedor de gráfico. ECharts pinta sobre un div con ALTO propio, y si la
   tarjeta es item de un grid necesita min-width:0: sin eso el canvas fija el
   ancho mínimo de la columna y el panel se desborda en móvil. */
.ek-chart{ height:250px; min-width:0; padding:6px 14px 14px; box-sizing:border-box; }

.ek-g4{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:var(--gap); align-items:start; }
@media (max-width:1024px){ .ek-g4{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
.ek-g2 > *, .ek-g3 > *{ min-width:0; }
/* minmax(0,1fr) y no 1fr: un <select> con una opción larga tiene ancho mínimo
   propio y con 1fr desborda la columna en vez de encogerse. */
.ek-form{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px 16px; }
.ek-form.ek-form-3{ grid-template-columns:repeat(3,minmax(0,1fr)); }
.ek-form .ek-ancho{ grid-column:1 / -1; }

/* Preguntas de Sí/No dentro de un formulario.
   ⚠️ NO son un campo más, y por eso salen de la grilla de campos. Una
   pregunta trae una etiqueta larga —«¿Ha hecho la oración de fe / salvación
   o ha participado en otra iglesia cristiana?»— y un control de ancho fijo;
   metida en un tercio de fila junto a un <input>, la etiqueta se parte en
   cuatro líneas y la celda crece de 62 a 103px de alto.
   `.ek-pregs` toma la fila entera y arma su propia pista: columnas de hasta
   300px, tantas como quepan. Con una sola pregunta ya no quedan dos tercios
   vacíos, y con dos dejan de competir por 174px. */
.ek-form .ek-pregs{ grid-column:1 / -1; display:grid; gap:14px 16px;
  grid-template-columns:repeat(auto-fit, minmax(240px, 300px)); }
/* ⚠️ EL CONTROL SE ANCLA ABAJO (`margin-top:auto`), y es lo que de verdad
   arregla la desalineación: en «Qué autoriza» conviven una etiqueta de
   cuatro líneas y otra de una, así que sin esto los dos segmentados de la
   misma fila quedaban a distinta altura y la sección se veía torcida. */
.ek-preg{ display:flex; flex-direction:column; }
/* ⚠️ `align-self:start` además del `margin-top:auto`. `.ek-segs` es
   `inline-flex` —o sea, del ancho de sus dos botones— pero un hijo de una
   columna flex se estira por defecto: sin esto el Sí/No se abría a los
   300px de la celda y quedaban dos botones enormes con aire adentro.
   Devuelve al componente el ancho que ya tenía definido, en vez de
   redefinirlo acá. */
.ek-preg .ek-segs{ margin-top:auto; align-self:start; }
/* Subtítulo de grupo dentro de un formulario largo. Nueve campos seguidos se
   leen como un trámite; en bloques con nombre se leen como una conversación. */
.ek-form-sec{ grid-column:1 / -1; display:flex; align-items:center; gap:10px;
  font-size:12px; font-weight:600; color:var(--ink); margin-top:8px; }
.ek-form-sec::after{ content:''; flex:1; height:1px; background:var(--ln2); }
.ek-form-sec:first-child{ margin-top:0; }
/* La misma cabecera, pero plegable (`<details>` nativo). En escritorio va
   con `open`, así que se ve igual que antes; en el teléfono nace cerrada y
   deja «Personas» y «Guardar» en la primera pantalla.
   ⚠️ `list-style:none` MÁS `::-webkit-details-marker`: el triángulo por
   defecto se quita distinto en Safari/iOS que en el resto, y ahí es donde
   más se va a usar esto. Sin las dos reglas queda un triángulo negro
   pegado al ícono de la sección. */
.ek-form-det > summary{ cursor:pointer; list-style:none; }
.ek-form-det > summary::-webkit-details-marker{ display:none; }
/* El chevron se dibuja al final, DESPUÉS del filete que ya pone
   `.ek-form-sec::after` — por eso es un segundo pseudo-elemento y no se
   reemplaza aquél: el filete separa, el chevron dice que se abre. */
.ek-form-det > summary::before{ content:'\f078'; font-family:'Font Awesome 6 Free';
  font-weight:900; font-size:10px; color:var(--mut); order:3; margin-left:8px;
  transition:transform var(--t-fast) var(--ease); }
.ek-form-det[open] > summary::before{ transform:rotate(180deg); }
/* El foco tiene que verse: es un control de teclado, y sin esto el
   `list-style:none` se lleva también la única señal de dónde estás. */
.ek-form-det > summary:focus-visible{ outline:2px solid var(--acc); outline-offset:3px;
  border-radius:var(--r-sm); }
@media (prefers-reduced-motion:reduce){
  .ek-form-det > summary::before{ transition:none; }
}
/* 2 · El ícono de la sección, en pastilla. Describe el bloque y va en tinta
   apagada sobre el tinte del acento — igual que el ícono de la cinta de
   cifras—, así ordena sin competir con el nombre.

   ⚠️ TODAS del mismo color, a propósito. Un color por sección (azul «quién
   es», verde «cómo llegó», violeta «qué autoriza») se ve bien en esta
   pantalla y rompe la aplicación: el verde de sección competiría con el
   verde de estado en la fila de al lado. Es exactamente la razón por la que
   se descartó la dirección «Expresivo». */
.ek-form-sec .ek-ic{ display:grid; place-items:center; width:24px; height:24px; flex:none;
  border-radius:7px; background:var(--acc-sf); color:var(--acc); font-size:11px; }

/* 3 · El resultado calculado de la sección, en su propio divisor. Va con
   `font-weight:400` porque el divisor entero es 600 y un chip en negrita
   compite con el nombre de la sección, que es lo que ordena el formulario.

   El chip toma el TONO DEL GRUPO OBJETIVO: el mismo con el que esa persona
   va a aparecer en «Visitas por derivar». No es un color nuevo ni decorativo
   —es el de `EK_AV_TONOS`, bajado a tokens— y dice lo mismo que dirá el
   avatar después, así que la pantalla ya se parece a su consecuencia.
   Sin `data-g` queda en el gris de `.tag`: preferible no decir nada a pintar
   una categoría adivinada, igual que el avatar sin objetivo. */
.ek-form-sec .ek-obj{ font-weight:400; flex:0 0 auto; }
.ek-form-sec .ek-obj[hidden]{ display:none; }
.ek-obj[data-g="JOVENES_MUJERES"]{ background:var(--gob-jm-sf); color:var(--gob-jm-ink); border-color:transparent; }
.ek-obj[data-g="ADULTAS_MUJERES"]{ background:var(--gob-am-sf); color:var(--gob-am-ink); border-color:transparent; }
.ek-obj[data-g="JOVENES_HOMBRES"]{ background:var(--gob-jh-sf); color:var(--gob-jh-ink); border-color:transparent; }
.ek-obj[data-g="ADULTOS_HOMBRES"]{ background:var(--gob-ah-sf); color:var(--gob-ah-ink); border-color:transparent; }
.ek-obj[data-g="MATRIMONIOS"]{ background:var(--gob-mt-sf); color:var(--gob-mt-ink); border-color:transparent; }
.ek-obj[data-g="TEENS"]{ background:var(--gob-tn-sf); color:var(--gob-tn-ink); border-color:transparent; }
.ek-obj[data-g="NINOS"]{ background:var(--gob-nn-sf); color:var(--gob-nn-ink); border-color:transparent; }
@media (max-width:900px){ .ek-form, .ek-form.ek-form-3{ grid-template-columns:1fr; } }
.ek-hint{ font-size:12px; color:var(--mut); margin-top:5px; }

/* ---- Combo: el <select> que se puede escribir (EK.combos) -------------
   Para listas largas —346 comunas, 133 grupos—, donde un <select> obliga a
   rodar la lista con la vista. Se aplica SÓLO a esas: en «Sexo» o «Estado
   civil» el <select> nativo ya busca por letra y en el teléfono abre el
   selector del sistema, que es mejor que cualquier cosa que uno escriba.

   El <select> original NO se reemplaza por un hidden: se esconde y sigue
   siendo el que viaja en el formulario, así que ningún endpoint cambia. */
.ek-combo-wrap{ position:relative; }
/* `position:absolute` y no `display:none`: un <select> oculto con `display`
   queda fuera del layout, pero además Safari deja de reportarlo en
   `form.elements` en algunos casos. Así sigue siendo un control de verdad,
   sólo que invisible. */
.ek-combo-src{ position:absolute; width:1px; height:1px; opacity:0;
  pointer-events:none; }
.ek-combo-lst{ display:none; position:absolute; z-index:var(--z-drawer);
  top:calc(100% + 4px); left:0; right:0; max-height:262px; overflow-y:auto;
  padding:5px; background:var(--sf); border:1px solid var(--ln);
  border-radius:var(--r-sm); box-shadow:var(--sh-lg); }
.ek-combo-wrap.ek-open .ek-combo-lst{ display:block; }
.ek-combo-it{ display:block; width:100%; text-align:left; border:0; cursor:pointer;
  background:transparent; padding:7px 9px; border-radius:6px;
  font-size:13px; color:var(--ink2); font-family:inherit; }
.ek-combo-it:hover, .ek-combo-it.on{ background:var(--acc-sf); color:var(--acc); }
.ek-combo-no{ padding:9px; font-size:12.5px; color:var(--mut); }
.ek-vacio{ text-align:center; padding:34px 18px; color:var(--mut); }
.ek-vacio i{ font-size:20px; color:var(--fnt); }
/* El título del estado vacío se escribe como <b> a mano, pero ek_vacio()
   de includes/ui.php emite un <div>. Sin la segunda mitad de este selector
   el título sale sin realce en toda pantalla que use el helper. */
.ek-vacio b,
.ek-vacio > div{ display:block; font-size:14px; font-weight:600; color:var(--ink); margin:10px 0 3px; }

/* Registrar visita: formulario + la jornada al costado. Asimétrico a
   propósito — el formulario es el trabajo y la columna lateral lo acompaña;
   dos columnas iguales harían pensar que pesan lo mismo. */
/* ⚠️ `stretch` y no `start`: la columna de «Últimas que registraste» tiene que
   ocupar el ALTO del formulario, que es lo que la hace consultable de un
   vistazo. Con `start` la tarjeta medía lo que midiera su contenido y dejaba
   media columna vacía al lado de un formulario de trece campos. */
/* ⚠️ La segunda pista NO es `1fr`: es una banda de ancho acotado. Con dos
   fracciones, todo el ancho que gana la ventana se reparte entre las dos y
   la lista de nombres terminaba en 580px —una columna enorme para «nombre ·
   comuna · edad»— mientras el formulario, que es el trabajo, se quedaba
   corto. Con `minmax` la lista crece hasta donde se lee cómoda y el sobrante
   se lo lleva entero el formulario. */
.visita-g{ display:grid; grid-template-columns:minmax(0,1fr) minmax(260px,360px);
  gap:var(--gap); align-items:stretch; }
.visita-side{ display:flex; flex-direction:column; gap:var(--gap); }
/* La tarjeta llena la columna y la LISTA rueda por dentro, en vez de estirar
   la página. `min-height:0` en los tres niveles no es de más: sin él, un hijo
   flex nunca se encoge por debajo de su contenido y el `overflow` no llega a
   activarse nunca — el clásico de las columnas que scrollean. */
.visita-g > .visita-side{ min-height:0; }
.visita-g > .visita-side > .ek-card{ display:flex; flex-direction:column;
  flex:1; min-height:0; }
.visita-g > .visita-side > .ek-card > .vs-bd{ flex:1; min-height:0; overflow-y:auto; }
.vs-bd{ padding:0 16px 16px; }
.vs-big{ display:flex; align-items:baseline; gap:9px; }
/* La cifra de la jornada va en el ACENTO, no en tinta. Es la única excepción
   a «una cifra nunca se pinta por ser cifra», y se sostiene porque el acento
   NO es un color de estado: no dice si doce visitas son muchas o pocas, dice
   que ése es el dato de esta tarjeta. Un verde o un ámbar acá sí mentirían,
   porque mañana el mismo número puede querer decir lo contrario. */
.vs-big b{ font-family:var(--mono); font-size:30px; font-weight:500; color:var(--acc);
  letter-spacing:-.02em; }
.vs-big span{ font-size:12.5px; color:var(--mut); }
.vs-split{ display:flex; flex-wrap:wrap; gap:22px; margin-top:12px; padding-top:12px;
  border-top:1px solid var(--ln2); }
.vs-split b{ display:block; font-family:var(--mono); font-size:16px; font-weight:500; color:var(--ink); }
.vs-split span{ font-size:11.5px; color:var(--mut); }

/* Desglose por culto, como PROPORCIÓN. Eran tres cifras sueltas una al lado
   de otra: para saber si el de las 10 trajo el doble que el de las 12 había
   que dividir de cabeza. La barra lo dice sin leer los números.
   El porcentaje es sobre el total del día, y ese total es la suma de estos
   mismos grupos (getJornadaCaptador agrupa TODO, incluido «sin culto
   indicado»), así que las barras siempre suman el ancho completo.
   La barra va en la escala del acento y no en un color por culto: el culto
   es un dato, no un estado, y cinco colores acá competirían con el ámbar de
   «sin teléfono» que vive tres centímetros más abajo. */
.vs-cul{ display:flex; flex-direction:column; gap:9px; margin-top:14px; padding-top:13px;
  border-top:1px solid var(--ln2); }
.vs-cul-r{ display:grid; grid-template-columns:minmax(0,1fr) auto; gap:3px 10px; align-items:center; }
.vs-cul-r span{ font-size:12px; color:var(--ink2); min-width:0; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.vs-cul-r b{ font-family:var(--mono); font-size:12.5px; font-weight:500; color:var(--ink); }
.vs-cul-b{ grid-column:1 / -1; height:5px; border-radius:99px; background:var(--sf3); overflow:hidden; }
.vs-cul-b i{ display:block; height:100%; border-radius:99px; background:var(--acc); }

/* El aviso de «sin teléfono», como CAJA y no como punto. Es lo único de esta
   pantalla que pide una acción AHORA —mientras la persona sigue en la sala—,
   y un punto de 6px al lado de una línea de texto no pesa lo que pesa el
   hecho: sin teléfono, a esa persona no la contacta nadie nunca.
   El ícono va además del color, como en los segmentados. */
.vs-avi{ display:flex; gap:11px; align-items:flex-start; margin-top:14px; padding:11px 13px;
  background:var(--warn-sf); border:1px solid var(--warn-bd); border-radius:var(--r-sm); }
.vs-avi > i{ color:var(--warn); font-size:13px; margin-top:2px; flex:none; }
.vs-avi b{ display:block; font-size:12.5px; font-weight:600; color:var(--warn); }
.vs-avi span{ font-size:12px; color:var(--ink2); line-height:1.45; }
.vs-row{ display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:10px 0; border-bottom:1px solid var(--ln2); }
.vs-row:last-child{ border-bottom:0; }
.vs-qr{ height:104px; display:grid; place-items:center; background:var(--sf2);
  border:1px dashed var(--ln); border-radius:var(--r-sm); color:var(--fnt); font-size:34px; }
@media (max-width:1100px){ .visita-g{ grid-template-columns:1fr; } }

/* Mi perfil: lo que se HACE a la izquierda —contacto, clave, segundo factor—
   y quién eres al costado. La identidad no se edita acá (la define el sistema
   de inscripciones), así que es referencia y no trabajo: misma asimetría que
   «Registrar visita», por la misma razón y con la misma proporción.
   Antes era una columna de 672px con las tres tarjetas apiladas: un tercio de
   la pantalla vacío a la derecha y el segundo factor a dos scrolls de ahí. */
.perfil-g{ display:grid; grid-template-columns:minmax(0,1.9fr) minmax(0,1fr);
  gap:var(--gap); align-items:start; }
.perfil-main, .perfil-side{ display:flex; flex-direction:column; gap:var(--gap); }
/* La ficha de identidad va en UNA columna. `.ek-ficha` reparte con
   auto-fit/minmax(160px), que en la lateral mete dos: «(Adultos) Marcelo Ziem
   & Andrea Aedo» cae en cuatro líneas contra el borde. */
.perfil-side .ek-ficha{ grid-template-columns:1fr; gap:11px; }
.perfil-id{ display:flex; align-items:center; gap:11px; padding-bottom:13px;
  margin-bottom:14px; border-bottom:1px solid var(--ln2); }
.perfil-id .ek-nm{ font-size:15px; letter-spacing:-.01em; }
/* `.ek-est` va `white-space:nowrap` porque nació para una celda de tabla, y
   acá la frase es una oración entera («Segundo factor activo. Códigos de
   respaldo sin usar: 10/10»): en el teléfono empujaba la tarjeta 25px fuera
   de la pantalla y dejaba scroll horizontal en todo el sistema. */
.perfil-main .ek-est{ white-space:normal; }
/* ⚠️ `minmax(0,1fr)` y no `1fr` a secas: una pista `1fr` tiene mínimo
   `auto`, así que en el teléfono la columna crecía hasta el min-content de
   la tarjeta más ancha —391px en una pantalla de 375— y aparecía scroll
   horizontal en toda la pantalla. */
@media (max-width:1100px){ .perfil-g{ grid-template-columns:minmax(0,1fr); } }

/* Recorrido: etapas con su fuga. La etapa se aclara a medida que avanza. */
.ek-trip{ display:flex; flex-direction:column; gap:10px; }
.ek-trip-r{ display:grid; grid-template-columns:110px 1fr 124px; align-items:center; gap:12px; }
.ek-trip-lb{ font-size:12.5px; font-weight:500; color:var(--ink); }
.ek-trip-vl{ font-family:var(--mono); font-size:12.5px; color:var(--ink); text-align:right;
  font-variant-numeric:tabular-nums; }
.ek-trip-vl em{ font-style:normal; color:var(--mut); font-size:11.5px; }
.ek-trip-lk{ grid-column:2 / -1; display:flex; align-items:center; gap:7px; font-size:11.5px;
  color:var(--mut); margin-top:-3px; }
.ek-trip-lk .pt{ width:6px; height:6px; border-radius:99px; background:var(--warn); flex-shrink:0; }
.ek-meter > span[data-lv="1"]{ opacity:.86 } .ek-meter > span[data-lv="2"]{ opacity:.70 }
.ek-meter > span[data-lv="3"]{ opacity:.54 } .ek-meter > span[data-lv="4"]{ opacity:.40 }

/* Tablero por etapas (vive en Reportes, no es puerta de entrada). */
.ek-board{ display:grid; grid-template-columns:repeat(4,1fr); gap:11px; }
.ek-bcol{ background:var(--sf2); border:1px solid var(--ln); border-radius:var(--r);
  padding:10px; min-width:0; }
.ek-bcol-hd{ display:flex; align-items:baseline; justify-content:space-between; gap:8px;
  padding:1px 3px 9px; }
.ek-bcol-nm{ font-size:12.5px; font-weight:600; color:var(--ink); }
.ek-bcol-ct{ font-family:var(--mono); font-size:11.5px; color:var(--mut); }
.ek-bcard{ background:var(--sf); border:1px solid var(--ln); border-radius:var(--r-sm);
  padding:10px 11px; margin-bottom:7px; box-shadow:var(--sh); }
.ek-bcard b{ display:block; font-size:12.5px; font-weight:600; color:var(--ink); }
.ek-bcard span{ font-family:var(--mono); font-size:11px; color:var(--mut); }
.ek-bcard.ek-viejo{ border-left:2px solid var(--warn); }
.ek-bcard.ek-viejo span{ color:var(--warn); }

/* -------------------- 4 · BANDEJA DEL DÍA («HOY») -------------------- */

/* La frase de carga es el encabezado real: dice cuánto hay y qué se enfría. */
.ek-load{ font-size:19px; font-weight:600; letter-spacing:-.015em; color:var(--ink); }
.ek-load em{ font-style:normal; color:var(--warn); }
.ek-load-sb{ font-size:13px; color:var(--mut); margin-top:3px; }
.ek-qg{ margin-top:26px; }
.ek-qg-hd{ display:flex; align-items:baseline; gap:9px; padding-bottom:9px; flex-wrap:wrap; }
.ek-qg-nm{ font-size:13px; font-weight:600; color:var(--ink); }
.ek-qg-ct{ font-family:var(--mono); font-size:11.5px; color:var(--mut); }
.ek-qg-wy{ font-size:12.5px; color:var(--mut); margin-left:auto; }

/* Tarjeta de tarea: la decisión se toma acá, no en otra pantalla. */
.ek-task{ background:var(--sf); border:1px solid var(--ln); border-radius:var(--r);
  box-shadow:var(--sh); margin-bottom:9px; overflow:hidden; }
.ek-task-hd{ display:flex; align-items:center; gap:14px; padding:13px 15px; }
.ek-task-bd{ flex:1; min-width:0; }
.ek-task-nd{ font-size:11px; font-weight:600; color:var(--acc); }
.ek-task-nm{ font-size:15px; font-weight:600; letter-spacing:-.01em; color:var(--ink); margin-top:1px; }
.ek-task-fx{ font-size:12.5px; color:var(--mut); margin-top:2px; }
.ek-task-rt{ display:flex; align-items:center; gap:12px; flex-shrink:0; }
.ek-wait{ text-align:right; }
.ek-wait b{ display:block; font-family:var(--mono); font-size:13px; color:var(--ink); font-weight:500; }
.ek-wait span{ font-size:10.5px; color:var(--mut); }
.ek-wait.w b{ color:var(--warn); }
.ek-task-ex{ display:none; padding:0 15px 15px; border-top:1px solid var(--ln2); }
.ek-task.ek-open .ek-task-ex{ display:block; }
.ek-task.ek-open{ border-color:var(--acc-bd); box-shadow:var(--sh-open); }
/* Mensaje sin leer en "Mis mensajes": el mismo borde de acento que ya
   usan .ek-note/.ek-bcard.ek-viejo para "esto pide algo tuyo". */
.ek-task.no-leido{ border-left:3px solid var(--acc); }
.ek-ex-q{ font-size:12.5px; color:var(--mut); padding:13px 0 10px; }

/* Opción de grupo: se elige por los motivos, no por un porcentaje. */
.ek-opt{ display:block; width:100%; box-sizing:border-box; text-align:left; background:var(--sf);
  border:1px solid var(--ln); border-radius:var(--r-sm); padding:12px 13px; cursor:pointer;
  margin-bottom:8px; transition:border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease); }
.ek-opt:hover{ border-color:var(--mut); }
.ek-opt.ek-sel{ border-color:var(--acc); background:var(--acc-sf); }
.ek-opt-hd{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.ek-opt-nm{ font-size:13.5px; font-weight:600; color:var(--ink); }
.ek-rec{ font-size:10.5px; font-weight:600; color:var(--acc); border:1px solid var(--acc);
  border-radius:99px; padding:1px 8px; }
.ek-opt-sb{ font-size:12px; color:var(--mut); margin-top:2px; }
.ek-opt-fx{ display:flex; gap:15px; margin-top:9px; flex-wrap:wrap; }
/* La esquina derecha de la cabecera de una opción: el chip de proximidad o
   la advertencia, empujados al borde. */
.ek-opt-r{ margin-left:auto; display:flex; align-items:center; gap:7px; }
/* La tira de datos duros de un GC: mono y apagada, como .ek-rail-sum en
   chico. Lo que se CONSULTA, separado de lo que se lee. */
.ek-opt-fx > span{ font-family:var(--mono); font-size:11.5px; color:var(--mut); }
.ek-opt-fx > span b{ color:var(--ink); font-weight:500; }
.ek-opt-fx > span i{ color:var(--fnt); }
.ek-opt-fx > span.w{ color:var(--warn); }
/* Por qué se recomienda ESTE. Va solo en la tarjeta recomendada: si lo
   llevaran las tres, ninguna diría nada. */
.ek-opt-why{ font-size:12px; color:var(--acc); margin-top:8px; line-height:1.5; }
/* El bloque de búsqueda manual dentro de un riel: hundido sobre --sf2 para
   que se lea como una zona aparte de la lista de sugeridos, y no como tres
   tarjetas más de la misma lista. */
.ek-bus{ border:1px solid var(--ln); border-radius:var(--r); background:var(--sf2);
  padding:12px; margin-top:10px; }
.ek-fx{ display:flex; align-items:center; gap:6px; font-size:12px; color:var(--ink2); }
.ek-fx .pt{ width:6px; height:6px; border-radius:99px; background:var(--ok); flex-shrink:0; }
.ek-fx.no{ color:var(--fnt); }
.ek-fx.no .pt{ background:var(--ln); }
.ek-ex-ft{ display:flex; align-items:center; gap:9px; padding-top:4px; }
.ek-ex-ft .btn-text{ margin-right:auto; }

/* Hilo del recorrido: en qué etapa va esta persona. */
.ek-hilo{ display:flex; gap:3px; margin-top:7px; }
.ek-hilo i{ display:block; width:14px; height:3px; border-radius:2px; background:var(--ln); }
.ek-hilo i.f{ background:var(--acc); }

/* Fin de la cola: no es un vacío, es el trabajo terminado. */
.ek-done{ display:flex; align-items:center; gap:11px; margin-top:26px; padding:15px;
  background:var(--sf); border:1px dashed var(--ln); border-radius:var(--r); }
.ek-done i{ color:var(--ok); font-size:15px; }
.ek-done b{ font-size:13.5px; font-weight:600; color:var(--ink); }
.ek-done span{ display:block; font-size:12.5px; color:var(--mut); }

/* Barra de avance (recorrido, stock, compromisos) */
.ek-meter{ height:24px; background:var(--sf3); border-radius:var(--r-sm); overflow:hidden; }
.ek-meter > span{ display:block; height:100%; background:var(--acc); border-radius:var(--r-sm); }

/* ------------------- 5 · FICHA EN PANEL LATERAL ------------------- */
.ek-rail{ position:fixed; top:0; right:0; bottom:0; width:392px; max-width:100%;
  background:var(--sf); border-left:1px solid var(--ln); box-shadow:var(--sh-lg);
  z-index:var(--z-rail); display:flex; flex-direction:column; transform:translateX(100%);
  transition:transform var(--t-slow) var(--ease); visibility:hidden; }
.ek-rail.ek-open{ transform:none; visibility:visible; }
/* Riel ancho: para lo que antes justificaba un modal —formularios de muchos
   campos, tablas de selección—. Sigue entrando por la derecha. */
.ek-rail.ek-w{ width:620px; }
.ek-rail.ek-xw{ width:860px; }
/* ---- Cabecera: el medianoche del menú, no una cuarta caja blanca ----
   Antes cabecera, cuerpo y pie eran tres cajas del mismo blanco separadas
   por un filete de 1px: nada decía por dónde empezar a leer, y al abrir el
   riel no se notaba que se había abierto algo. Con la cabecera en --nav el
   riel se lee como una CAPA sobre el contenido, que es lo que es.
   No es un azul nuevo: es el token del menú lateral. */
.ek-rail-hd{ display:flex; align-items:center; gap:13px; padding:17px 18px;
  background:var(--nav); }
.ek-rail-hd .ek-nm{ font-size:17px; color:var(--nav-on); letter-spacing:-.01em; }
.ek-rail-hd .ek-sb{ color:var(--nav-ink); margin-top:3px; }
/* La identidad necesita min-width:0 o la línea mono impone su ancho y
   empuja el botón de cerrar fuera de la cabecera. */
.ek-rail-id{ flex:1; min-width:0; }
.ek-rail-id .ek-est{ margin-top:7px; color:var(--nav-on); }
/* El punto de estado sobre oscuro usa la escala luminosa. Ver los tokens
   --ok-nav / --warn-nav / --dan-nav en la sección 1. */
.ek-rail-id .ek-est .pt{ background:var(--nav-ink); }
.ek-rail-id .ek-est.k .pt{ background:var(--ok-nav); }
.ek-rail-id .ek-est.a .pt{ background:var(--acc-nav); }
.ek-rail-id .ek-est.w .pt{ background:var(--warn-nav); }
.ek-rail-id .ek-est.d .pt{ background:var(--dan-nav); }
.ek-rail-hd .ek-icb{ align-self:flex-start; background:transparent;
  border-color:var(--nav-ln); color:var(--nav-ink); }
.ek-rail-hd .ek-icb:hover{ background:var(--nav-hov); color:var(--nav-on); }
/* La marca del riel. Si el riel es de una PERSONA va su avatar; si no
   —un formulario, una ayuda, un ensayo— va el ícono de ese módulo, que es
   lo que ya lo identifica en el menú.
   ⚠️ El avatar va acá SIN anillo de estado: el aro se calibró contra fondo
   claro y, sobre todo, en la cabecera el estado ya está escrito con su
   palabra al lado. El aro sirve para barrer una lista de veinte filas, no
   para repetir lo que dice el renglón de al lado. */
.ek-rail-mk{ width:42px; height:42px; border-radius:12px; flex:none; display:grid;
  place-items:center; font-size:15px; background:rgba(255,255,255,.10); color:var(--nav-on); }
.ek-rail-hd .ek-av-aro::after{ display:none; }

/* ---- Tira de datos duros ----
   Lo que se CONSULTA, separado de lo que se lee: teléfono, comuna, qué le
   corresponde, cuánto lleva esperando. Va en mono y en una sola franja
   porque no es prosa, son valores.
   ⚠️ REGLA: se omite entera con menos de tres celdas. Media tira dice
   menos que ninguna, y los rieles de CREAR (nueva solicitud, nuevo GC,
   enrolar el segundo factor) no tienen nada que resumir todavía. Un riel
   puede tener cabecera sin tira; nunca tira sin cabecera. */
/* ⚠️ La tira NO es una sola fila. Con `grid-auto-flow:column` las tres
   celdas se reparten los 356px útiles del riel estándar y las tres se
   truncan a la vez: «+56 9 2052 7…», «Jóvenes Homb…», «hace una sem…».
   Un teléfono a medias no es un dato, y el motivo de poner el teléfono
   arriba era justamente poder leerlo. Con `auto-fit` la tira entra en dos
   columnas a 392px y en cuatro a 620px, sin que nadie elija el número.
   ⚠️ El mínimo se eligió MIDIENDO los valores reales, no a ojo. Los más
   largos que pasan por la tira, en mono a 12.5px: «(Jóvenes) Ashley
   Fuentes» 180px, «Campus Renacer Santiago» 173px, «Caja #1 · Individual»
   150px, un teléfono formateado 113px. Con 180 la tira entra en 2
   columnas a 392px, 3 a 620 y 4 a 860, y el contenido útil queda en
   168 / 178 / 187px: alcanza para todos salvo un correo largo.
   Ojo con `minmax`: mide la PISTA, no el contenido, así que el número
   incluye los 28px de padding de la celda. Los dos intentos anteriores
   (120 y 148) daban una columna de más y el valor seguía cortado, que es
   el bug que esto venía a arreglar.
   ⚠️ Los filetes van en `box-shadow` de la celda y NO en el `gap` sobre un
   contenedor teñido: con tres celdas en dos columnas sobra media pista, y
   ese hueco pintado del color del filete se lee como una celda vacía —o
   sea, como un dato que falta—. Con la sombra, el hueco queda del color
   de la tira y no existe. Las sombras del borde exterior las recorta el
   `overflow:hidden`, así que solo se ven las divisiones interiores, tanto
   entre columnas como entre FILAS —que es lo que un border-left no
   podía—. */
.ek-rail-sum{ display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  margin:0; overflow:hidden; background:var(--sf2); border-bottom:1px solid var(--ln); }
/* Un riel que rellena el JS declara la tira vacía y la completa después.
   Si nunca junta tres celdas se queda vacía, y una franja vacía es un
   filete suelto bajo la cabecera: no se dibuja. */
.ek-rail-sum:empty{ display:none; }
.ek-rail-sum > div{ padding:11px 14px; min-width:0;
  box-shadow:-1px 0 0 var(--ln2), 0 -1px 0 var(--ln2); }
.ek-rail-sum dt{ font-size:10.5px; color:var(--fnt); letter-spacing:.04em;
  text-transform:uppercase; }
.ek-rail-sum dd{ margin:3px 0 0; font-family:var(--mono); font-size:12.5px; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

.ek-rail-bd{ flex:1; overflow-y:auto; padding:18px; }
/* El pie sobre --sf2 y con filete: cierra el riel en vez de terminarlo.
   Un solo botón lleno; las secundarias van discretas o bajo «⋯». */
.ek-rail-ft{ padding:14px 18px; border-top:1px solid var(--ln); display:flex; gap:9px;
  background:var(--sf2); }
.ek-rail-ft > *{ min-width:0; overflow:hidden; text-overflow:ellipsis; }
/* El «⋯» de las acciones secundarias: ancho fijo, no se reparte el pie.
   Su desplegable abre hacia ARRIBA y se pega al borde derecho del riel. */
.ek-rail-mas{ flex:none; overflow:visible; }
.ek-rail-mas > button{ width:38px; padding:0; justify-content:center; }
.ek-rail-mas .ek-menu.ek-arriba{ left:auto; right:0; width:220px; }
.ek-dl{ display:grid; grid-template-columns:1fr 1fr; gap:14px 16px; }
.ek-dl dt{ font-size:11.5px; color:var(--mut); }
.ek-dl dd{ font-size:13.5px; font-weight:500; color:var(--ink); margin:1px 0 0; }
/* Rótulo de sección: versalitas apagadas, no tinta principal. Estaba en
   --ink a 12px, o sea con el mismo peso visual que el dato que rotula:
   ordenaba tanto como una línea más de contenido. */
.ek-rail-sc{ font-size:11px; font-weight:600; letter-spacing:.08em; text-transform:uppercase;
  color:var(--mut); border-top:1px solid var(--ln2); padding-top:16px; margin:20px 0 11px; }
/* El primer rótulo no lleva filete ni aire arriba: ya lo separa el borde del
   contenedor, y con los dos se abría una franja vacía con una línea suelta.
   ⚠️ Vale en el riel Y en la tarjeta: desde que la ficha de usuario salió del
   riel a pantalla propia (ago 2026), estos rótulos también viven en
   `.ek-card`. Con la regla acotada a `.ek-rail-bd` había que apagarlo inline
   en cada pestaña, que es la copia que siempre termina derivando. */
.ek-rail-bd > .ek-rail-sc:first-child,
.ek-card > .ek-rail-sc:first-child,
.ek-card-bd > .ek-rail-sc:first-child{ border-top:0; padding-top:0; margin-top:0; }
.ek-time{ list-style:none; margin:0; padding:0; }
.ek-time li{ position:relative; padding:0 0 15px 20px; font-size:12.5px; color:var(--ink2); }
.ek-time li::before{ content:''; position:absolute; left:3px; top:5px; width:7px; height:7px;
  border-radius:99px; background:var(--ln); }
.ek-time li.k::before{ background:var(--acc); }
.ek-time li:not(:last-child)::after{ content:''; position:absolute; left:6px; top:14px; bottom:0;
  width:1px; background:var(--ln); }
.ek-time b{ display:block; font-size:12.5px; font-weight:600; color:var(--ink); }
.ek-time span{ font-family:var(--mono); font-size:11px; color:var(--mut); }

/* Grilla de códigos de respaldo del segundo factor (modulos/perfil.php),
   dentro del riel de enrolamiento. Mismos tokens que .tag: superficie de
   campo, borde de línea y radio chico — es un dato para copiar, no una
   tarjeta. */
.ek-codigos-grid{ display:grid; grid-template-columns:repeat(2, 1fr); gap:8px;
  font-family:var(--mono); }
.ek-codigo{ padding:8px 12px; border:1px solid var(--ln); border-radius:var(--r-sm);
  background:var(--sf2); color:var(--ink); text-align:center; letter-spacing:.05em; }

/* Ficha de datos que NO se editan (identidad en Mi perfil). Es una lista
   de definición y no una tabla: son pares dato/valor de una sola persona,
   no filas comparables entre sí. */
.ek-ficha{ display:grid; grid-template-columns:repeat(auto-fit, minmax(160px,1fr)); gap:12px 18px; }
.ek-ficha dt{ font-size:11.5px; color:var(--mut); margin-bottom:2px; }
.ek-ficha dd{ margin:0; color:var(--ink); font-weight:500; }

/* Checklist de requisitos que se van cumpliendo mientras se teclea.
   ⚠️ El color no es la única señal: el ícono cambia de círculo a visto. */
.ek-chk{ list-style:none; margin:0; padding:0; display:grid; gap:5px; }
.ek-chk li{ display:flex; align-items:center; gap:8px; font-size:12px; color:var(--mut); }
.ek-chk li i{ font-size:9px; }
.ek-chk li.on{ color:var(--ok); }

/* Ventana de progreso (Lote D, EK.progreso()): una línea por canal de
   aviso —app, correo, WhatsApp—, con su ícono y su nota. NO es un
   checklist que se va marcando solo (eso es .ek-chk, arriba): llega ya
   resuelto desde el servidor en la respuesta del guardado, y esto sólo
   lo pinta. Mismos niveles que .ek-est (k/w/d); 'espera' queda neutro
   porque ahí el ícono YA dice «en curso» con el giro. */
.ek-prog-ln{ display:flex; align-items:flex-start; gap:11px; padding:10px 0;
  border-bottom:1px solid var(--ln); }
.ek-prog-ln:last-child{ border-bottom:none; }
.ek-prog-ic{ flex-shrink:0; width:24px; height:24px; border-radius:99px;
  display:flex; align-items:center; justify-content:center;
  font-size:11px; color:var(--mut); background:var(--sf2); }
.ek-prog-ln.k .ek-prog-ic{ color:var(--ok); background:var(--ok-sf); }
.ek-prog-ln.w .ek-prog-ic{ color:var(--warn); background:var(--warn-sf); }
.ek-prog-ln.d .ek-prog-ic{ color:var(--danger); background:var(--dan-sf); }
.ek-prog-tx{ flex:1; min-width:0; padding-top:2px; }
.ek-prog-tt{ font-size:13.5px; font-weight:500; color:var(--ink); }
.ek-prog-nt{ font-size:12px; color:var(--mut); margin-top:2px; }

/* Fila con casilla: una opción que se activa, con su texto al lado. Es
   una FILA y no un `flex` suelto —va en `display:flex` sobre un <label>,
   que por defecto es inline y dejaba las tres opciones en un renglón—.
   El área clicleable es toda la fila, no solo el cuadrito de 13px. */
.ek-opcion{ display:flex; align-items:flex-start; gap:9px; padding:7px 0;
  font-size:13.5px; color:var(--ink2); cursor:pointer; }
.ek-opcion input{ margin-top:2px; flex:none; }
.ek-opcion .ek-opcion-sb{ display:block; font-size:12px; color:var(--mut); margin-top:2px; }
/* Opción que hoy no se puede activar. Se apaga pero NO se esconde: la
   razón va escrita en su propio subtítulo, ahí donde se busca, en vez de
   aparecer como un error después de confirmar. */
.ek-opcion-off{ cursor:not-allowed; color:var(--mut); }
.ek-opcion-off input{ cursor:not-allowed; }

/* Las cuatro apps autenticadoras del paso 1 del enrolamiento: dos filas
   (una por app) por dos columnas (una por plataforma). No hay pestañas ni
   detección de sistema operativo a propósito — el teléfono que escanea no
   es el equipo que muestra la pantalla, así que cualquier preselección
   escondería justo el QR que hace falta la mitad de las veces.

   ⚠️ Se llaman `ek-authapp`, NO `ek-app`: ese nombre ya es el de la marca
   «Ekklesia» de la barra superior (sección 8, más abajo), y como esa regla
   va después ganaba sobre ésta — las tarjetas salían con el tipo y el
   color del wordmark. Misma trampa que .ek-bar-top contra .ek-bar. */
.ek-authapps{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:14px; }
.ek-authapp{ border:1px solid var(--ln); border-radius:var(--r-sm); background:var(--sf2);
  padding:10px; text-align:center; }
.ek-authapp img, .ek-authapp canvas, .ek-authapp table{ margin:0 auto; max-width:100%; height:auto; }
.ek-authapp-nm{ font-size:12px; font-weight:600; color:var(--ink); margin-top:6px; }
.ek-authapp-pl{ font-size:11px; color:var(--mut); }

/* ---- Escudo de Seguridad (2FA) — includes/ui.php::ek_escudo_2fa().
   Reutilizado en las tres pantallas del módulo; el estado se lee en
   borde/relleno, nunca en un color nuevo fuera de --acc/--warn/--ln. ---- */
.ek-escudo-2fa{ position:relative; display:inline-flex; align-items:center; justify-content:center; flex:none; }
.ek-escudo-2fa-svg{ position:relative; width:100%; height:100%; z-index:1;
  filter:drop-shadow(0 6px 14px rgba(14,42,99,.22)); }
.ek-escudo-2fa-escudo{ fill:var(--acc-sf); stroke:var(--acc); stroke-width:1.3; }
.ek-escudo-2fa.pendiente .ek-escudo-2fa-svg{ filter:none; }
.ek-escudo-2fa.pendiente .ek-escudo-2fa-escudo{ fill:var(--warn-sf); stroke:var(--warn); stroke-dasharray:3 2; }
.ek-escudo-2fa.inactivo .ek-escudo-2fa-svg{ filter:none; }
.ek-escudo-2fa.inactivo .ek-escudo-2fa-escudo{ fill:var(--sf2); stroke:var(--ln); stroke-dasharray:3 2; }

/* Cerrojo dentro del escudo: sin él, el estado "activo" era un contorno
   vacío — un candado adentro es lo que dice "esto protege algo", no
   solo "esto es un escudo". Sigue la misma paleta de estado que el
   escudo, nunca un color aparte. */
.ek-escudo-2fa-cerrojo-arco{ stroke:var(--acc); }
.ek-escudo-2fa-cerrojo-cuerpo{ fill:var(--acc); }
.ek-escudo-2fa.pendiente .ek-escudo-2fa-cerrojo-arco{ stroke:var(--warn); }
.ek-escudo-2fa.pendiente .ek-escudo-2fa-cerrojo-cuerpo{ fill:var(--warn); }
.ek-escudo-2fa.inactivo .ek-escudo-2fa-cerrojo-arco{ stroke:var(--mut); }
.ek-escudo-2fa.inactivo .ek-escudo-2fa-cerrojo-cuerpo{ fill:var(--mut); }

.ek-escudo-2fa-anillo{ position:absolute; inset:-12%; border-radius:50%;
  border:1.5px dashed rgba(14,42,99,.22); }
.ek-escudo-2fa-pulso{ position:absolute; inset:6%; border-radius:50%;
  background:radial-gradient(circle, rgba(14,42,99,.14), transparent 72%); }
.ek-escudo-2fa.pendiente .ek-escudo-2fa-anillo, .ek-escudo-2fa.pendiente .ek-escudo-2fa-pulso,
.ek-escudo-2fa.inactivo .ek-escudo-2fa-anillo, .ek-escudo-2fa.inactivo .ek-escudo-2fa-pulso{ display:none; }

@media (prefers-reduced-motion: no-preference){
  .ek-escudo-2fa.activo .ek-escudo-2fa-anillo{ animation:ek-escudo-spin 16s linear infinite; }
  .ek-escudo-2fa.activo .ek-escudo-2fa-pulso{ animation:ek-escudo-pulso 2.6s ease-in-out infinite; }
}
@keyframes ek-escudo-spin{ to{ transform:rotate(360deg); } }
@keyframes ek-escudo-pulso{ 0%,100%{ transform:scale(.88); opacity:.55; } 50%{ transform:scale(1.12); opacity:0; } }

/* Confirmado: se dibuja UNA vez — es una confirmación, no una celebración. */
.ek-escudo-2fa.confirmado .ek-escudo-2fa-circulo{ stroke-dasharray:220; stroke-dashoffset:220; }
.ek-escudo-2fa.confirmado .ek-escudo-2fa-check{ stroke-dasharray:36; stroke-dashoffset:36; }
@media (prefers-reduced-motion: no-preference){
  .ek-escudo-2fa.confirmado .ek-escudo-2fa-circulo{ animation:ek-escudo-trazo 1s ease forwards; }
  .ek-escudo-2fa.confirmado .ek-escudo-2fa-check{ animation:ek-escudo-trazo .6s ease .8s forwards; }
}
@media (prefers-reduced-motion: reduce){
  .ek-escudo-2fa.confirmado .ek-escudo-2fa-circulo, .ek-escudo-2fa.confirmado .ek-escudo-2fa-check{ stroke-dashoffset:0; }
}
@keyframes ek-escudo-trazo{ to{ stroke-dashoffset:0; } }

/* Entrada escalonada de los 10 códigos de respaldo, solo la primera vez
   que se pintan. */
@media (prefers-reduced-motion: no-preference){
  .ek-codigos-grid .ek-codigo{ opacity:0; animation:ek-codigo-entra .35s ease forwards; }
  .ek-codigos-grid .ek-codigo:nth-child(1){ animation-delay:.02s; }
  .ek-codigos-grid .ek-codigo:nth-child(2){ animation-delay:.06s; }
  .ek-codigos-grid .ek-codigo:nth-child(3){ animation-delay:.10s; }
  .ek-codigos-grid .ek-codigo:nth-child(4){ animation-delay:.14s; }
  .ek-codigos-grid .ek-codigo:nth-child(5){ animation-delay:.18s; }
  .ek-codigos-grid .ek-codigo:nth-child(6){ animation-delay:.22s; }
  .ek-codigos-grid .ek-codigo:nth-child(7){ animation-delay:.26s; }
  .ek-codigos-grid .ek-codigo:nth-child(8){ animation-delay:.30s; }
  .ek-codigos-grid .ek-codigo:nth-child(9){ animation-delay:.34s; }
  .ek-codigos-grid .ek-codigo:nth-child(10){ animation-delay:.38s; }
}
@keyframes ek-codigo-entra{ from{ opacity:0; transform:translateY(4px); } to{ opacity:1; transform:translateY(0); } }

/* Shake corto del campo de código cuando el 2FA de login rechaza el
   intento — reemplaza el recuadro de error como única señal. */
@media (prefers-reduced-motion: no-preference){
  .ek-shake{ animation:ek-shake .4s ease; }
}
@keyframes ek-shake{
  10%,90%{ transform:translateX(-1px); } 20%,80%{ transform:translateX(2px); }
  30%,50%,70%{ transform:translateX(-4px); } 40%,60%{ transform:translateX(4px); }
}

/* Confirmación de EK.confirmar(), que reemplaza al window.confirm() del
   navegador —el diálogo del sistema operativo, que no se parece en nada
   al resto de la aplicación—.

   Es un VELO que bloquea y no un riel, por la misma razón que el aviso de
   cierre por inactividad: la regla del riel rige para VER un detalle, y
   esto exige decidir. Comparte marcado y medidas con `#ek-ses-caja`. */
.ek-conf-velo{
  position:fixed; inset:0; z-index:var(--z-sesion-velo);
  display:flex; align-items:center; justify-content:center; padding:20px;
  background:rgba(7,17,41,.55);
  backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
}
.ek-conf-caja{
  background:var(--sf); border-radius:var(--r-lg); box-shadow:var(--sh-lg);
  max-width:420px; width:100%; padding:28px; text-align:center;
}
.ek-conf-ic{
  width:52px; height:52px; margin:0 auto 14px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; font-size:22px;
  background:var(--acc-sf); color:var(--acc);
}
.ek-conf-ic.w{ background:var(--warn-sf); color:var(--warn); }
.ek-conf-ic.d{ background:var(--dan-sf); color:var(--danger); }
.ek-conf-caja h2{ font-size:19px; font-weight:600; color:var(--ink); margin-bottom:6px; }
.ek-conf-caja p{ font-size:14px; color:var(--ink2); margin-bottom:0; line-height:1.5; }
.ek-conf-ft{ display:flex; gap:10px; margin-top:22px; }
.ek-conf-ft .btn-secondary{ flex:1; justify-content:center; }
.ek-conf-ft .btn-primary{ flex:1.4; justify-content:center; }

/* El enlace copiable del simulador móvil (EK.simulador()): la salida que
 * no toca la sesión de esta pestaña — se pega en una ventana de incógnito
 * o en otro navegador y queda una sesión de verdad aparte. */
.ek-sim-url{ display:flex; gap:8px; margin-top:16px; text-align:left; }
.ek-sim-url input{
  flex:1; min-width:0; font-family:var(--mono); font-size:12px; color:var(--ink2);
  background:var(--sf2); border:1px solid var(--ln); border-radius:var(--r-sm);
  padding:9px 10px; cursor:text;
}
.ek-sim-url .btn-secondary{ flex-shrink:0; padding:0 14px; }

@media (prefers-reduced-motion: no-preference){
  .ek-conf-caja{ animation:ek-conf-entra .22s var(--ease); }
}
@keyframes ek-conf-entra{ from{ opacity:0; transform:translateY(8px) scale(.98); } to{ opacity:1; transform:none; } }

/* ---------------- 6 · CAPAS, MODALES Y RESPONSIVO ---------------- */
.ek-z-nav{ z-index:var(--z-nav); }
.ek-z-drawer-o{ z-index:var(--z-drawer-o); }
.ek-z-drawer{ z-index:var(--z-drawer); }
.ek-z-modal{ z-index:var(--z-modal); }
/* Fila de una lista maestro-detalle (seguimiento). Tres estados y nada más:
   normal, en alarma —lleva días sin contacto— y la que está abierta. */
/* Ícono redondo que lleva el color de un estado (historial de contactos). */
.ek-ico-est{ width:32px; height:32px; border-radius:99px; display:grid; place-items:center;
  flex-shrink:0; font-size:12px; background:var(--sf3); color:var(--mut); }
.ek-ico-est.k{ background:rgba(6,122,85,.10); color:var(--ok); }
.ek-ico-est.w{ background:rgba(180,83,9,.10); color:var(--warn); }
.ek-ico-est.d{ background:var(--dan-sf); color:var(--danger); }

.ek-fila{ background:var(--sf2); border:1px solid var(--ln); }
.ek-fila:hover{ background:var(--sf3); }
.ek-alarma{ background:var(--dan-sf); border:1px solid var(--dan-bd); }
.ek-alarma:hover{ border-color:var(--danger); }
.ek-sel{ background:var(--acc); border:1px solid var(--acc); color:var(--acc-ink); }
.ek-sel .ek-nm, .ek-sel .ek-sb{ color:var(--acc-ink); }
.ek-sel .ek-sb{ opacity:.72; }

/* Paleta ⌘K: ir a una pantalla escribiendo. */
/* Globo de la campanita. Es un contador, no un adorno: solo aparece si
   hay algo, y usa el rojo de estado porque significa trabajo esperando.
   ⚠️ Va COLGADO de la esquina, no encima del ícono. Con `top:-5px;right:-5px`
   el globo quedaba dentro del botón —que mide 34px— y un valor de tres
   caracteres («99+») medía 26px: tapaba el ancho completo y empujaba la
   campana al borde inferior, que es como decir que no había campana. Ahora
   se apoya en el borde superior y lleva un anillo del color de la barra, así
   que se lee como un objeto pegado encima y no como parte del ícono.
   Por eso el marcado muestra CUÁNTOS asuntos hay (dos dígitos), no la suma
   de todo lo pendiente: ningún globo de 18px aguanta tres caracteres.
   El desplazamiento es asimétrico a propósito: sube 8px —lo justo para
   despegarse del glifo, que ocupa apenas 12.5px en un botón de 34— y sale
   solo 4px a la derecha, porque más lo dejaba a 3px del botón de acción que
   viene enseguida en la barra. */
.ek-globo{ position:absolute; top:-8px; right:-4px; min-width:18px; height:18px; padding:0 3px;
  box-sizing:border-box; border:2px solid var(--sf);
  border-radius:99px; background:var(--danger); color:#fff; font-family:var(--mono);
  font-size:9.5px; line-height:14px; text-align:center; font-weight:500; }

.ek-pal-o{ position:fixed; inset:0; background:rgba(9,12,22,.42); backdrop-filter:blur(2px);
  z-index:var(--z-modal); display:none; align-items:flex-start; justify-content:center; padding-top:12vh; }
.ek-pal-o.ek-open{ display:flex; }
.ek-pal{ width:min(560px,92vw); background:var(--sf); border:1px solid var(--ln);
  border-radius:var(--r); box-shadow:var(--sh-lg); overflow:hidden; }
.ek-pal input{ width:100%; border:0; outline:0; padding:15px 18px; font-size:15px;
  color:var(--ink); border-bottom:1px solid var(--ln2); background:var(--sf); }
.ek-pal-r{ max-height:340px; overflow-y:auto; padding:7px; }
.ek-pal-it{ display:flex; align-items:center; gap:11px; padding:9px 12px; border-radius:var(--r-sm);
  font-size:13.5px; color:var(--ink2); text-decoration:none; }
.ek-pal-it i{ width:15px; text-align:center; color:var(--fnt); font-size:12.5px; }
.ek-pal-it small{ margin-left:auto; font-size:11.5px; color:var(--fnt); }
.ek-pal-it:hover, .ek-pal-it.on{ background:var(--acc-sf); color:var(--acc); }
.ek-pal-it:hover i, .ek-pal-it.on i{ color:var(--acc); }
.ek-pal-v{ padding:22px; text-align:center; color:var(--fnt); font-size:13px; }

.ek-velo{ background:rgba(9,12,22,.42); backdrop-filter:blur(2px); }

/* ---------------- 6a · MODAL ----------------
   REHABILITADO (ago 2026) por decisión explícita del dueño del sistema. Esta
   clase estuvo marcada OBSOLETA con la regla «NADA va en modal: el escape para
   un formulario largo es el riel ancho, no volver al centro de la pantalla».
   Esa regla se revierte, y conviene dejar escrito QUÉ la reemplaza para no
   volver a discutirlo — y para que el modal no se coma otra vez al riel:

   · RIEL (.ek-rail) — VER un detalle sin perder la lista. Ficha de la persona,
     ficha del usuario, pendientes, ayuda, ensayo de un evento. El contenido de
     atrás sigue visible a propósito: es contra eso que se está mirando.
   · MODAL (.ek-modal) — DECIDIR o LLENAR algo que no admite mirar a los
     costados. Se lleva el foco entero porque el trabajo es ese y no otro.
   · PANTALLA — cuando hay navegación interna (pestañas, pasos) o el formulario
     es la tarea completa. Un riel de 860 px ya era una pantalla disfrazada.
   · AVISO (.ek-aviso) — lo que sólo informa. Nunca interrumpe.

   ⚠️ La diferencia que importa entre riel y modal NO es el ancho: es si se
   puede descartar sin contestar. Un riel se cierra con Escape o con un clic al
   costado; un modal de decisión, no (ver `EK.modal()` y `data-ek-fijo`).

   El velo es el mismo tono que el del riel y el de la sesión: una sola
   profundidad para toda la aplicación. */
/* El fondo no scrollea con el modal arriba: el velo dice que no se puede
   tocar, pero la rueda del mouse seguía moviendo la tabla de atrás. */
body.ek-modal-on{ overflow:hidden; }
.ek-modal-o{ position:fixed; inset:0; z-index:var(--z-modal);
  background:rgba(9,12,22,.42); backdrop-filter:blur(2px);
  display:flex; align-items:center; justify-content:center; padding:18px;
  opacity:0; visibility:hidden; transition:opacity .16s ease, visibility 0s .16s; }
.ek-modal-o.ek-open{ opacity:1; visibility:visible; transition:opacity .16s ease; }
/* ⚠️ Los anchos BAJARON en ago 2026 (880/520/980 → 760/460/880) por pedido
   explícito: los modales se veían «grandes y dispersos». Un modal no es una
   pantalla —es una decisión o un detalle— y a 980px el contenido se estira
   hasta que las etiquetas quedan a media cuadra de sus valores. El que de
   verdad necesita ancho es el que lleva DOS columnas, y para eso está
   `.ek-w`; el resto se lee mejor angosto. */
.ek-modal{ width:min(760px,100%); max-height:92vh; display:flex; flex-direction:column;
  background:var(--sf); border:1px solid var(--ln); border-radius:var(--r);
  box-shadow:var(--sh-lg); overflow:hidden;
  transform:translateY(8px) scale(.985); transition:transform .16s ease; }
.ek-modal-o.ek-open .ek-modal{ transform:none; }
/* Anchos, con la misma escala del riel: el estrecho para una decisión de dos
   líneas, el ancho para un formulario de verdad. */
.ek-modal.ek-n{ width:min(460px,100%); }
.ek-modal.ek-w{ width:min(880px,100%); }
.ek-modal-hd{ display:flex; align-items:flex-start; justify-content:space-between; gap:14px;
  padding:15px 18px; border-bottom:1px solid var(--ln2); flex-shrink:0; }
.ek-modal-hd .ek-nm{ font-size:17px; letter-spacing:-.01em; }
.ek-modal-hd .ek-sb{ margin-top:3px; }
.ek-modal-bd{ padding:16px 18px; overflow-y:auto; flex:1; min-height:0; }
/* ⚠️ El PRIMER rótulo de sección del cuerpo no lleva filete ni aire arriba:
   ya lo separa el borde de la tira o de la cabecera, y con los dos se abría
   una franja vacía con una línea suelta. Es la misma regla que ya rige en el
   riel; acá hacía falta declararla porque el cuerpo del modal es otro
   contenedor. */
.ek-modal-bd > .ek-rail-sc:first-child,
.ek-modal-bd > *:first-child > .ek-rail-sc:first-child{
  margin-top:0; padding-top:0; border-top:0; }
/* ⚠️ La tira de datos duros es un HERMANO flex de la cabecera y del cuerpo, y
   sin `flex-shrink:0` el cuerpo —que es `flex:1`— se la come: salía cortada
   por la mitad, con los cuatro valores tapados justo debajo de su rótulo. La
   cabecera y el pie ya lo llevaban; el <dl> se agregó después y quedó fuera.
   No se ve en ninguna prueba de estado: el elemento está ahí y `abierto` da
   true. Se vio en una captura. */
.ek-modal > .ek-rail-sum{ flex-shrink:0; }
.ek-modal-ft{ display:flex; justify-content:flex-end; gap:9px; padding:14px 18px;
  border-top:1px solid var(--ln2); flex-shrink:0; background:var(--sf2); }
/* En el teléfono no hay «centro de la pantalla» que valga: el modal ocupa lo
   que hay y se ancla abajo, donde llega el pulgar. */
@media (max-width:640px){
  .ek-modal-o{ padding:0; align-items:flex-end; }
  .ek-modal, .ek-modal.ek-n, .ek-modal.ek-w{ width:100%; max-height:94vh;
    border-radius:var(--r) var(--r) 0 0; border-bottom:0; }
}
@media (prefers-reduced-motion:reduce){
  .ek-modal-o, .ek-modal{ transition:none; }
  .ek-modal{ transform:none; }
}
/* ---------------- 6b · AVISOS EMERGENTES ----------------
   Reemplazan a los modales de SweetAlert que sólo informaban. Un aviso no
   interrumpe: aparece arriba a la derecha, se va solo a los 10 s y lleva un
   OK que lo cierra de inmediato. Nada de velo ni de foco robado — quien está
   escribiendo sigue escribiendo.
   Lo que SÍ interrumpe (elegir, confirmar, llenar) va en riel, no acá.

   Con un riel abierto la pila se corre a la izquierda del riel: si no, el
   aviso cae encima de la ficha y tapa justo lo que se acaba de abrir.
   --ek-riel-w lo escribe EK.riel() según el ancho del riel que esté abierto. */
.ek-avisos{ position:fixed; top:calc(var(--top-h) + 12px); z-index:var(--z-toast);
  right:calc(16px + var(--ek-riel-w, 0px));
  display:flex; flex-direction:column; gap:10px; width:min(392px, calc(100vw - 32px));
  pointer-events:none; transition:right var(--t-slow) var(--ease); }
.ek-aviso{ pointer-events:auto; display:flex; align-items:flex-start; gap:11px;
  background:var(--sf); border:1px solid var(--ln); border-left:3px solid var(--mut);
  border-radius:var(--r); box-shadow:var(--sh-lg); padding:13px 14px;
  transform:translateX(12px); opacity:0;
  transition:transform var(--t) var(--ease), opacity var(--t) var(--ease); }
.ek-aviso.ek-open{ transform:none; opacity:1; }
.ek-aviso.k{ border-left-color:var(--ok); }
.ek-aviso.w{ border-left-color:var(--warn); }
.ek-aviso.d{ border-left-color:var(--danger); }
.ek-aviso.i{ border-left-color:var(--acc); }
.ek-aviso-ic{ width:26px; height:26px; border-radius:99px; display:grid; place-items:center;
  flex-shrink:0; font-size:12px; background:var(--sf3); color:var(--mut); margin-top:1px; }
.ek-aviso.k .ek-aviso-ic{ background:rgba(6,122,85,.10); color:var(--ok); }
.ek-aviso.w .ek-aviso-ic{ background:rgba(180,83,9,.10); color:var(--warn); }
.ek-aviso.d .ek-aviso-ic{ background:var(--dan-sf); color:var(--danger); }
.ek-aviso.i .ek-aviso-ic{ background:var(--acc-sf); color:var(--acc); }
.ek-aviso-tx{ flex:1; min-width:0; }
.ek-aviso-tt{ font-size:13px; font-weight:600; color:var(--ink); }
.ek-aviso-sb{ font-size:12.5px; color:var(--ink2); margin-top:2px; line-height:1.45; }
.ek-aviso-ok{ flex-shrink:0; height:26px; padding:0 11px; border-radius:var(--r-sm);
  border:1px solid var(--acc-bd); background:var(--sf); color:var(--acc);
  font-size:11.5px; font-weight:600; cursor:pointer; align-self:center; }
.ek-aviso-ok:hover{ background:var(--acc-sf); border-color:var(--acc); }
/* Barra que muestra cuánto le queda. Sin esto, los 10 s son una sorpresa. */
.ek-aviso-br{ position:absolute; left:0; bottom:0; height:2px; background:var(--acc-bd);
  border-radius:0 0 0 var(--r); animation:ek-aviso-run linear forwards; }
@keyframes ek-aviso-run{ from{ width:100% } to{ width:0 } }
@media (prefers-reduced-motion:reduce){
  .ek-aviso{ transition:none; }
  .ek-aviso-br{ animation:none; width:0; }
}
@media (max-width:640px){
  /* En móvil el riel ocupa el ancho completo, así que correrse no sirve: los
     avisos bajan al pie, donde no tapan la cabecera de la ficha. */
  .ek-avisos{ top:auto; bottom:12px; right:12px; left:12px; width:auto; }
}

/* Caja del QR del chat de WhatsApp en la ficha de la persona. Fondo blanco
   siempre: un QR sobre gris no lo lee la mitad de los teléfonos. */
/* 116px y no 96: lo que decide si una cámara lee un QR es el tamaño de
   CADA MÓDULO, no el del cuadrado. El de WhatsApp son 25 módulos por lado,
   así que a 96px cada uno quedaba en 3,4px y había que acercar el teléfono;
   a 116 pasa a 4,2px y se lee de una.
   ⚠️ Por eso mismo el QR NO puede llevar el mensaje: con el texto adentro
   son 137 módulos, o sea 0,7px cada uno — ilegible a cualquier tamaño
   razonable. Ver ek_wa_bloque() en includes/ui.php. */
.ek-qr{ width:116px; height:116px; flex-shrink:0; background:#fff; border:1px solid var(--ln);
  border-radius:var(--r-sm); padding:5px; display:grid; place-items:center; }
.ek-qr img, .ek-qr canvas{ width:100%; height:100%; display:block; image-rendering:pixelated; }
/* La capa del QR grande (EK.qrGrande). Existe porque el QR CON el mensaje
   necesita ~137 módulos, y a 4px cada uno son ~560px: en la tarjeta no
   cabe, a pantalla completa sí. `--z-modal` porque se abre POR ENCIMA del
   riel, que ya está en --z-rail. */
.ek-qrbig{ position:fixed; inset:0; z-index:var(--z-modal); display:grid; place-items:center;
  background:rgba(7,17,41,.55); padding:20px; }
.ek-qrbig-caja{ background:var(--sf); border-radius:var(--r); padding:22px;
  box-shadow:var(--sh-lg); text-align:center; max-width:min(94vw,640px); }
.ek-qrbig-tt{ font-size:15px; font-weight:600; color:var(--ink); margin-bottom:14px; }
/* El cuadro se estira hasta 560px pero cede en pantallas chicas: un QR que
   se sale del viewport no se escanea, se scrollea. */
.ek-qrbig .ek-qrbig-qr{ width:min(560px,80vh,86vw); height:min(560px,80vh,86vw);
  margin:0 auto; background:#fff; padding:12px; border-radius:var(--r-sm);
  display:grid; place-items:center; }
.ek-qrbig .ek-qrbig-qr img{ width:100%; height:100%; display:block; image-rendering:pixelated; }
.ek-qrbig-sb{ font-size:12.5px; color:var(--mut); margin:14px 0 12px; line-height:1.5; }
.ek-wa-bloque{ display:flex; align-items:center; gap:13px; padding:12px;
  background:var(--wa-sf); border:1px solid var(--wa-bd); border-radius:var(--r); }

.ek-veil{ position:fixed; inset:0; background:rgba(9,12,22,.28); z-index:calc(var(--z-rail) - 1);
  opacity:0; pointer-events:none; transition:opacity var(--t) var(--ease); }
.ek-veil.ek-open{ opacity:1; pointer-events:auto; }

@media (max-width:1240px){
  /* min() y no 3 a secas: una cinta de 2 cifras no puede pasar a 3 columnas,
     porque la tercera queda vacía y el filete cae en el aire. */
  .ek-kpis{ grid-template-columns:repeat(min(3,var(--kpi-n,3)),1fr); }
  .ek-kpi:nth-child(3){ border-right:0; }
  .ek-kpi:nth-child(-n+3){ border-bottom:1px solid var(--ln); }
}
@media (max-width:1024px){
  #sidebar{ position:fixed; top:0; left:0; bottom:0; z-index:var(--z-drawer);
    transform:translateX(-100%); transition:transform var(--t-slow) var(--ease);
    box-shadow:0 0 60px rgba(0,0,0,.4); }
  #sidebar.open{ transform:translateX(0); }
}
@media (max-width:1240px){
  .ek-board{ grid-template-columns:repeat(2,1fr); }
}
@media (max-width:1024px){
  .ek-g2, .ek-g3{ grid-template-columns:1fr; }
}
@media (max-width:820px){
  :root{ --pad:14px; }
  .ek-form{ grid-template-columns:1fr; }
  .ek-board{ grid-template-columns:1fr; }
  .ek-trip-r{ grid-template-columns:1fr; gap:5px; }
  .ek-trip-vl{ text-align:left; }
  .ek-trip-lk{ grid-column:1; }
  .ek-kpis{ grid-template-columns:repeat(min(2,var(--kpi-n,2)),1fr); }
  .ek-kpi:nth-child(3){ border-right:1px solid var(--ln); }
  .ek-kpi:nth-child(2),.ek-kpi:nth-child(4){ border-right:0; }
  .ek-kpi:nth-child(-n+4){ border-bottom:1px solid var(--ln); }
  /* La ÚLTIMA celda ocupa las dos columnas cuando la cinta trae un número
     impar. `:last-child:nth-child(odd)` cubre 3 y 5 a la vez; antes se
     nombraba sólo la quinta, así que una cinta de 3 dejaba media fila en
     blanco al lado de la última cifra — y un hueco dentro de la cinta se
     lee como un dato que falta, no como espacio sobrante. */
  .ek-kpi:last-child:nth-child(odd){ grid-column:1 / -1; }
  .ek-kpi-fg{ font-size:24px; }
  .ek-rail{ width:100%; }
  /* La tarjeta de tarea se apila y la acción pasa a ancho completo. */
  .ek-task-hd{ flex-wrap:wrap; }
  .ek-task-rt{ width:100%; justify-content:space-between; }
  .ek-task-rt .btn, .ek-task-rt .btn-primary, .ek-task-rt .btn-secondary{ flex:1; }
  .ek-wait{ text-align:left; display:flex; align-items:baseline; gap:6px; }
  .ek-ex-ft{ flex-wrap:wrap; }
  .ek-ex-ft .btn-primary{ width:100%; order:3; }
  /* Las tablas de registro se vuelven listas. */
  table.dt thead{ display:none; }
  table.dt, table.dt tbody, table.dt tr, table.dt td{ display:block; }
  table.dt tbody tr{ padding:12px 0; border-bottom:1px solid var(--ln2); position:relative; }
  table.dt tbody td{ height:auto; padding:0; white-space:normal; border:0; }
  /* Las celdas marcadas con .ek-inline se leen como una sola línea. El
     separador va ANTES de cada celda siguiente, no después de cada una:
     puesto al final deja un «·» colgando cuando la fila corta ahí. */
  table.dt tbody td.ek-inline{ display:inline; }
  table.dt tbody td.ek-inline + td.ek-inline::before{ content:' · '; color:var(--mut); }
  table.dt tbody td.num{ text-align:left; color:var(--mut); }
}
@media (prefers-reduced-motion:reduce){
  .ek-rail, #sidebar{ transition:none; }
}

/* =====================================================================
   8 · DIRECCIÓN «B · CÁLIDO INSTITUCIONAL»  (jul 2026)

   La aplicación se sentía plana y quieta. La modernidad entra por
   MOVIMIENTO, DENSIDAD, ICONOGRAFÍA E ILUSTRACIÓN — no por color nuevo.

   ⚠️ La regla que manda sobre todo lo de acá: en esta aplicación el COLOR
   SIGNIFICA ESTADO (urgente, en curso, atrasado). Por eso se descartó la
   dirección «Expresivo», que daba un color a cada módulo: ese color
   competía con la señal de urgencia en la misma fila. Nada de este bloque
   introduce color que no sea estado, salvo el avatar —que es identidad,
   va desaturado y encerrado en un círculo—.

   Comparativa viva de las tres direcciones: docs/rediseno_grafico.html
   ===================================================================== */

/* -------------------- 8a · Movimiento ------------------------------- */
/* Entrada escalonada: la pantalla se ARMA en vez de aparecer de golpe.
   Se aplica con .ek-anim en un contenedor; los hijos entran en cascada. */
@keyframes ekIn{ from{ opacity:0; transform:translateY(8px); } to{ opacity:1; transform:none; } }

.ek-anim > *{ animation:ekIn .40s var(--ease) both; }
/* ⚠️ LAS CAPAS QUE SE ABREN QUEDAN FUERA DE LA CASCADA. Una hoja, un riel
   o un modal no «entran» con la pantalla: viven escondidos hasta que
   alguien los abre, y su escondite es un `transform`. Como una animación
   con `both` conserva su último fotograma —y una animación LE GANA a una
   declaración normal—, el `transform:none` con el que termina `ekIn`
   pisaba el `translateY(100%)` de `.ek-sheet` y la hoja quedaba ABIERTA de
   entrada, fija, tapando el 47 % inferior de la pantalla en el teléfono y
   sin forma de cerrarla. El riel se salvaba por casualidad: además del
   transform lleva `visibility:hidden`, que la animación no toca.
   Es la segunda vez que `.ek-anim > *` muerde por lo mismo —la primera fue
   el apilamiento del `.ek-combo`, documentado en la sección 3—, así que
   acá se corta de raíz para las tres capas. */
.ek-anim > .ek-sheet,
.ek-anim > .ek-rail,
.ek-anim > .ek-modal-o{ animation:none; }
.ek-anim > *:nth-child(1){ animation-delay:.02s }
.ek-anim > *:nth-child(2){ animation-delay:.07s }
.ek-anim > *:nth-child(3){ animation-delay:.12s }
.ek-anim > *:nth-child(4){ animation-delay:.17s }
.ek-anim > *:nth-child(5){ animation-delay:.22s }
.ek-anim > *:nth-child(6){ animation-delay:.27s }
.ek-anim > *:nth-child(n+7){ animation-delay:.31s }

/* Las filas de una tabla entran igual, pero más rápido: son muchas y una
   cascada lenta se vuelve una espera. */
.ek-anim-filas tbody tr{ animation:ekIn .34s var(--ease) both; }
.ek-anim-filas tbody tr:nth-child(1){ animation-delay:.03s }
.ek-anim-filas tbody tr:nth-child(2){ animation-delay:.06s }
.ek-anim-filas tbody tr:nth-child(3){ animation-delay:.09s }
.ek-anim-filas tbody tr:nth-child(4){ animation-delay:.12s }
.ek-anim-filas tbody tr:nth-child(5){ animation-delay:.15s }
.ek-anim-filas tbody tr:nth-child(6){ animation-delay:.18s }
.ek-anim-filas tbody tr:nth-child(7){ animation-delay:.21s }
.ek-anim-filas tbody tr:nth-child(8){ animation-delay:.24s }
.ek-anim-filas tbody tr:nth-child(n+9){ animation-delay:.27s }

/* Esqueleto de carga. Dice «está viniendo» sin mentir con un número. */
@keyframes ekSk{ 0%{ background-position:200% 0 } 100%{ background-position:-200% 0 } }
.ek-sk{
  border-radius:5px; height:11px; display:block;
  background:linear-gradient(90deg,var(--sf3) 25%,var(--ln2) 37%,var(--sf3) 63%);
  background-size:200% 100%; animation:ekSk 1.3s linear infinite;
}

/* Profundidad al pasar el cursor. Una tarjeta que responde se siente viva;
   una que no, se siente una captura de pantalla. */
.ek-card, .glass-card{ transition:box-shadow var(--t) var(--ease), border-color var(--t) var(--ease); }
.ek-card:hover, .glass-card:hover{ box-shadow:var(--sh-open); border-color:var(--acc-bd); }
/* Las tarjetas que solo contienen un gráfico no reaccionan: el hover ahí
   compite con el tooltip de ECharts. */
.ek-card.ek-quieta:hover{ box-shadow:var(--sh-card); border-color:var(--ln); }

table.dt tbody tr{ transition:background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
table.dt tbody tr:hover{ box-shadow:inset 3px 0 0 var(--acc-bd); }

/* -------------------- 8b · Avatar de identidad ----------------------- */
/* El tono sale del NOMBRE (lo calcula ek_avatar() en PHP), así que la misma
   persona tiene siempre el mismo color. Es IDENTIDAD, no estado: por eso va
   desaturado y encerrado en un círculo, donde no compite con el punto de
   `.ek-est`. Nunca uses estos colores para comunicar una situación. */
/* Tinte claro de fondo, tinta oscura de la misma familia. El color y la
   tinta llegan en línea desde ek_avatar(); acá solo va la forma.
   Sin el aro blanco interior de antes: sobre un fondo claro no se veía y
   solo ensuciaba el borde. */
.ek-av{
  width:30px; height:30px; border-radius:50%; flex:none; display:grid; place-items:center;
  font-size:11px; font-weight:600; letter-spacing:.01em; position:relative;
}
/* Anillo de estado. El relleno dice QUIÉN es; el aro, CÓMO VA. Dos
   significados en el mismo objeto, separados por forma: uno es la masa y
   el otro el contorno. El color sale de --ek-aro, que pone ek_avatar()
   con los mismos tokens que el punto de `.ek-est`.

   `inset:-3px` deja un respiro entre el relleno y el aro: pegados se leen
   como un borde grueso del avatar y el estado deja de distinguirse.
   Por eso .ek-persona necesita su gap: el aro sobresale 3px. */
.ek-av-aro::after{
  content:''; position:absolute; inset:-3px; border-radius:50%;
  border:2px solid var(--ek-aro);
}
.ek-av-sm{ width:24px; height:24px; font-size:9.5px; }
.ek-av-lg{ width:42px; height:42px; font-size:14px; border-radius:12px; }
/* Persona en una celda: avatar + nombre + línea secundaria. */
.ek-persona{ display:flex; align-items:center; gap:10px; min-width:0; }
.ek-persona > div{ min-width:0; }

/* -------------------- 8c · Banda ilustrada del módulo ---------------- */
/* Ilustración vectorial PROPIA (assets/img/ilustracion-*.svg), no
   fotografía de stock: pesa 2 KB, escala sin perder y usa los azules de la
   casa. El SVG está dibujado a ≈7:1, la proporción de esta banda, para que
   `cover` no recorte ni la cruz ni la asamblea. */
.ek-hero{
  position:relative; overflow:hidden; border-radius:var(--r); margin-bottom:var(--gap);
  min-height:148px; display:flex; flex-direction:column; justify-content:flex-end;
  padding:16px 18px; color:#fff; background:linear-gradient(135deg,#0b1a3a,var(--nav));
}
/* Aurora de la banda (ago 2026): la misma idea de `.au-aurora` del login
   (docs commit b233552), trasplantada al componente sin tocar el marcado de
   las tres pantallas que lo usan —por eso son ::before/::after de `.ek-hero`
   y no <div> nuevos—. Dos manchas, no tres: son los únicos dos pseudo-
   elementos que un solo contenedor puede dar, y con el resto del banner ya
   ocupado (ilustración + texto) alcanza para leerse como aurora sin repetir
   el mismo ritmo dos veces.
   Más lenta y más tenue que en el login a propósito: ahí es la pantalla
   entera y se mira cinco segundos; acá es una franja encima de cifras y
   gráficos que alguien tiene delante mientras trabaja. Duraciones casi el
   doble (52s/64s contra 26s/34s) y una escala que apenas respira
   (1.05-1.06 contra 1.12-1.2). Tamaño en px y no en vmax: `.ek-hero` no
   es la ventana, es una tarjeta de ~150px de alto, así que escalar con el
   viewport la habría vuelto gigante o invisible según la pantalla. */
.ek-hero::before, .ek-hero::after{
  content:''; display:block; position:absolute; z-index:0; pointer-events:none;
  border-radius:50%; will-change:transform;
}
.ek-hero::before{
  /* ⚠️ El NÚCLEO de la mancha tiene que caer DENTRO de la banda, no fuera.
     La primera versión las anclaba en `top:-140px` sobre una franja de
     ~148px de alto: el centro quedaba por encima del borde y lo único que
     entraba era la cola del gradiente, al 16%. El resultado no era «sutil»,
     era invisible — se probó y no se veía nada. */
  width:420px; height:420px; left:-40px; top:-130px;
  background:radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--acc-nav) 22%, transparent) 0%, transparent 72%);
  animation:ekHeroAurora1 34s ease-in-out infinite;
}
.ek-hero::after{
  width:380px; height:380px; right:-30px; bottom:-120px;
  background:radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--renacer) 32%, transparent) 0%, transparent 72%);
  animation:ekHeroAurora2 42s ease-in-out infinite;
}
/* ⚠️ La amplitud también estaba mal: 2.2vw en 26 s son ~1,3 px por segundo,
   por debajo del umbral en que el ojo registra movimiento. Acá recorre una
   distancia comparable al alto de la banda, que es lo que la hace leerse
   como luz que se corre y no como una imagen quieta. */
@keyframes ekHeroAurora1{
  0%, 100%{ transform:translate3d(0,0,0) scale(1); }
  50%{ transform:translate3d(9vw,26px,0) scale(1.18); }
}
@keyframes ekHeroAurora2{
  0%, 100%{ transform:translate3d(0,0,0) scale(1); }
  50%{ transform:translate3d(-7vw,-22px,0) scale(1.14); }
}
.ek-hero-ilu{
  position:absolute; inset:0; width:100%; height:100%; z-index:1;
  object-fit:cover; object-position:center; pointer-events:none;
}
.ek-hero-k, .ek-hero-t, .ek-hero-s{ position:relative; z-index:2; }
.ek-hero-k{ font-family:var(--mono); font-size:10.5px; letter-spacing:.22em;
  text-transform:uppercase; color:var(--acc-nav); }
.ek-hero-t{ font-size:19px; font-weight:600; letter-spacing:-.02em; margin-top:5px;
  text-shadow:0 1px 12px rgba(7,17,41,.7); }
.ek-hero-s{ font-size:12.5px; color:rgba(255,255,255,.75); margin-top:3px;
  text-shadow:0 1px 10px rgba(7,17,41,.7); }

/* -------------------- 8d · Estado vacío ilustrado -------------------- */
.ek-vacio-art{ display:block; margin:0 auto 4px; width:112px; height:auto; }

/* -------------------- 8e · Ícono del KPI ----------------------------- */
/* El ícono es DEL DATO, no decorativo, y va en tinta apagada para no
   competir con la cifra —que sigue siendo lo que se lee—. */
.ek-kpi-lb{ display:flex; align-items:center; gap:8px; }
.ek-kpi-lb > i{ font-size:11px; color:var(--fnt); flex:none; }

/* -------------------- 8f · Usuario al pie del menú ------------------- */
/* Baja acá desde la barra superior. Reemplaza al `ekklesia.irenacer.cl`,
   que no le sirve a nadie que ya está adentro, y descarga la esquina
   superior derecha —la zona más apretada de la aplicación—. */
.ek-side-user{ flex:none; border-top:1px solid var(--nav-ln); padding:10px; position:relative; }
.ek-side-user-btn{
  width:100%; display:flex; align-items:center; gap:10px; padding:8px 9px;
  border:0; background:transparent; border-radius:var(--r-sm); cursor:pointer;
  text-align:left; font:inherit; transition:background var(--t-fast) var(--ease);
}
.ek-side-user-btn:hover{ background:var(--nav-hov); }
.ek-side-user-av{
  width:32px; height:32px; border-radius:9px; flex:none; display:grid; place-items:center;
  font-size:11.5px; font-weight:600; color:#fff; background:var(--acc);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.18);
}
.ek-side-user-tx{ min-width:0; flex:1; }
/* `display:block` explícito: son <span>, y en línea el rol se pegaba al
   nombre en la misma fila en vez de quedar debajo. */
.ek-side-user-nm{ display:block; font-size:12.5px; font-weight:500; color:#fff; line-height:1.25;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ek-side-user-rl{ display:block; font-size:10.5px; color:var(--nav-grp); line-height:1.3;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ek-side-user-btn > .fa-chevron-up{ font-size:9px; color:var(--nav-grp); flex:none; }

/* "Ver como" activo (§4 del spec de roles múltiples): franja de aviso
   PERMANENTE mientras dure la simulación, para que se note aunque el
   desplegable esté cerrado. Reusa los tokens de estado ámbar —no es un
   color nuevo, es "esto es un modo especial", el mismo semántico que ya
   usa el resto del sistema para una alerta suave. */
.ek-side-user-verComo{
  display:flex;align-items:center;gap:6px;
  padding:6px 10px;margin:0 8px 4px;border-radius:8px;
  background:var(--warn-sf);border:1px solid var(--warn-bd);
  color:var(--warn);font-size:12px;font-weight:600;text-decoration:none;
}
.ek-side-user-verComo:hover{filter:brightness(0.96)}

/* Al estar abajo, el desplegable abre HACIA ARRIBA. Sin esto el menú se
   dibuja fuera de la ventana y no se ve nada. */
.ek-menu.ek-arriba{ top:auto; bottom:calc(100% + 9px); right:10px; left:10px; width:auto; }

/* -------------------- 8f-bis · La barra superior --------------------- */
/* GRID de tres pistas y no flex: `auto 1fr auto` deja el título a la
   izquierda, la búsqueda centrada de verdad y las acciones pegadas al
   borde derecho, a cualquier ancho.

   ⚠️ Con flex quedaban 132px muertos a la derecha: la búsqueda tenía
   `flex:1` con tope de 420px, así que dejaba de crecer y el sobrante no
   se lo llevaba nadie — el grupo de acciones flotaba a media barra en vez
   de anclarse. Un `margin-left:auto` lo tapa, pero entonces la búsqueda
   deja de estar centrada respecto de la ventana. El grid resuelve las dos
   cosas sin pelearse. */
/* ⚠️ Se llama `.ek-bar-top` y NO `.ek-bar` porque esa clase ya era la barra
   de avance de la sección 4 (stock, cupos, compromisos). Con el mismo nombre,
   esta regla —que va después— le imponía `display:grid`, `padding`, un
   `border-bottom` y `background:var(--sf)`: la pista gris de TODAS las barras
   de avance del sistema desaparecía y quedaban lavadas. El alto no se notaba
   porque ek_barra() lo escribe inline. */
.ek-bar-top{
  /* `minmax(0,…)` en las dos primeras pistas: sin eso, cuando el ancho
     aprieta, la pista `auto` de la izquierda se encoge hasta su min-content
     y el título quedaba reducido a una letra mientras la búsqueda seguía
     en sus 420px. Con minmax(0,1fr) la que cede es la búsqueda, que es lo
     prescindible; el camino y el título mandan. Bajo 1280px la búsqueda
     desaparece del todo (clase `xl:flex` en el marcado).

     ⚠️ La tercera pista (avisos + acción del módulo) NO puede quedar en
     `auto` a secas. Con un título largo (el nombre de un curso sin
     truncar, por ejemplo) la pista 1 pide más de lo que hay disponible y
     el navegador termina asignándole 0px a la tercera pista — su
     mínimo de contenido (`auto`/`min-content`) NO se respeta cuando el
     grid está sobre-exigido, aunque el spec diga que debería. La campanita
     y el botón de acción se siguen dibujando a su ancho fijo porque nadie
     les recorta el overflow, así que quedan fuera del viewport: invisibles
     y sin poder tocarlos. Un mínimo EXPLÍCITO en píxeles sí se respeta —
     por eso las tres pistas de abajo, calculadas contra lo que esa
     tercera pista realmente puede llegar a contener en cada quiebre
     (campanita sola · +texto del botón desde `sm` · +ámbito desde `md`,
     los mismos puntos que ya usa el marcado con `sm:inline`/`md:flex`). */
  /* 88px alcanzaba cuando la barra tenía una sola campanita. Después fueron
     TRES controles de 34px (sobre, avisos y ayuda) más sus separaciones de
     9px = 120px.
     ⚠️ Y esa cuenta OLVIDÓ el botón de acción del módulo, que vive en la
     misma pista: son 40px más su separación. Medido en una pantalla con
     acción a 375px, la pista pedía 169px y recibía 0 — el botón terminaba a
     396px, o sea 21px fuera de la ventana: el ÚNICO botón lleno de la
     pantalla, invisible y sin poder tocarse en un teléfono.
     172 = 3×34 + 40 + 4×9 de separación, con un píxel de holgura. */
  display:grid; grid-template-columns:minmax(0,auto) minmax(0,1fr) minmax(172px,auto);
  align-items:center;
  gap:14px; height:var(--top-h); padding:0 var(--pad);
  background:var(--sf); border-bottom:1px solid var(--ln);
}
@media (min-width:640px){
  /* Desde 640px el botón muestra su texto (`sm:inline`), así que la pista
     crece con él: 210 cubría los tres íconos + un rótulo corto. */
  .ek-bar-top{ grid-template-columns:minmax(0,auto) minmax(0,1fr) minmax(260px,auto); }
}
@media (min-width:768px){
  .ek-bar-top{ grid-template-columns:minmax(0,auto) minmax(0,1fr) minmax(450px,auto); }
}
.ek-bar-l{ display:flex; align-items:center; gap:11px; min-width:0; }
.ek-bar-r{ display:flex; align-items:center; gap:9px; }
/* Dentro del grid, `flex:1` de .ek-buscar NO aplica —el elemento es item de
   grid, no de flex— y el botón se encogía a su contenido (176px). El ancho
   lo fija la pista, con el mismo tope de 420. */
.ek-bar-top .ek-buscar{ justify-self:center; width:100%; max-width:420px; }

/* La marca del software. Dentro de la aplicación vive acá y en ningún otro
   sitio: en el menú manda el logo de la iglesia, y el del sistema no compite
   con ese. Su otra aparición es la hoja blanca de las pantallas de acceso
   (`.au-app` en ekklesia-auth.css), con el mismo dibujo y la misma voz —
   mono, espaciado, discreto—: el símbolo pone el peso y la palabra acompaña. */
.ek-app{
  display:flex; align-items:center; gap:0; flex:none; text-decoration:none;
}
.ek-marca{ display:block; flex:none; }
.ek-app-tx{
  font-family:var(--mono); font-size:11.5px; font-weight:500; letter-spacing:.2em;
  text-transform:uppercase; color:var(--acc); white-space:nowrap;
  /* El hueco no viene del `gap` sino del aire interno del viewBox: el trazo
     no llega al borde del SVG. Se compensa acá para que «ϵ» y «kklesia»
     queden pegadas y el bloque se lea como UNA palabra, que es todo el
     sentido de esta marca. */
  margin-left:-2px;
}
.ek-app:hover .ek-app-tx{ color:var(--renacer-hover); }
.ek-bar-div{ width:1px; height:22px; background:var(--ln); flex:none; }

/* Migas de pan. Sustituyen al bloque de dos líneas (rótulo + título): el
   rótulo del módulo era texto muerto y ahora se puede volver a él. */
.ek-migas{ display:flex; align-items:center; gap:8px; min-width:0; }
.ek-migas > i{ font-size:8px; color:var(--fnt); flex:none; }
.ek-migas a, .ek-migas > span{
  font-size:12.5px; color:var(--mut); text-decoration:none; white-space:nowrap; flex:none;
  transition:color var(--t-fast) var(--ease);
}
.ek-migas a:hover{ color:var(--acc); }
/* El último nivel ES el <h1>: sigue siendo el título de la pantalla, solo
   que en línea con su camino en vez de encima de él. */
.ek-miga-hoy{
  margin:0; font-size:16.5px; font-weight:600; letter-spacing:-.02em; color:var(--ink);
  line-height:1.3; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0;
}
/* En pantallas chicas sobra el camino: manda dónde estás. */
@media (max-width:900px){
  .ek-migas > i, .ek-migas a, .ek-migas > span{ display:none; }
  .ek-migas > i:last-of-type, .ek-miga-hoy{ display:block; }
  .ek-migas > i:last-of-type{ display:none; }
}

/* -------------------- 8g · Ámbito (selector de campus) --------------- */
/* Es el FILTRO MAESTRO de toda la aplicación, así que tiene que parecerlo.
   Antes era un <select> nativo de 150×17px dentro de una caja: se veía
   diminuto, con la flecha del sistema operativo, y «Campus Renacer
   Santiago» no cabía. */
.ek-ambito{
  display:flex; align-items:center; gap:8px; height:34px; padding:0 10px 0 11px;
  background:var(--sf2); border:1px solid var(--ln); border-radius:var(--r-sm);
  transition:border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.ek-ambito:hover{ border-color:var(--acc-bd); background:var(--sf); }
.ek-ambito:focus-within{ border-color:var(--acc); background:var(--sf);
  box-shadow:0 0 0 3px rgba(14,42,99,.10); }
.ek-ambito > i{ color:var(--acc); font-size:11.5px; flex:none; }
.ek-ambito select{
  appearance:none; -webkit-appearance:none;   /* fuera la flecha del sistema */
  border:0; background:transparent; outline:none; cursor:pointer;
  font:inherit; font-size:13px; font-weight:500; color:var(--ink);
  height:100%; padding:0 2px 0 0; max-width:210px;
  text-overflow:ellipsis;
}
/* La flecha, dibujada por nosotros para que siga a los tokens. */
.ek-ambito::after{
  content:"\f078"; font-family:"Font Awesome 6 Free"; font-weight:900;
  font-size:9px; color:var(--fnt); pointer-events:none; flex:none;
}

/* La flecha de .ek-ambito::after existía para tapar la nativa del
   <select> de antes. El botón nuevo no tiene <select> — trae su propio
   <i class="fas fa-chevron-down"> real — así que se apaga sólo para él;
   el <div> de una sola sede (.ek-ambito-fijo) no se toca y conserva el
   comportamiento de siempre. */
.ek-ambito-btn::after{ content:none; }

.ek-ambito-wrap{ position:relative; }
/* Todo lo interactivo vive en .ek-ambito-btn, NUNCA en .ek-ambito a
   secas: esa clase la comparte el <div> estático de una sola sede, que
   no es clicable y no lleva flecha ni chevron.

   ⚠️ NO reiniciar aquí `border`/`padding`/`background`: esos ya los pone
   `.ek-ambito` (sin tocar) y una regla de autor siempre le gana al
   estilo nativo del navegador para un <button>, sea cual sea el orden —
   repetirlos acá sólo arriesga pisar por accidente lo que la clase
   compartida ya resuelve para las dos variantes. Lo único propio de un
   `<button>` que hace falta neutralizar es que herede la tipografía. */
.ek-ambito-btn{
  cursor:pointer; font:inherit; text-align:left;
  transition:border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.ek-ambito-btn:hover{ border-color:var(--acc-bd); background:var(--sf); }
.ek-ambito-btn:focus-visible{ border-color:var(--acc); background:var(--sf);
  box-shadow:0 0 0 3px rgba(14,42,99,.10); outline:none; }
.ek-ambito-btn > i:first-child{ color:var(--acc); font-size:11.5px; flex:none; }
.ek-ambito-btn > i:last-child{ color:var(--fnt); font-size:9px; flex:none; margin-left:2px; }
/* El texto: «Campus Renacer» apagado y chico sobre el nombre de la sede,
   fuerte y más grande — el mismo texto completo de siempre (CLAUDE.md
   exige el nombre íntegro), sólo con jerarquía. En una sola línea porque
   la caja mide 34px de alto: dos líneas no caben. */
.ek-ambito-tx{ display:flex; align-items:baseline; gap:5px; min-width:0;
  max-width:190px; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
.ek-ambito-tx small{ font-size:10px; font-weight:500; color:var(--fnt);
  text-transform:uppercase; letter-spacing:.02em; flex:none; }
.ek-ambito-tx b{ font-size:13.5px; font-weight:600; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; }

/* El desplegable: mismas reglas que .ek-menu (position/ancho/sombra), acá
   sólo lo que es propio de esta variante. */
.ek-ambito-menu a{ display:flex; align-items:center; justify-content:space-between;
  gap:10px; padding:9px 11px; border-radius:var(--r-sm);
  text-decoration:none; }
.ek-ambito-menu a:hover{ background:var(--sf3); }
.ek-ambito-menu a.on{ background:var(--acc-sf); }
.ek-ambito-menu a span{ display:flex; align-items:baseline; gap:5px; min-width:0; }
.ek-ambito-menu a small{ font-size:10px; font-weight:500; color:var(--fnt);
  text-transform:uppercase; letter-spacing:.02em; flex:none; }
.ek-ambito-menu a b{ font-size:13.5px; font-weight:500; color:var(--ink);
  overflow:hidden; text-overflow:ellipsis; }
.ek-ambito-menu a.on b{ color:var(--acc); font-weight:600; }
.ek-ambito-menu a i{ color:var(--acc); font-size:11px; flex:none; }

/* -------------------- 8g-ter · Barra de guardado por lote ------------
   Para las pantallas donde se marcan varias casillas y se confirma al
   final (Gestión de roles). Va FIJA al pie del área de trabajo: la matriz
   mide más de una pantalla de alto, y un botón al final de la tabla
   obliga a bajar 300 filas para confirmar lo que se marcó arriba.

   Se apoya sobre la barra de estado (--bot-h), no encima: esa barra
   OCUPA, no flota, así que taparla escondería el reloj y el cronómetro
   de sesión. */
.ek-guardar-bar{
  position:fixed; left:var(--side-w); right:0; bottom:var(--bot-h);
  z-index:var(--z-nav);
  display:flex; align-items:center; justify-content:flex-end; gap:12px;
  padding:10px 24px;
  background:var(--sf); border-top:1px solid var(--ln);
  box-shadow:0 -6px 20px -12px rgba(7,17,41,.25);
}
.ek-guardar-tx{ margin-right:auto; font-size:12.5px; color:var(--ink2); font-weight:500;
  display:flex; align-items:center; gap:7px; }
.ek-guardar-tx i{ font-size:8px; color:var(--warn); }
.ek-oculto{ display:none !important; }
@media (max-width:900px){ .ek-guardar-bar{ left:0; } }

/* La celda con un cambio sin guardar. Ámbar y no verde: no está hecho,
   está pendiente — el verde diría que ya quedó guardado. */
.ek-celda-suc{ background:var(--warn-sf); box-shadow:inset 0 0 0 1px var(--warn-bd); }

/* Ámbito FIJO: quien alcanza una sola sede la ve como dato, no como
   control — un <select> con una sola opción invita a buscar las otras.
   Mismo lugar y peso que el selector, sin afordancia: sin flecha, sin
   hover, sin foco. */
.ek-ambito-fijo{ cursor:default; }
.ek-ambito-fijo::after{ content:none; }
.ek-ambito-fijo:hover{ border-color:var(--ln); background:var(--sf2); }
.ek-ambito-fijo span{
  font-size:13px; font-weight:500; color:var(--ink2);
  max-width:210px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

/* -------------------- 8g-bis · Búsqueda ancha en la barra ------------ */
/* Antes era un ícono que abría ⌘K. Un atajo que no se ve no lo descubre
   nadie: ahora el campo se ve, dice qué busca y muestra el atajo. */
.ek-buscar{
  flex:1; max-width:420px; display:flex; align-items:center; gap:9px; height:34px;
  padding:0 11px; background:var(--sf2); border:1px solid var(--ln);
  border-radius:var(--r-sm); color:var(--mut); font:inherit; font-size:12.5px;
  cursor:text; text-align:left;
  transition:border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.ek-buscar:hover{ border-color:var(--acc-bd); background:var(--sf); }
.ek-buscar .tx{ flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ek-buscar kbd{
  font-family:var(--mono); font-size:10px; padding:2px 5px; border:1px solid var(--ln);
  border-radius:4px; background:var(--sf); color:var(--fnt); flex:none;
}

/* -------------------- 8h · Acción del módulo en la barra ------------- */
/* «Nueva solicitud», «Registrar visita»… vivían dentro de la tarjeta y se
   perdían al hacer scroll. Acá están siempre, y de paso queda UN solo
   botón lleno por pantalla, que es la regla de la casa. */
.ek-bar-cta{
  display:inline-flex; align-items:center; gap:8px; height:34px; padding:0 14px;
  background:var(--acc); color:var(--acc-ink); border:1px solid transparent;
  border-radius:var(--r-sm); font:inherit; font-size:13px; font-weight:500;
  text-decoration:none; cursor:pointer; white-space:nowrap;
  transition:background var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.ek-bar-cta:hover{ background:var(--renacer-hover); }
.ek-bar-cta:active{ transform:translateY(1px); }
.ek-bar-cta i{ font-size:11px; }
/* Deshabilitado: la acción sigue a la vista —dice por qué no se puede
   todavía, en vez de desaparecer— pero no reacciona al clic ni al hover. */
.ek-bar-cta:disabled{ opacity:.45; cursor:default; }
.ek-bar-cta:disabled:hover{ background:var(--acc); }

/* -------------------- 8i · Menos movimiento ------------------------- */
/* No es opcional ni un extra de accesibilidad: quien marcó esta preferencia
   en su sistema suele hacerlo por mareo o migraña. */
@media (prefers-reduced-motion:reduce){
  .ek-anim > *, .ek-anim-filas tbody tr{ animation:none; }
  .ek-sk{ animation:none; }
  .ek-card, .glass-card, table.dt tbody tr, .ek-bar-cta,
  .ek-buscar, .ek-side-user-btn{ transition:none; }
  .ek-bar-cta:active{ transform:none; }
  /* La aurora de la banda queda fija en su primer cuadro (0%), que ya es
     un estado legible por sí solo: no es un cuadro a mitad de transición. */
  .ek-hero::before, .ek-hero::after{ animation:none; }
  /* ⚠️ La barra del fondo (.dw-fondo-bar) NO se apaga acá aunque sea el
     bloque compartido: sus reglas de animación viven en la sección 8k, que
     va DESPUÉS de ésta en el archivo. Con el mismo selector y la misma
     especificidad manda el ORDEN DE DECLARACIÓN, así que el override
     quedaba pisado por la animación y la barra se movía igual. Su apagado
     está al final de 8l, después de lo que tiene que ganar. */
}

@media (max-width:900px){
  /* En el teléfono la banda ilustrada compite con el trabajo. */
  .ek-hero{ min-height:112px; }
  .ek-hero-t{ font-size:16.5px; }
  .ek-hero-s{ display:none; }
}

/* ---- 7 · Normalización de utilidades Tailwind heredadas ----
   Las pantallas anteriores traen utilidades del look antiguo escritas en el
   marcado (`font-black`, `text-[#003399]`, `bg-blue-100`, `uppercase`…).
   Mientras se van limpiando pantalla por pantalla, este bloque las alinea
   con el lenguaje sobrio. Es deuda declarada, no diseño: cuando una
   pantalla quede migrada a las clases de arriba, deja de necesitarlo.
   Los `!important` son para ganarle a esas utilidades y están acotados
   a este bloque. */
.glass-card .font-black:not(button):not(.text-white),
.glass-card .font-black.text-lg,
table.dt td .font-black:not(button):not(.text-white){
  font-weight:600 !important; color:var(--ink) !important; letter-spacing:-.01em; }
.glass-card .text-2xl.font-black, .glass-card .text-3xl.font-black{
  font-family:var(--mono); font-weight:500 !important; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums; }
button.btn-primary, a.btn-primary, button.btn-primary *{ color:var(--acc-ink) !important; }
/* Las pantallas viejas escriben el azul de marca a mano (89 veces
   `text-[#003399]`). Se remapean al acento para que no queden dos azules
   distintos mientras se migran. */
[class*="text-[#003399]"]{ color:var(--acc) !important; }
[class*="bg-[#003399]"]{ background:var(--acc) !important; }
[class*="border-[#003399]"]{ border-color:var(--acc) !important; }
button, .btn, .btn-primary, .btn-secondary{ text-transform:none !important; letter-spacing:0 !important; }
[class*="bg-slate-200"], [class*="bg-slate-100"].btn-secondary{
  background:var(--sf) !important; border:1px solid var(--ln) !important; color:var(--ink2) !important; }
[class*="bg-rose-100"]:not(.chip){ background:var(--sf) !important; border:1px solid #fecdd3 !important;
  color:var(--danger) !important; }
/* Los chips de color heredados pasan a punto de estado + fondo neutro. */
.chip[class*="bg-emerald"]{ --dot:var(--ok); }
.chip[class*="bg-amber"]{ --dot:var(--warn); }
.chip[class*="bg-rose"]{ --dot:var(--danger); }
.chip[class*="bg-blue"], .chip[class*="bg-indigo"]{ --dot:var(--acc); }
.chip[class*="bg-purple"], .chip[class*="bg-violet"]{ --dot:var(--purple); }
.chip[class*="bg-"]{ background:var(--sf) !important; border:1px solid var(--ln) !important;
  color:var(--ink2) !important; }

/* --- 8k · La barra del fondo de Donaciones Web -----------------------
 * Una sola figura contesta a la vez cuánto entró, cuánto queda, dónde
 * está lo que queda y cuánto ya se convirtió en comida.
 *
 * ⚠️ SE LLAMA .dw-fondo-bar Y NO .ek-bar. Ese nombre ya es el de la barra
 * de avance de la sección 4, y esta regla —que va después— le impondría
 * su fondo y su alto a TODAS las barras de stock del sistema: quedarían
 * lavadas sin que nada parezca roto. Misma trampa que .ek-bar-top,
 * .ek-bar-bot y .ek-authapp.
 *
 * ⚠️ Los tres tonos son ESTADO, no categoría ni decoración: dicen en qué
 * estado está ese dinero. Y «gastado» va en --ok a propósito — en este
 * ministerio gastar la plata ES LA META, no una fuga; en rojo contaría
 * la historia al revés.
 */
.dw-fondo-cifra{ font-family:var(--mono); font-variant-numeric:tabular-nums;
  font-size:34px; font-weight:700; color:var(--ink); line-height:1.1; }
.dw-fondo-bar{ display:flex; height:44px; border-radius:var(--r);
  overflow:hidden; background:var(--sf2); border:1px solid var(--ln);
  margin-top:14px; }
.dw-fondo-bar > span{ display:block; min-width:0;
  transition:width .6s cubic-bezier(.2,.7,.3,1); }
.dw-fondo-bar .s-linea{ background:var(--acc); }
.dw-fondo-bar .s-caja{ background:var(--warn); }
.dw-fondo-bar .s-gasto{ background:var(--ok); }

/* ⚠️ El color no puede ser la única señal: los tres montos van escritos
 * con su rótulo SIEMPRE, entren o no dentro de su segmento. */
.dw-fondo-ley{ display:flex; flex-wrap:wrap; gap:8px 22px; margin-top:12px; }
.dw-fondo-ley > div{ display:flex; align-items:center; gap:7px; font-size:12.5px;
  color:var(--ink2); }
.dw-fondo-ley i{ width:9px; height:9px; border-radius:3px; flex-shrink:0; }
.dw-fondo-ley .s-linea{ background:var(--acc); }
.dw-fondo-ley .s-caja{ background:var(--warn); }
.dw-fondo-ley .s-gasto{ background:var(--ok); }
.dw-fondo-ley b{ font-family:var(--mono); font-variant-numeric:tabular-nums;
  color:var(--ink); font-weight:600; }

/* La entrada: los tres segmentos crecen desde cero al cargar. Es la
 * modernidad por movimiento que pide la dirección «B», sin color nuevo. */
@keyframes dwFondoEntra{ from{ transform:scaleX(0); } to{ transform:scaleX(1); } }
.dw-fondo-bar > span{ transform-origin:left center; animation:dwFondoEntra .7s
  cubic-bezier(.2,.7,.3,1) both; }
.dw-fondo-bar > span:nth-child(2){ animation-delay:.08s; }
.dw-fondo-bar > span:nth-child(3){ animation-delay:.16s; }

/* --- 8l · La cartola del fondo -------------------------------------- */
.dw-cartola td.num{ font-family:var(--mono); font-variant-numeric:tabular-nums;
  text-align:right; white-space:nowrap; }
.dw-cartola .entra{ color:var(--ok); }
.dw-cartola .sale{ color:var(--ink); }
.dw-cartola .saldo{ color:var(--ink2); font-weight:600; }
/* ⚠️ El movimiento anulado NO se esconde: el error también es historia.
 * Va tachado y apagado, con su motivo al lado. */
.dw-cartola tr.anulada td{ color:var(--mut); text-decoration:line-through; }
.dw-cartola tr.anulada .ek-sb{ text-decoration:none; }
.dw-cartola .ico{ width:22px; text-align:center; color:var(--mut); }

/* ⚠️ EL ÚNICO `prefers-reduced-motion` DEL ARCHIVO QUE NO REUSA EL BLOQUE
 * COMPARTIDO DE 8i, Y VA ACÁ POR ORDEN DE DECLARACIÓN. Todos los demás
 * apagados viven juntos en 8i, que es lo correcto salvo para esto: 8i se
 * declara ANTES que 8k, donde `.dw-fondo-bar > span` recibe su
 * `animation:dwFondoEntra` y su `transition:width`. Mismo selector y misma
 * especificidad ⇒ gana la declaración POSTERIOR, así que el apagado escrito
 * en 8i lo pisaba la animación y la barra se movía igual para quien pidió
 * que no se moviera nada. Puesto después de 8k y 8l, gana.
 *   Si algún día la barra del fondo se muda antes de 8i, esto vuelve al
 *   bloque compartido y este comentario sobra. */
@media (prefers-reduced-motion:reduce){
  .dw-fondo-bar > span{ animation:none; transition:none; }
}

/* =====================================================================
   9 · CALENDARIO

   Grilla mensual con hasta 3 franjas de texto por día (el título de
   cada elemento, coloreado por su capa — estilo Google Calendar; ver
   docs/superpowers/specs/2026-08-02-calendario-franjas-design.md). Un
   4º elemento pasa a «+N más» en vez de franja propia. El detalle del
   día vive en el riel estándar (.ek-rail), armado en JS desde un JSON
   ya embebido en la página: no hay fetch nuevo para abrir un día.
   ===================================================================== */
.ek-cal-cab{ display:flex; align-items:center; justify-content:space-between;
  gap:12px; flex-wrap:wrap; margin-bottom:var(--gap); }
.ek-cal-nav{ display:flex; align-items:center; gap:6px; }
.ek-cal-mes{ font-family:var(--mono); font-size:14px; font-weight:500;
  color:var(--ink); min-width:150px; text-align:center; }

.ek-chips-capa{ display:flex; flex-wrap:wrap; gap:8px; margin-bottom:var(--gap); }
.ek-chip-capa{ display:inline-flex; align-items:center; gap:6px;
  font-family:var(--sans); font-size:12px; padding:5px 11px; border-radius:20px;
  border:1px solid var(--ln); background:var(--sf); color:var(--ink2);
  text-decoration:none; transition:opacity var(--t-fast) var(--ease); }
.ek-chip-capa.off{ opacity:.45; }
.ek-chip-capa .pt{ width:7px; height:7px; border-radius:50%; display:inline-block; }
.ek-chip-capa[data-capa="curso"] .pt{ background:var(--acc); }
.ek-chip-capa[data-capa="recordatorio"] .pt{ background:var(--ok); }
.ek-chip-capa[data-capa="seguimiento"] .pt{ background:var(--warn); }
.ek-chip-capa[data-capa="actividad"] .pt{ background:var(--purple); }

.ek-cal-grid{ display:grid; grid-template-columns:repeat(7,1fr);
  border:1px solid var(--ln); border-radius:var(--r); overflow:hidden;
  background:var(--ln2); gap:1px; }
.ek-cal-dow{ background:var(--sf2); color:var(--mut); font-size:11px;
  text-transform:uppercase; letter-spacing:.02em; text-align:center; padding:8px 0; }
.ek-cal-dia{ background:var(--sf); min-height:96px; padding:6px 8px;
  cursor:pointer; transition:background var(--t-fast) var(--ease); border:none;
  text-align:left; display:flex; flex-direction:column; gap:4px; width:100%; }
.ek-cal-dia:hover{ background:var(--sf3); }
.ek-cal-dia:disabled, .ek-cal-fuera{ cursor:default; background:var(--sf2); }
.ek-cal-dia:disabled:hover{ background:var(--sf2); }
.ek-cal-dia-n{ font-family:var(--mono); font-size:12.5px; color:var(--ink2); }
.ek-cal-fuera .ek-cal-dia-n{ color:var(--fnt); }
.ek-cal-hoy .ek-cal-dia-n{ color:var(--acc-ink); background:var(--acc);
  width:20px; height:20px; border-radius:50%; display:flex; align-items:center;
  justify-content:center; }
.ek-cal-franjas{ display:flex; flex-direction:column; gap:2px; margin-top:2px; min-width:0; }
.ek-cal-franja{ font-family:var(--sans); font-size:10.5px; line-height:1.4; padding:1px 5px;
  border-radius:3px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ek-cal-franja.curso{ background:var(--acc-sf); color:var(--acc); }
.ek-cal-franja.recordatorio{ background:rgba(6,122,85,.12); color:var(--ok); }
.ek-cal-franja.seguimiento{ background:rgba(180,83,9,.12); color:var(--warn); }
.ek-cal-franja.actividad{ background:rgba(109,40,217,.12); color:var(--purple); }
.ek-cal-mas{ font-size:10.5px; color:var(--mut); font-family:var(--mono); padding:0 5px; }

.ek-cal-item{ border-left:3px solid var(--ln); padding:7px 10px; border-radius:0 7px 7px 0;
  background:var(--sf2); margin-bottom:8px; }
.ek-cal-item.curso{ border-color:var(--acc); }
.ek-cal-item.recordatorio{ border-color:var(--ok); }
.ek-cal-item.seguimiento{ border-color:var(--warn); }
.ek-cal-item.actividad{ border-color:var(--purple); }
.ek-cal-item .tp{ font-size:10.5px; text-transform:uppercase; color:var(--mut); }

@media (max-width:640px){
  .ek-cal-dia{ min-height:64px; }
}

/* =====================================================================
   10 · MOTOR DE AYUDA
 * Motor de Ayuda — contenido del riel (§4 y §6 de la spec). Reusa los
 * tokens de estado existentes: --ok para "tip", --warn para "aviso". No
 * hay tokens de color dedicados a tipos de ayuda — inventar unos nuevos
 * para dos cajas de color duplicaría la semántica que ya tienen .ek-est.
 * Los tintes rgba(6,122,85,.10) / rgba(180,83,9,.10) son los mismos que
 * ya usa .ek-aviso-ic para "ok"/"warn": no son un color nuevo, son el
 * mismo tinte de insignia que el resto de la aplicación.
 *
 * "Moderno" acá entra por movimiento y jerarquía, nunca por color nuevo
 * (regla del proyecto): el contenido entra en cascada con el mismo
 * keyframe `ekIn` que usa .ek-anim en el resto de la app, los pasos se
 * leen como una línea de tiempo con insignias numeradas, y el reproductor
 * tiene profundidad (brillo, anillos, ecualizador con resplandor) sin
 * salirse del acento único --acc.
 * ===================================================================== */
.ek-ayuda-desc{ font-size:13px; color:var(--mut); line-height:1.5; margin:0 0 14px; }

/* El cuerpo entra en cascada al abrir el riel — mismo lenguaje que
 * .ek-anim, acotado a esta pantalla para no tocar el resto de rieles. */
.ek-ayuda-cuerpo > *{ animation:ekIn .38s var(--ease) both; }
.ek-ayuda-cuerpo > *:nth-child(1){ animation-delay:.02s }
.ek-ayuda-cuerpo > *:nth-child(2){ animation-delay:.07s }
.ek-ayuda-cuerpo > *:nth-child(3){ animation-delay:.12s }
.ek-ayuda-cuerpo > *:nth-child(4){ animation-delay:.17s }
.ek-ayuda-cuerpo > *:nth-child(n+5){ animation-delay:.21s }

/* Pasos: línea de tiempo con insignias numeradas en vez de una lista
 * plana — la secuencia se lee de un vistazo, no solo se enumera. */
.ek-ayuda-pasos{
  list-style:none; counter-reset:ekpaso; margin:0 0 18px; padding:0;
  font-size:13px; line-height:1.55; position:relative;
}
.ek-ayuda-pasos li{
  counter-increment:ekpaso; position:relative; padding:1px 0 16px 34px; color:var(--ink2);
}
.ek-ayuda-pasos li:last-child{ padding-bottom:0; }
.ek-ayuda-pasos li::before{
  content:counter(ekpaso); position:absolute; left:0; top:-1px; width:22px; height:22px;
  border-radius:99px; background:var(--acc-sf); color:var(--acc); border:1px solid var(--acc-bd);
  font:600 11px/20px var(--mono); text-align:center; z-index:1;
}
.ek-ayuda-pasos li:not(:last-child)::after{
  content:''; position:absolute; left:11px; top:22px; bottom:0; width:1px; background:var(--ln);
}

/* FAQ: acordeón con ícono en insignia circular (mismo patrón que
 * .ek-aviso-ic) y una franja de foco/hover que separa cada pregunta. */
.ek-ayuda-faq{ margin-bottom:16px; border:1px solid var(--ln); border-radius:var(--r); overflow:hidden; }
.ek-ayuda-faq-it{ border-bottom:1px solid var(--ln); }
.ek-ayuda-faq-it:last-child{ border-bottom:0; }
.ek-ayuda-faq-p{
  display:flex; align-items:center; justify-content:space-between; gap:10px; width:100%;
  background:none; border:0; padding:11px 12px; font:inherit; font-size:13px;
  font-weight:500; color:var(--ink); cursor:pointer; text-align:left;
  transition:background var(--t-fast) var(--ease);
}
.ek-ayuda-faq-p:hover, .ek-ayuda-faq-p:focus-visible{ background:var(--sf2); }
.ek-ayuda-faq-ic{
  flex:none; width:20px; height:20px; border-radius:99px; display:grid; place-items:center;
  background:var(--sf3); color:var(--fnt); font-size:9.5px;
  transition:transform var(--t-slow) var(--ease), background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.ek-ayuda-faq-it.ek-open .ek-ayuda-faq-p{ background:var(--acc-sf); }
.ek-ayuda-faq-it.ek-open .ek-ayuda-faq-ic{ transform:rotate(180deg); background:var(--acc); color:var(--acc-ink); }
.ek-ayuda-faq-r{
  display:grid; grid-template-rows:0fr; transition:grid-template-rows var(--t-slow) var(--ease);
}
.ek-ayuda-faq-it.ek-open .ek-ayuda-faq-r{ grid-template-rows:1fr; }
.ek-ayuda-faq-in{
  overflow:hidden; min-height:0; font-size:12.5px; color:var(--mut); line-height:1.55;
  padding:0 12px;
}
.ek-ayuda-faq-it.ek-open .ek-ayuda-faq-in{ padding:0 12px 13px; }

/* Tip/aviso: insignia de ícono a la SIGE-.ek-aviso, con entrada propia y
 * un leve realce al pasar el mouse — sigue siendo tinta de estado, no
 * decoración: el color de la insignia es el mismo que ya lee "va bien" o
 * "atención" en el resto de la aplicación. */
.ek-ayuda-caja{
  display:flex; flex-direction:column; gap:2px; padding:4px 12px;
  border-radius:var(--r); font-size:12.5px; line-height:1.5; margin-bottom:10px;
  background:var(--sf); border:1px solid var(--ln); border-left:3px solid var(--ok);
  box-shadow:var(--sh-card); transition:box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.ek-ayuda-caja:hover{ box-shadow:var(--sh-open); transform:translateY(-1px); }
.ek-ayuda-caja.aviso{ border-left-color:var(--warn); }
.ek-ayuda-caja-row{ display:flex; gap:10px; align-items:flex-start; padding:9px 0; }
.ek-ayuda-caja-row + .ek-ayuda-caja-row{ border-top:1px dashed var(--ln2); }
.ek-ayuda-caja-ic{
  flex:none; width:24px; height:24px; margin-top:1px; border-radius:99px;
  display:grid; place-items:center; font-size:11.5px;
  background:rgba(6,122,85,.10); color:var(--ok);
}
.ek-ayuda-caja.aviso .ek-ayuda-caja-ic{ background:rgba(180,83,9,.10); color:var(--warn); }
.ek-ayuda-caja-tx{ color:var(--ink2); padding-top:2px; }

/* El `?` inline de un concepto (§3.3): junto a una etiqueta, discreto. */
.ek-ayuda-c{
  display:inline-flex; align-items:center; justify-content:center; width:16px; height:16px;
  border:0; background:none; padding:0; margin-left:4px; color:var(--fnt); cursor:pointer;
  font-size:11px; vertical-align:middle;
}
.ek-ayuda-c:hover{ color:var(--acc); }

/* ---------------------------------------------------------------------
 * FAB de ayuda + popover anclado (ago 2026) — reemplaza al `?` de la
 * barra superior y al riel de ancho completo. La spec §3.2 había
 * descartado el FAB flotante de SIGE porque "un anillo animado ETERNO
 * compite en la misma jerarquía visual que un punto de estado real, p.ej.
 * 'lleva tres semanas esperando'". Esa objeción sigue vigente: de las seis
 * opciones comparadas (se probaron también el "anillo orbital" y el
 * "plano y sobrio" antes de volver a ésta), la elegida es el "círculo con
 * brillo interior" — degradado sutil --nav→--acc, un aro interior de luz
 * arriba y un halo tenue del acento, SIN pulso ni animación: el brillo es
 * estático, no compite con nada porque no se mueve nunca.
 * Lo que cambió, por decisión explícita del dueño del sistema, es la
 * SUPERFICIE — un botón flotante arrastrable con un popover anclado en
 * vez de un ícono fijo que abre un riel de ancho completo — adaptada a
 * los tokens de la casa: nada de --acc-nav es color nuevo. */
.ek-ayuda-fab{
  /* `right:var(--pad)` a propósito, no un valor suelto: es el MISMO margen
   * derecho de `.ek-bar-top` (line 2032), así que el FAB queda siempre en
   * la misma columna vertical que el sobre y la campanita de la barra,
   * incluida la variante de `--pad` en pantallas angostas. Un valor fijo
   * distinto al `--pad` de la barra desalineaba el FAB del resto del
   * chrome de la derecha — se notaba aunque las cajas mismas calzaran. */
  position:fixed; top:50%; right:var(--pad); transform:translateY(-50%); z-index:var(--z-fab);
  width:48px; height:48px; border-radius:50%; border:0; padding:0; cursor:grab; touch-action:none;
  display:grid; place-items:center; font-size:17px;
  background:linear-gradient(155deg, color-mix(in srgb, var(--nav) 70%, var(--acc) 30%), var(--nav) 60%);
  color:var(--acc-nav);
  /* Sombra + un aro interior de luz arriba (glossy, no plano) + un halo
   * tenue del acento debajo: la misma idea de profundidad que ya usa
   * `.ek-ayuda-play` (inset highlight), sin salirse de --nav/--acc/--acc-nav. */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    0 0 0 6px color-mix(in srgb, var(--acc-nav) 10%, transparent),
    0 8px 22px -6px rgba(7,17,41,.55), 0 1px 3px rgba(7,17,41,.35);
  transition:box-shadow var(--t) var(--ease), filter var(--t) var(--ease);
}
.ek-ayuda-fab:hover{ filter:brightness(1.16); }
.ek-ayuda-fab:focus-visible{ outline:2px solid var(--acc-nav); outline-offset:3px; }
/* ⚠️ El arrastre escribe `top` + `transform:none` inline (ver
   ekklesia-ayuda.js): por eso el realce de acá NUNCA usa `transform` —
   perdería siempre contra el inline y el hover se vería "roto" justo
   después de la primera vez que alguien mueve el botón. */
.ek-ayuda-fab.ek-arrastrando{ cursor:grabbing; box-shadow:0 14px 34px -6px rgba(7,17,41,.55); }

/* ---- El popover: anclado al disparador (el FAB o un `?` de concepto),
 * con cola triangular — nunca un velo de fondo, porque a diferencia del
 * riel esto no bloquea nada: es una consulta rápida, no una tarea.
 * Cerrado usa el mismo patrón que .ek-rail (visibility:hidden +
 * transform, nunca display:none): así EKA.posicionar() puede medirlo
 * antes de abrirlo y la animación de entrada tiene un estado "desde"
 * real. */
.ek-ayuda-pop{
  position:fixed; top:0; left:0; width:min(372px, calc(100vw - 24px));
  max-height:min(560px, 84vh); z-index:var(--z-pop);
  display:flex; flex-direction:column; background:var(--sf);
  border:1px solid var(--ln); border-radius:var(--r); overflow:hidden;
  box-shadow:var(--sh-lg); transform:scale(.92); transform-origin:100% 50%;
  opacity:0; visibility:hidden; pointer-events:none;
  transition:transform var(--t) var(--ease), opacity var(--t-fast) var(--ease);
}
.ek-ayuda-pop.ek-open{ transform:none; opacity:1; visibility:visible; pointer-events:auto; }
.ek-ayuda-pop:focus{ outline:none; }  /* el foco lo señala el propio contenido, no un aro sobre el panel */

/* ⚠️ Sin esto el popover NO recorta: `#ekAyudaPopCt` es un <div> normal
 * (JS le pone el innerHTML por fetch), así que `.ek-ayuda-hero` y
 * `.ek-rail-bd` son NIETOS de `.ek-ayuda-pop`, no hijos — el `flex:1` y el
 * `min-height:0` del cuerpo no significan nada si su padre inmediato no es
 * un contenedor flex. `display:contents` saca la caja de `#ekAyudaPopCt`
 * del árbol de layout sin tocar el DOM ni el JS: sus hijos pasan a ser
 * flex items DIRECTOS de `.ek-ayuda-pop`, que es donde el `max-height` y
 * el `overflow-y:auto` del cuerpo por fin se cruzan. Sin esta línea el
 * popover crecía para caber TODO el contenido en vez de recortarlo con
 * scroll interno, y al abrir un FAQ cerca del final se salía del
 * viewport por los dos lados. */
.ek-ayuda-pop-ct{ display:contents; }

.ek-ayuda-pop .ek-rail-bd{ flex:1; overflow-y:auto; padding:14px 16px; min-height:0; }

/* ---- Hero de la cabecera (ago 2026, pedido explícito): insignia, título
 * y subtítulo CENTRADOS, con el reproductor debajo — la referencia visual
 * es Delta Core, adaptada a los tokens de la casa (--nav/--acc/--acc-nav,
 * ningún color de marca nuevo). Es marcado PROPIO, construido en JS
 * (mostrar() en ekklesia-ayuda.js), no `EK.rielHd()`: la cabecera
 * compartida de los 16 rieles es horizontal (marca+nombre a la izquierda),
 * y forzarla a un layout centrado la habría vuelto una copia-17 con un
 * `if` por dentro. El popover de ayuda dejó de ser un `.ek-rail` — es su
 * propio componente, `.ek-ayuda-pop` — así que tiene sentido que tenga su
 * propia cabecera, no que finja compartirla. */
.ek-ayuda-hero{
  position:relative; overflow:hidden; flex-shrink:0;
  padding:22px 20px 4px; display:flex; flex-direction:column; align-items:center; text-align:center;
  background:
    radial-gradient(120% 90% at 50% -12%, color-mix(in srgb, var(--acc-nav) 24%, transparent) 0%, transparent 62%),
    linear-gradient(160deg, color-mix(in srgb, var(--nav) 78%, #1c3d7a) 0%, var(--nav) 68%);
}
/* Marca de agua: el emblema institucional reversado —el mismo PNG que ya
 * usan `.ek-shell` (mezcla clara) y las pantallas de acceso sobre fondo
 * oscuro—, muy tenue y centrado detrás de la insignia. Mismo criterio que
 * el correo y el login: la iglesia de fondo, el software (acá, la
 * insignia del tema) encima. Opacidad en el ELEMENTO, no en la imagen —a
 * diferencia de `.ek-shell`, que necesita el alfa horneado porque combina
 * background-color y background-image en la misma capa, acá el `::after`
 * es una capa aparte y `opacity` no se lleva nada más con ella. */
.ek-ayuda-hero::after{
  content:''; position:absolute; z-index:0; pointer-events:none;
  width:230px; height:230px; left:50%; top:-56px; transform:translateX(-50%);
  background:url("/assets/img/logo-renacer-emblema-blanco.png") center/contain no-repeat;
  opacity:.09;
}
.ek-ayuda-hero > *{ position:relative; z-index:1; }
.ek-ayuda-hero-x{
  position:absolute; z-index:2; top:12px; right:12px; width:28px; height:28px;
  border-radius:var(--r-sm); border:0; background:transparent; color:var(--nav-ink);
  display:grid; place-items:center; font-size:12.5px; cursor:pointer;
  transition:background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.ek-ayuda-hero-x:hover, .ek-ayuda-hero-x:focus-visible{ background:var(--nav-hov); color:var(--nav-on); }
.ek-ayuda-hero-badge{
  width:58px; height:58px; border-radius:17px; margin-bottom:12px;
  background:rgba(255,255,255,.10); border:1px solid rgba(255,255,255,.16);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.20), 0 8px 20px -8px rgba(0,0,0,.5);
  display:grid; place-items:center; font-size:22px; color:var(--nav-on);
}
.ek-ayuda-hero-tt{ font-size:16.5px; font-weight:700; color:var(--nav-on); line-height:1.25; letter-spacing:-.01em; max-width:280px; }
.ek-ayuda-hero-sub{
  font-size:10px; font-weight:600; color:var(--nav-ink); text-transform:uppercase;
  letter-spacing:.09em; margin-top:3px; margin-bottom:15px;
}

/* La cola: un cuadrado de 14px rotado 45° que muestra solo dos bordes.
 * Nace apuntando a la izquierda (el FAB vive en el borde derecho, así que
 * el caso más común es "el panel abre a la izquierda del botón"); cuando
 * EKA.posicionar() voltea el panel al lado derecho del ancla, `.ek-der`
 * espeja qué par de bordes se dibuja. */
.ek-ayuda-pop-cola{
  position:absolute; right:-7px; width:14px; height:14px; background:var(--sf);
  border:0; border-top:1px solid var(--ln); border-right:1px solid var(--ln);
  border-radius:0 3px 0 0; transform:rotate(45deg); z-index:2;
}
.ek-ayuda-pop.ek-der .ek-ayuda-pop-cola{
  right:auto; left:-7px; border-top:0; border-right:0;
  border-bottom:1px solid var(--ln); border-left:1px solid var(--ln);
  border-radius:0 0 0 3px;
}
/* Sobre el hero (la cabecera + el reproductor, ambos --nav): el cuadrado
 * toma el medianoche y apaga los filetes claros — el hero no tiene borde
 * propio, así que un filete claro colgando de él se lee como una raya
 * suelta en el aire. */
.ek-ayuda-pop-cola.ek-sobre-nav{ background:var(--nav); border-color:transparent; }
/* Sin ancla visible (llamada antigua, o el disparador ya no está en
 * pantalla): panel centrado, sin cola que apunte a ningún lado. */
.ek-ayuda-pop.ek-sin-cola .ek-ayuda-pop-cola{ display:none; }

@media (prefers-reduced-motion:reduce){
  /* El FAB ya no anima nada por su cuenta (el aro orbital es estático):
     nada que apagar acá. Solo la entrada del popover. */
  .ek-ayuda-pop{ transition:none; }
}

/* ---- Reproductor dentro del hero oscuro. Es el único consumidor real de
 * `.ek-ayuda-player-*` en toda la app (modulos/config/ayuda.php sólo
 * llama a EKA.previsualizar(), no pinta reproductor), así que esto no es
 * una variante que conviva con otra: es una reescritura en el lugar con
 * los tokens "sobre oscuro" que ya existen para el resto del chrome
 * (--nav-ink, --nav-on, --acc-nav), sin inventar un color de marca nuevo
 * como el dorado de SIGE. */
.ek-ayuda-pop .ek-ayuda-player{
  background:rgba(255,255,255,.06); border-color:var(--nav-ln); box-shadow:none;
}
.ek-ayuda-pop .ek-ayuda-player.tts-on{
  background:rgba(255,255,255,.13); border-color:var(--acc-nav); box-shadow:none;
}
.ek-ayuda-pop .ek-ayuda-play{ background:rgba(127,166,255,.18); color:var(--acc-nav); box-shadow:none; }
.ek-ayuda-pop .ek-ayuda-play:hover{
  background:var(--acc-nav); color:var(--nav); box-shadow:none; transform:scale(1.06);
}
.ek-ayuda-pop .ek-ayuda-player.tts-on .ek-ayuda-play{
  background:var(--acc-nav); color:var(--nav); box-shadow:0 0 0 4px rgba(127,166,255,.16);
}
.ek-ayuda-pop .ek-ayuda-player.tts-on .ek-ayuda-play::before,
.ek-ayuda-pop .ek-ayuda-player.tts-on .ek-ayuda-play::after{ border-color:var(--acc-nav); }
.ek-ayuda-pop .ek-ayuda-wave span{ background:var(--nav-ln); }
.ek-ayuda-pop .ek-ayuda-player.tts-on .ek-ayuda-wave span{
  background:var(--acc-nav); filter:drop-shadow(0 0 2.5px rgba(127,166,255,.5));
}
.ek-ayuda-pop .ek-ayuda-player-txt{ color:var(--nav-ink); }
.ek-ayuda-pop .ek-ayuda-player.tts-on .ek-ayuda-player-txt{ color:var(--nav-on); }

/* La píldora va CENTRADA (no a lo ancho, como en el resto de la app) y la
 * barra de progreso se estira a ras de los dos bordes del hero —el mismo
 * gesto de Delta Core—: por eso los -20px de margen cancelan exactamente
 * el padding lateral del hero (22px 20px, ver .ek-ayuda-hero). */
.ek-ayuda-pop .ek-ayuda-player-bar{
  display:flex; flex-direction:column; align-items:center; gap:11px;
  padding:0 0 18px;
}
.ek-ayuda-pop .ek-ayuda-player{ width:auto; max-width:100%; padding:7px 9px 7px 7px; }
.ek-ayuda-pop .ek-ayuda-player-prog{
  width:calc(100% + 40px); margin:0 -20px; height:3px; border-radius:0;
  background:rgba(255,255,255,.14); box-shadow:none;
}
.ek-ayuda-pop .ek-ayuda-player-prog-fill{ border-radius:0; background:linear-gradient(90deg, var(--acc-nav), var(--nav-on)); }

/* Reproductor de ayuda (narración por voz, §3.4). Mismo comportamiento que
 * el de SIGE — botón play/stop, ecualizador decorativo, texto de estado,
 * barra de progreso lineal — pero con el acento de la casa (--acc, ya usado
 * para "en curso" en .ek-est) en vez de un color de marca nuevo. El anillo
 * y el ecualizador SOLO se mueven mientras hay audio sonando de verdad
 * (.tts-on): es una señal de estado real, no una animación de adorno.
 * La "modernidad" acá es profundidad (brillo interior, sombra, resplandor)
 * sobre el mismo acento, no un color nuevo — sigue siendo --acc de punta
 * a cabo, solo con más matiz tonal. */
.ek-ayuda-player-bar{ padding:16px 18px 14px; }
.ek-ayuda-player{
  position:relative; display:flex; align-items:center; gap:10px; padding:8px 15px;
  background:linear-gradient(155deg, var(--sf2), var(--sf)); border:1px solid var(--ln);
  border-radius:28px; box-shadow:var(--sh-card);
  transition:background var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease),
             border-color var(--t-slow) var(--ease);
}
.ek-ayuda-player.tts-on{
  background:linear-gradient(155deg, var(--acc-sf), var(--sf));
  border-color:var(--acc-bd); box-shadow:var(--sh-open);
}

.ek-ayuda-play{
  position:relative; flex:none; width:32px; height:32px; border-radius:50%;
  border:0; background:var(--acc-sf); color:var(--acc); cursor:pointer;
  display:flex; align-items:center; justify-content:center; font-size:12px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4);
  transition:background var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
             transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.ek-ayuda-play:hover{
  background:var(--acc); color:var(--acc-ink); transform:scale(1.06);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35), 0 3px 10px -3px rgba(14,42,99,.45);
}
.ek-ayuda-play:active{ transform:scale(.96); }
.ek-ayuda-player.tts-on .ek-ayuda-play{
  background:var(--acc); color:var(--acc-ink);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35), 0 0 0 4px var(--acc-sf);
}
.ek-ayuda-play i{ margin-left:1px; }   /* el triángulo de "play" se ve corrido a la izquierda si no se compensa */

@keyframes ekAyudaAnillo{ 0%{ transform:scale(1); opacity:.55; } 100%{ transform:scale(1.7); opacity:0; } }
.ek-ayuda-player.tts-on .ek-ayuda-play::before,
.ek-ayuda-player.tts-on .ek-ayuda-play::after{
  content:''; position:absolute; inset:-5px; border-radius:50%;
  border:1.5px solid var(--acc); animation:ekAyudaAnillo 1.7s ease-out infinite;
}
.ek-ayuda-player.tts-on .ek-ayuda-play::after{ inset:-12px; border-width:1px; opacity:.55; animation-delay:.55s; }

.ek-ayuda-wave{ display:flex; align-items:center; gap:2.5px; height:18px; flex:none; }
.ek-ayuda-wave span{
  width:2.5px; height:4px; border-radius:2px; background:var(--acc-bd);
  transition:height .3s var(--ease), background .3s var(--ease);
}
.ek-ayuda-player.tts-on .ek-ayuda-wave span{
  background:var(--acc); animation:ekAyudaBarra .9s ease-in-out infinite;
  filter:drop-shadow(0 0 2.5px var(--acc-bd));
}
@keyframes ekAyudaBarra{ 0%,100%{ height:4px } 50%{ height:16px } }
.ek-ayuda-wave span:nth-child(1){ animation-delay:0s }
.ek-ayuda-wave span:nth-child(2){ animation-delay:.07s }
.ek-ayuda-wave span:nth-child(3){ animation-delay:.14s }
.ek-ayuda-wave span:nth-child(4){ animation-delay:.21s }
.ek-ayuda-wave span:nth-child(5){ animation-delay:.28s }
.ek-ayuda-wave span:nth-child(6){ animation-delay:.35s }
.ek-ayuda-wave span:nth-child(7){ animation-delay:.31s }
.ek-ayuda-wave span:nth-child(8){ animation-delay:.24s }
.ek-ayuda-wave span:nth-child(9){ animation-delay:.17s }
.ek-ayuda-wave span:nth-child(10){ animation-delay:.10s }
.ek-ayuda-wave span:nth-child(11){ animation-delay:.04s }
.ek-ayuda-wave span:nth-child(12){ animation-delay:.38s }

.ek-ayuda-player-txt{
  flex:1; min-width:0; font-size:12px; font-family:var(--mono); color:var(--mut);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  transition:color var(--t-fast) var(--ease);
}
.ek-ayuda-player.tts-on .ek-ayuda-player-txt{ color:var(--acc); font-weight:600; }

.ek-ayuda-player-prog{
  position:relative; height:4px; background:var(--ln); border-radius:99px; margin-top:9px;
  overflow:hidden; box-shadow:inset 0 1px 1px rgba(16,24,40,.06);
}
.ek-ayuda-player-prog-fill{
  position:relative; height:100%; width:0%; border-radius:99px;
  background:linear-gradient(90deg, var(--acc-bd), var(--acc));
  transition:width .25s linear;
}
/* Destello que recorre la barra SOLO mientras suena de verdad — misma
 * regla que el anillo y el ecualizador: nada se mueve si no hay audio. */
.ek-ayuda-player-bar.tts-on .ek-ayuda-player-prog-fill::after{
  content:''; position:absolute; inset:0;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  background-size:60px 100%; animation:ekAyudaDestello 1.3s linear infinite;
}
@keyframes ekAyudaDestello{ from{ background-position:-60px 0; } to{ background-position:120px 0; } }

@media (prefers-reduced-motion:reduce){
  .ek-ayuda-player.tts-on .ek-ayuda-play::before,
  .ek-ayuda-player.tts-on .ek-ayuda-play::after{ animation:none; opacity:0; }
  .ek-ayuda-player.tts-on .ek-ayuda-wave span{ animation:none; height:10px; }
  .ek-ayuda-player-bar.tts-on .ek-ayuda-player-prog-fill::after{ animation:none; }
  .ek-ayuda-cuerpo > *{ animation:none; }
  .ek-ayuda-caja{ transition:none; }
  .ek-ayuda-caja:hover{ transform:none; }
}

/* =====================================================================
   9 · Paneles de pestaña
   =====================================================================
   El estado vive en DOS lugares y no en una tercera clase «activo»: el
   botón lleva `.on` (que ya es el idioma de .ek-segs) y el panel lleva
   `hidden`. Duplicarlo en una clase propia es la forma segura de que un
   día digan cosas distintas.

   `hidden` es un atributo, no una clase, y el `display` de una regla
   posterior le gana: sin esta línea el panel oculto se seguiría viendo.
   ------------------------------------------------------------------ */
.ek-tabp[hidden]{ display:none; }

/* ------------------ 9 · BARRA DE ESTADO INFERIOR ------------------
   Reemplaza a la píldora flotante del cronómetro de sesión, que tapaba la
   última fila de una tabla y el último campo de un formulario. Correrla no
   arreglaba nada —siempre hay algo debajo—; el arreglo es que deje de
   flotar. Esta barra OCUPA: va como hermana de <main> dentro de la columna
   derecha, así que <main> se encoge solo y ninguna pantalla tiene que
   acordarse de reservarle sitio.

   Dirección «B · pie claro del área de trabajo» (docs/rediseno_barra_estado.html):
   empieza a la derecha del menú, que sigue llegando al fondo con su bloque
   de usuario intacto.

   ⚠️ Se llama `.ek-bar-bot` por lo mismo que la superior se llama
   `.ek-bar-top` y no `.ek-bar`: ese nombre ya es el de la barra de avance
   de la sección 4, y una regla posterior con `background` y `padding` la
   dejaba lavada en todo el sistema.
   ------------------------------------------------------------------ */
/* ⚠️ Los tamaños de acá son deliberadamente MAYORES que los del resto del
   chrome (`.micro` es 11px). Esta barra la miran de reojo, desde lejos y
   sin acercarse, personas mayores: a 11px la hora no se leía. Es la única
   pieza del sistema donde el tamaño lo fija quién la lee y no la jerarquía
   —una barra de estado no compite con el contenido por atención, así que
   crecer no la sube de rango—. */
.ek-bar-bot{
  height:var(--bot-h); display:flex; align-items:center; gap:16px;
  padding:0 var(--pad); background:var(--sf); border-top:1px solid var(--ln);
  font-size:13px; color:var(--ink2); overflow:hidden;
}
.ek-bb-g{ display:flex; align-items:center; gap:7px; white-space:nowrap; min-width:0; }
.ek-bb-g > i{ font-size:13px; opacity:.55; }
/* La palabra que acompaña al dato va más apagada que el dato: lo que se
   consulta es la cifra, no el rótulo. */
.ek-bb-w{ color:var(--fnt); }
.ek-bb-g .num{ font-family:var(--mono); font-size:15px; font-weight:500;
  font-variant-numeric:tabular-nums; color:var(--ink); }
.ek-bb-sep{ width:1px; height:15px; background:var(--ln); flex-shrink:0; }

/* ── Carátula del reloj ────────────────────────────────────────────
   No es un ícono de catálogo: la aguja da una vuelta por minuto y arranca
   desfasada a los segundos que ya lleva el minuto (animation-delay
   negativo, escrito en línea desde PHP), así que marca la hora de verdad.
   Es la única animación permanente del sistema y se la gana porque dice,
   sin leer nada, que el reloj está andando. */
.ek-bb-reloj{ width:17px; height:17px; flex-shrink:0; overflow:visible; }
/* La carátula usa --ln y no --ln2: ese es el separador de tabla (#edeff3) y
   a 17px un círculo de 1.7px en ese tono no se ve. */
.ek-bb-reloj circle{ fill:none; stroke:var(--ln); stroke-width:1.7; }
.ek-bb-ag{
  stroke:var(--acc); stroke-width:1.9; stroke-linecap:round;
  transform-origin:12px 12px; animation:ek-bb-giro 60s linear infinite;
}
@keyframes ek-bb-giro{ to{ transform:rotate(360deg); } }
/* Quieta, pero NO escondida: la carátula sigue diciendo «esto es la hora».
   Lo que molesta de una animación permanente es el movimiento, no el
   dibujo. */
@media (prefers-reduced-motion:reduce){
  .ek-bb-ag{ animation:none; }
}
.ek-bb-der{ margin-left:auto; display:flex; align-items:center; gap:14px; flex-shrink:0; }
/* El culto es lo único variable en ancho, así que es lo único que cede: sin
   esto empuja al reloj fuera de la barra en un nombre largo. */
.ek-bb-culto{ overflow:hidden; text-overflow:ellipsis; }

/* El cronómetro es lo único de la barra que cambia de color, y solo en la
   recta final: «queda menos de un minuto» ES un estado. El resto son datos,
   y un dato va en tinta. */
#ek-ses[data-niv="w"] .num{ color:var(--warn); }
#ek-ses[data-niv="d"] .num{ color:var(--danger); }

/* En pantalla angosta se quedan la hora y el cierre, que es lo que no se
   puede deducir de nada. «Culto AM · empezó a las 10:00» y la fecha se
   comen los 375px enteros. */
@media (max-width:820px){
  .ek-bar-bot{ padding:0 12px; gap:10px; }
  .ek-bb-culto, .ek-bb-fec{ display:none; }
  .ek-bb-der{ gap:10px; }
}

/* ── Velo del cierre por inactividad ───────────────────────────────
   Bloquea a los 60 s finales. Bloquear es el punto: quien vuelve al
   escritorio tiene que ver esto primero. No contradice la regla del riel,
   que rige para VER un detalle; esto exige decidir, y un riel deja el
   contenido usable a un costado. */
#ek-ses-velo{
  position:fixed; inset:0; z-index:var(--z-sesion-velo); display:none;
  align-items:center; justify-content:center; padding:20px;
  background:rgba(7,17,41,.55);
  backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
}
#ek-ses-velo.ek-abierto{ display:flex; }
#ek-ses-caja{
  background:var(--sf); border-radius:var(--r-lg); box-shadow:var(--sh-lg);
  max-width:420px; width:100%; padding:28px; text-align:center;
}
#ek-ses-caja .ek-ses-ic{
  width:52px; height:52px; margin:0 auto 14px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:var(--warn-sf); color:var(--warn); font-size:22px;
}
#ek-ses-caja h2{ font-size:19px; font-weight:600; margin-bottom:6px; }
#ek-ses-caja p{ font-size:14px; color:var(--ink2); margin-bottom:18px; }
#ek-ses-cuenta{
  font-family:var(--mono); font-size:30px; font-variant-numeric:tabular-nums;
  color:var(--danger); display:block; margin-bottom:18px;
}
#ek-ses-datos{
  display:none; font-size:13px; text-align:left; margin-bottom:18px;
  background:var(--dan-sf); border:1px solid var(--dan-bd); color:var(--danger);
  border-radius:var(--r); padding:10px 12px;
}
#ek-ses-datos.ek-abierto{ display:block; }
#ek-ses-caja .btn-primary{ width:100%; }

/* ------------------------- 9 · IMPRESIÓN ---------------------------- */
/* Una pantalla que se imprime NO es un archivo aparte: es la misma
   pantalla sin el chrome. El menú, la barra superior y la barra de estado
   no existen en papel —nadie navega una hoja—, así que se van; lo que
   queda es el contenido, a todo el ancho.

   ⚠️ Varias de estas reglas llevan !important y no es descuido: el
   armazón fija `h-screen`, `overflow-hidden` y `overflow-y-auto` con
   utilidades de Tailwind, y <main> trae su padding INLINE desde
   layout_top.php. Sin !important el navegador imprime una sola página
   —la ventana— y corta el resto de la tabla.

   Para esconder algo puntual de una pantalla (filtros, botones de
   acción), márcalo con .ek-noprint en vez de agregar un selector acá. */
/* Lo que SOLO existe en papel: la casilla para marcar a mano lo que en
   pantalla ya dice una palabra. En pantalla no se pinta, porque ahí un
   cuadrito vacío parece un control que no responde. */
.ek-soloprint{ display:none; }

@media print{
  .ek-soloprint{ display:inline-block; }

  /* El chrome de la aplicación no viaja al papel. */
  #sidebar, .ek-bar-top, .ek-bar-bot, .ek-noprint,
  .ek-rail, .ek-rail-velo, #ek-ses-velo, .ek-load-velo, .ek-load-bar{
    display:none !important;
  }

  /* El armazón deja de ser una ventana con scroll y pasa a ser un flujo
     continuo, que es lo que la impresora sabe paginar. */
  .ek-shell{ height:auto !important; overflow:visible !important; display:block !important;
    background:none !important; }
  .ek-main{ overflow:visible !important; padding:0 !important; }
  body{ background:#fff; }

  /* En papel el relieve no se lee: se leen los filetes. */
  .ek-card, .glass-card, .ek-kpis{ box-shadow:none !important; break-inside:avoid; }

  /* Una fila partida entre dos hojas deja media persona en cada una. */
  table.dt tbody tr{ break-inside:avoid; }
  /* La cabecera se repite en cada hoja: sin esto, de la segunda página en
     adelante hay columnas sin nombre. */
  table.dt thead{ display:table-header-group; }

  /* Sin animación de entrada: al imprimir se captura el primer cuadro, y
     con la cascada corriendo eso es contenido a medio aparecer. */
  .ek-anim > *, .ek-anim-filas tbody tr{ animation:none !important; opacity:1 !important;
    transform:none !important; }
}

/* ==================================================================
 * 10 · SUPERFICIE MÓVIL
 * Ver docs/superpowers/specs/2026-08-04-app-movil-design.md §9.
 * Mismo armazón, chrome distinto: nada de esto se aplica en escritorio,
 * lo decide includes/layout_top.php con $EK_RENDER_MOVIL.
 * ================================================================== */

/* ⚠️ LA ALTURA DEL ARMAZÓN ES LA VISIBLE, NO `100vh`.
   El armazón se dibuja con `h-screen` de Tailwind, o sea `100vh`, y en un
   navegador de teléfono `100vh` NO es lo que se ve: mide la ventana con
   la barra de URL retraída, así que en reposo sobra justo el alto de esa
   barra. Como `.ek-shell` es `overflow-hidden`, ese sobrante no se puede
   alcanzar con scroll — queda CORTADO, y lo que vive al fondo es
   precisamente la barra de navegación. Por eso «se pierden los botones de
   abajo» en un teléfono chico y no en el simulador, donde las dos
   medidas coinciden.
   `100dvh` es la altura VISIBLE y se re-mide sola cuando la barra de URL
   entra y sale. La regla va acá, después de las utilidades, para ganarle
   a `h-screen`; y el `100vh` de la línea de arriba es el respaldo para
   quien no entienda `dvh`, que se lo come sin aplicar. */
.ek-shell{ height:100vh; height:100dvh; }

/* Cabecera móvil: [volver] título · avatar. Reusa .ek-bar-top —mismos
   filetes— pero NO su alto: los 82px de escritorio son el 14 % de un
   teléfono de 600px, y entre cabecera, barra de estado y navegación el
   chrome se comía el 29 % de la pantalla. A 56px sigue habiendo 48 de
   blanco táctil para los botones, que es el mínimo que hay que respetar. */
/* ⚠️ `display:flex`, no el grid heredado. `.ek-bar-top` es un GRID de tres
   pistas (título · búsqueda · acciones) y en el teléfono sólo hay dos
   hijos: el grupo de la derecha caía en la pista del MEDIO y quedaba a
   media barra, con 200px muertos al costado. No se notaba hasta abrir el
   menú de cuenta, que se ancla al botón y por eso se salía por la
   izquierda cortando el nombre. `justify-content` sobre el grid no lo
   arreglaba: había que cambiar el modo de reparto. */
.ek-bar-top-mv{
  display:flex; align-items:center; justify-content:space-between;
  gap:8px; height:56px; min-height:56px;
}
.ek-bar-top-mv .ek-bar-r{ display:flex; align-items:center; gap:2px; flex-shrink:0; }
/* El emblema, a tamaño de ícono de app. 26px es lo que deja el alto de
   56 con aire arriba y abajo, y lo que permite que el título conserve su
   ancho: con el chevron, el logo y los dos botones de la derecha, en un
   teléfono de 360px quedan ~170px para el nombre de la pantalla, que
   alcanza para «Registrar visita» sin truncar. */
.ek-bar-top-mv .ek-mv-logo{ width:26px; height:26px; flex-shrink:0; display:block; }
.ek-bar-top-mv .ek-bar-l{ gap:8px; }
.ek-bar-top-mv .ek-bar-l{ min-width:0; flex:1; }
.ek-bar-top-mv .ek-miga-hoy{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* ⚠️ EL PIE DEL TELÉFONO ES FIJO Y VA SOBRE TODO. Acción principal y
   navegación, juntas y ancladas al borde de abajo. Estuvieron en el flujo,
   como hermanas de <main> —que es la postura correcta en escritorio— y en
   un teléfono no basta: el alto visible cambia solo mientras se hace
   scroll (la barra de URL del navegador entra y sale), así que cualquier
   desajuste de un píxel manda la navegación bajo el pliegue, donde sólo
   aparece con un segundo scroll que nadie sabe que existe.
   Fijo, se ve siempre. <main> le reserva el espacio con su padding-bottom,
   que lo calcula layout_top.php porque depende de si hay acción o no. */
.ek-mv-pie{
  position:fixed; left:0; right:0; bottom:0; z-index:var(--z-nav);
}

/* Barra de navegación inferior (§9.2). Alto fijo + el respiro de la barra
   de gestos del iPhone: sin `env(safe-area-inset-bottom)` el último ítem
   queda bajo esa franja y no se puede tocar. */
.ek-nav-bot{
  display:flex; height:calc(var(--nav-bot-h) + env(safe-area-inset-bottom));
  padding-bottom:env(safe-area-inset-bottom);
  background:var(--sf); border-top:1px solid var(--ln);
  flex-shrink:0;
}
.ek-nav-bot-it{
  flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:3px; min-height:48px; color:var(--mut); text-decoration:none;
  font-size:10px; font-weight:500; background:none; border:none; cursor:pointer;
  border-top:2px solid transparent; margin-top:-1px;
}
.ek-nav-bot-it i{ font-size:18px; }
/* «Acá estás»: tinta de acento + barra arriba, el mismo lenguaje del menú
   lateral (velo + barra de acento), no un color de relleno. */
.ek-nav-bot-it.on{ color:var(--acc); border-top-color:var(--acc); }

/* Acción principal fija al pie (§9.4), reemplazo móvil de .ek-bar-cta —
   ese se sale de la pantalla a 375px. Va SOBRE la barra inferior. */
.ek-cta-fija{
  display:flex; align-items:center; justify-content:center; gap:8px;
  width:100%; height:var(--cta-h); padding:0 13px; font-size:14px; font-weight:600;
  background:var(--acc); color:#fff; border:none; text-decoration:none;
  box-shadow:0 -2px 10px var(--sh-acc, rgba(14,42,99,.18));
}
.ek-cta-fija:disabled{ background:var(--mut); box-shadow:none; }

/* Hoja inferior (§9.3): para ELEGIR entre opciones —«Más», filtros—, no
   para VER un detalle (eso sigue siendo el riel). Comparte el velo y la
   escala de capas del riel (ver sincronizarVelo() en ekklesia-ui.js). */
.ek-sheet{
  position:fixed; left:0; right:0; bottom:0; z-index:var(--z-drawer);
  background:var(--sf); border-radius:16px 16px 0 0;
  max-height:85vh; overflow-y:auto;
  transform:translateY(100%); transition:transform var(--t) ease;
  padding:8px 0 calc(10px + env(safe-area-inset-bottom));
  /* El mismo cinturón que el riel: si algo vuelve a pisar el transform, la
     hoja sigue sin poder aparecer sola ni robar clics. */
  visibility:hidden;
}
.ek-sheet.ek-open{ transform:translateY(0); visibility:visible; }
.ek-sheet-asa{ width:36px; height:4px; border-radius:2px; background:var(--ln);
  margin:6px auto 10px; }
.ek-sheet-bd{ padding:0 6px; }
.ek-sheet-it{
  display:flex; align-items:center; gap:12px; padding:13px 14px;
  font-size:14px; color:var(--ink); text-decoration:none; border-radius:var(--r-sm);
}
.ek-sheet-it:hover{ background:var(--bg); }
.ek-sheet-it i{ width:18px; text-align:center; color:var(--fnt); }

/* El asa de la hoja es un BOTÓN, no un adorno: la barrita gris es el
   gesto que todo el mundo reconoce para descartar, así que se toca. El
   blanco táctil son 44px de alto aunque el dibujo mida 4 — un objetivo
   que se ve chiquito no tiene por qué SER chiquito. */
/* La cabecera de la hoja: el asa ocupa todo el ancho (es el gesto) y la X
   se apoya encima, a la derecha. Por eso el contenedor es relativo y la X
   absoluta — si fueran hermanas en flex, el asa dejaría de estar centrada
   respecto de la hoja y pasaría a estarlo respecto del hueco que deja la X. */
.ek-sheet-hd{ position:relative; }
.ek-sheet-x{ position:absolute; right:8px; top:0; }
.ek-sheet-asa{
  display:block; width:100%; height:44px; padding:0; border:0; background:none;
  cursor:pointer;
}
.ek-sheet-asa span{ display:block; width:36px; height:4px; border-radius:2px;
  background:var(--ln); margin:0 auto; }
.ek-sheet-asa:hover span{ background:var(--fnt); }
/* «Cerrar» va separado de las opciones por un filete: no es un destino
   más de la lista, es la salida. */
.ek-sheet-cerrar{
  width:100%; text-align:left; cursor:pointer; color:var(--mut);
  border:0; border-top:1px solid var(--ln2); border-radius:0;
  margin-top:6px; padding-top:14px; font-family:inherit;
}

/* Sólo se ve en móvil: el desktop nunca renderiza estos elementos (los
   condiciona $EK_RENDER_MOVIL en PHP), pero por si un estilo viejo los
   alcanzara en una ventana angosta de escritorio, se acotan igual. */
@media (min-width:821px){
  .ek-nav-bot, .ek-cta-fija{ display:none !important; }
}

/* Avatar de «mi cuenta» en la cabecera del teléfono. Las iniciales sobre
   el tinte del acento: es la marca de identidad, no un estado, así que no
   toma ningún color de la escala semántica. */
.ek-mv-yo{
  width:44px; height:44px; flex-shrink:0; border-radius:50%;
  background:var(--acc-sf); color:var(--acc); border:1px solid var(--acc-bd);
  font-size:12px; font-weight:700; letter-spacing:.02em; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
}
.ek-mv-yo:focus-visible{ outline:2px solid var(--acc); outline-offset:2px; }

/* ⚠️ Y aunque el anclaje esté bien, un menú anclado al último botón se
   sale por la izquierda apenas es más ancho que lo que queda de barra.
   `max-width` en vez de un ancho fijo: nunca más que la pantalla menos
   sus márgenes, así el nombre no se corta en ningún tamaño. */
.ek-bar-top-mv .ek-menu{ max-width:calc(100vw - 20px); }

/* ⚠️ 44px de BLANCO TÁCTIL en los controles de la cabecera del teléfono.
   `.ek-icb` mide 34, que es cómodo con un mouse de un píxel y chico para
   un dedo: el mínimo recomendado son 44, y acá los tres botones —volver,
   avisos, mi cuenta— están pegados al borde y uno al lado del otro, que
   es justo donde un objetivo chico se falla. El DIBUJO no crece: crece la
   zona que responde, así que la cabecera se ve igual y se acierta. Caben
   dentro de los 56px de alto. */
.ek-bar-top-mv .ek-icb{ width:44px; height:44px; }



/* «Necesita atención» del Resumen, en el teléfono. La fila entera es el
 * enlace —no un botón «Abrir» de 90px al final—, que es el gesto de una
 * app: se toca el renglón. */
.hoy-at{ display:flex; flex-direction:column; }
.hoy-at-it{
  display:flex; align-items:center; gap:11px; padding:13px 2px;
  border-bottom:1px solid var(--ln2); text-decoration:none; color:inherit;
}
.hoy-at-it:last-child{ border-bottom:0; }
.hoy-at-tx{ flex:1; min-width:0; }
/* La cifra, junto al título y no en su propio renglón: es lo que dice
 * cuánto pesa el problema, y separada dejaba de leerse con él. */
.hoy-at-n{ font-size:19px; font-weight:600; color:var(--ink); flex-shrink:0; }
.hoy-at-ch{ font-size:11px; color:var(--fnt); flex-shrink:0; }

/* Tarjeta de persona seleccionable, para colas móviles que se trabajan por
 * tanda («Registrar bienvenida»): la selección ES la acción de la pantalla,
 * así que tiene que notarse de un vistazo qué queda marcado — mismo
 * lenguaje que .ek-opt (borde + fondo de acento en :checked), no el
 * cuadradito nativo suelto sobre una fila de tabla genérica. */
.msg-todos{
  display:flex; align-items:center; gap:9px; font-size:13px; color:var(--mut);
  padding:4px 2px 12px; cursor:pointer;
}
.msg-lst{ display:flex; flex-direction:column; gap:8px; }
.msg-fila{
  display:flex; align-items:flex-start; gap:11px; box-sizing:border-box;
  padding:12px 13px; border:1px solid var(--ln); border-radius:var(--r-sm);
  background:var(--sf); cursor:pointer;
  transition:border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.msg-fila:has(.msg-chk:checked){ border-color:var(--acc); background:var(--acc-sf); }
.msg-fila-fija{ cursor:default; }
/* El cuadradito nativo se agranda: en escritorio 16px alcanza porque hay
 * mouse; acá el objetivo táctil mínimo son 44px, y sin agrandarlo la marca
 * visual de la tarjeta (borde + fondo) queda cargando todo el trabajo de
 * decir «esto se puede tocar». */
.msg-chk{ width:20px; height:20px; margin-top:1px; flex-shrink:0; accent-color:var(--acc); }
.msg-cuerpo{ flex:1; min-width:0; }
.msg-hd{ display:flex; align-items:center; gap:9px; }
.msg-hd .ek-nm{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Los días de espera, como dato de cabecera y no perdidos al pie: es lo
 * que ordena la cola, así que se lee al mismo tiempo que el nombre. */
.msg-esp{
  font-family:var(--mono); font-size:11px; color:var(--mut); background:var(--sf2);
  border-radius:99px; padding:2px 8px; flex-shrink:0;
}
/* Comuna · edad · estado civil, como CHIPS y no como texto con puntos
 * medios: tres datos sueltos se leen más rápido separados que en una
 * frase, y son justo los que deciden a qué grupo le corresponde. */
.msg-tags{ display:flex; flex-wrap:wrap; gap:6px; margin:8px 0 0 41px; }
.msg-meta{ display:flex; flex-wrap:wrap; gap:12px; margin:8px 0 0 41px; }
.msg-meta-it{ display:flex; align-items:center; gap:5px; font-size:12px; color:var(--mut); }
.msg-meta-it i{ font-size:11px; color:var(--fnt); width:12px; text-align:center; }
.msg-meta-it.w{ color:var(--warn); }
.msg-meta-it.w i{ color:var(--warn); }
.msg-meta-it.k{ color:var(--ok); }
.msg-meta-it.k i{ color:var(--ok); }
/* =====================================================================
   11 · RIEL DE PASOS («recorrido»)

   Reemplaza al sankey de cuatro etapas del Resumen General de Visitas.
   Ver docs/rediseno_recorrido.html (dirección C) y ek_ruta() en
   includes/ui.php, donde está el porqué.

   Ocupa 88px contra los 300px del gráfico y dice más: el conector carga
   la tasa de paso, y la fuga cuelga de él en ámbar — salvo lo que sigue
   en curso, que va neutro.

   Se llama `ek-ruta` y NO `ek-rec`: esa clase ya es la pastilla
   «Recomendado» de .ek-opt, y una regla posterior la habría pisado.
   Misma trampa que .ek-bar-top contra .ek-bar.
   ===================================================================== */
/* ⚠️ `nowrap`, no `wrap`. Con `wrap` la cuarta pastilla no cabía en los
   896px reales de la tarjeta (4×150 + 3×112 = 936), se iba sola a una
   segunda fila y ahí su `flex-grow` la estiraba al ancho completo: quedaba
   una pastilla gigante bajo tres chicas, y el conector de la fila de arriba
   apuntando a la nada. Una cadena partida en dos filas deja de leerse como
   una cadena. O entra entera, o baja en columna (ver el @media). */
.ek-ruta{ display:flex; align-items:flex-start; flex-wrap:nowrap; }

.ek-ruta-p{
  flex:1 1 140px; min-width:104px; display:block;
  border:1px solid var(--ln); border-radius:var(--r2); background:var(--sf);
  padding:11px 13px; box-shadow:var(--sh); text-decoration:none;
  transition:border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
a.ek-ruta-p:hover{ border-color:var(--mut); box-shadow:var(--sh-card); }
.ek-ruta-k{ font-size:11px; color:var(--mut); font-weight:600; }
.ek-ruta-v{
  font-family:var(--mono); font-variant-numeric:tabular-nums;
  font-size:23px; color:var(--ink); letter-spacing:-.02em; margin-top:1px;
}
/* La primera pastilla lleva el lavado del acento: es el universo del que
   hablan todas las demás, no una etapa más de la fila. */
.ek-ruta-uni{ background:var(--acc-sf); border-color:var(--acc-bd); }

/* El conector no es decoración: la tasa de paso es la única cifra que
   contesta «de los que capté, cuántos llegan». */
.ek-ruta-c{ flex:0 1 108px; min-width:76px; padding:14px 6px 0; text-align:center; }
.ek-ruta-t{ font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:13px; color:var(--ink); }
.ek-ruta-ln{ height:1px; background:var(--ln); margin:5px 0 7px; position:relative; }
.ek-ruta-ln::after{
  content:''; position:absolute; right:0; top:-3px;
  border-left:5px solid var(--ln);
  border-top:3.5px solid transparent; border-bottom:3.5px solid transparent;
}
/* El ámbar dice «esto se perdió». Sin nivel queda neutro, que es lo que
   corresponde a lo que sigue en curso. El color NUNCA es la única señal:
   el nombre de la fuga va escrito al lado. */
.ek-ruta-f{
  display:block; font-size:11px; line-height:1.35; color:var(--fnt);
  font-weight:600; text-decoration:none;
}
.ek-ruta-f.w{ color:var(--warn); }
.ek-ruta-f.d{ color:var(--danger); }
.ek-ruta-f.k{ color:var(--ok); }
a.ek-ruta-f:hover{ text-decoration:underline; }
.ek-ruta-n{ display:block; font-family:var(--mono); font-variant-numeric:tabular-nums; }

/* En angosto la fila se vuelve columna. El corte es 1060px y no 760: con el
   menú lateral (272px) y los márgenes, la tarjeta mide unos 384px menos que
   la ventana, así que a 1060 le quedan ~676px de contenido — lo justo sobre
   el mínimo de la fila (4×104 + 3×76 = 644). Más abajo de eso las pastillas
   se aplastan antes que la fila decida bajar, y «Contactados» se parte. */
@media(max-width:1060px){
  .ek-ruta{ flex-direction:column; align-items:stretch; }
  .ek-ruta-c{ flex:none; padding:9px 0; }
  .ek-ruta-ln{ display:none; }
}
/* ⚠️ El corte depende de CUÁNTAS etapas hay, y por eso ek_ruta() escribe
   `data-n`. La cadena de Ayuda Social tiene CINCO —5×104 + 4×76 = 824—, así
   que necesita bajar a columna antes: con 1220px le quedan ~836 de
   contenido. Con el corte de cuatro etapas, a 1100px las cinco pastillas se
   aplastaban bajo su mínimo y «Solicitudes» se partía en dos líneas.
   Las declaraciones se repiten a propósito: son el mismo estado para otro
   ancho, y una media query no acepta un umbral variable. */
@media(max-width:1220px){
  .ek-ruta[data-n="5"]{ flex-direction:column; align-items:stretch; }
  .ek-ruta[data-n="5"] .ek-ruta-c{ flex:none; padding:9px 0; }
  .ek-ruta[data-n="5"] .ek-ruta-ln{ display:none; }
}

/* =====================================================================
   12 · REGISTRO DE ASISTENCIA (Información Reuniones)

   La primera versión de la cola era una TABLA PLANA de pendientes, una
   fila por (campus, culto, fecha). Con los datos reales eso son 48 filas
   que repiten «Culto Domingo AM» cuatro veces por semana —una por
   campus— durante ocho semanas.

   El problema no era el largo: la tabla plana MIENTE SOBRE LA FORMA DEL
   DATO. Esto no es una lista, es una grilla de semanas × (campus ×
   culto). Y son dos trabajos con dos ritmos: cerrar el domingo recién
   pasado (cada semana, dos minutos, casi todo el uso) y pasar a limpio
   números sueltos de semanas atrás (una vez). Por eso hay DOS vistas —
   `?vista=semana` y `?vista=grilla`— y no una superficie que sirva mal a
   las dos. Comparativa viva: docs/rediseno_reuniones.html.
   ===================================================================== */

/* ── (retirada) La línea de tiempo semanal ──────────────────────────
   Acá vivían `.ek-tl*`: ocho barras, una por semana, donde la altura era
   cuánta gente vino y el punteado «sin registrar», y que además servían
   de navegador. Se retiraron por pedido explícito del dueño del sistema:
   confundían.

   Queda dicho para no reponerlas sin querer. Nacieron para resolver algo
   real —había DOS dibujos del mismo eje temporal, uno para registrar y
   otro para mirar— y ese problema ya está resuelto de otra forma: la
   tendencia vive sólo en las estadísticas, y para encontrar huecos la
   Grilla es mejor que un gráfico porque muestra la celda exacta que
   falta. Ver docs/rediseno_reuniones_interfaz.html.
   ------------------------------------------------------------------ */

/* ── El navegador de la semana enfocada ──────────────────────────────── */
.ek-sem{ display:flex; align-items:center; justify-content:space-between; gap:14px;
  padding:12px 4px 16px; }
.ek-sem-t{ font-size:17px; font-weight:600; color:var(--ink); letter-spacing:-.01em; }
.ek-sem-s{ font-size:12.5px; color:var(--mut); margin-top:1px; }
.ek-sem-nav{ display:flex; gap:6px; flex-shrink:0; }
.ek-sem-nav a, .ek-sem-nav span{ width:34px; height:34px; border-radius:var(--r-sm);
  border:1px solid var(--ln); background:var(--sf); color:var(--ink2);
  display:inline-flex; align-items:center; justify-content:center; text-decoration:none; }
.ek-sem-nav a:hover{ background:var(--sf3); }
/* El «siguiente» de la semana en curso no es un botón apagado por gusto:
   no se puede registrar la asistencia de un culto que no ha ocurrido. */
.ek-sem-nav span{ opacity:.4; cursor:not-allowed; }

/* ── La fila de un culto dentro de la semana ────────────────────────── */
.ek-cul{ display:grid; grid-template-columns:1fr auto; gap:14px; align-items:center;
  padding:13px 15px; border:1px solid var(--ln); border-radius:var(--r);
  background:var(--sf); margin-bottom:8px; }
.ek-cul.ok{ border-color:var(--ok-bd); background:var(--ok-sf); }
/* La que todavía no ocurre: se muestra para que la semana esté completa,
   pero no se puede registrar. Baja de tono en vez de esconderse — si no,
   la semana en curso parecería a la que le faltan filas. */
.ek-cul.fut{ opacity:.6; }
.ek-cul-n{ font-size:14.5px; font-weight:600; color:var(--ink); }
.ek-cul-s{ font-size:12px; color:var(--mut); margin-top:2px; }
.ek-cul-r{ display:flex; align-items:center; gap:8px; }
.ek-cul-in{ width:104px; text-align:right; font-family:var(--mono); }
.ek-cul-hecho{ font-family:var(--mono); font-size:19px; font-weight:600; color:var(--ok); }
.ek-cul-nh{ font-family:var(--mono); font-size:12px; color:var(--warn); }

/* ⚠️ En el teléfono la fila se APILA. Sin esto el bloque de la derecha
   —campo + «No hubo» + «Guardar»— mide más que los 375px de la pantalla y
   se sale de la tarjeta, metiendo scroll horizontal en TODA la página.
   Medido en la maqueta antes de construirlo: el borde de la fila caía en
   331px y el último botón llegaba a 400px. */
@media(max-width:640px){
  .ek-cul{ grid-template-columns:1fr; gap:10px; }
  .ek-cul-r{ flex-wrap:wrap; }
  .ek-cul-in{ flex:1; min-width:0; width:auto; text-align:left; }
  .ek-sem{ flex-direction:column; align-items:flex-start; gap:10px; }
}

/* ── La grilla (carga histórica) ─────────────────────────────────────
   Filas = semanas, columnas = cultos. Es la forma real del dato, y sirve
   para pasar a limpio varias semanas de corrido sin navegar.

   ⚠️ Va SIEMPRE acotada a un campus concreto: en consolidado las columnas
   serían campus × culto y la tabla se desborda. La pantalla lo impone. */
.ek-gr-wrap{ overflow-x:auto; }
.ek-gr{ width:100%; border-collapse:separate; border-spacing:0; font-size:13px; }
.ek-gr th{ font-size:11px; font-weight:600; color:var(--mut); text-align:center;
  padding:8px 6px; background:var(--sf2); border-bottom:1px solid var(--ln);
  white-space:nowrap; }
.ek-gr th:first-child{ text-align:left; }
.ek-gr td{ padding:5px 6px; border-bottom:1px solid var(--ln2); text-align:center; }
.ek-gr td:first-child{ text-align:left; font-family:var(--mono); font-size:12px; color:var(--ink2); }
.ek-gr input{ width:68px; text-align:center; font-family:var(--mono); font-size:13px;
  padding:5px 4px; border:1px solid var(--ln); border-radius:var(--r-sm); background:var(--sf); }
.ek-gr input:focus{ outline:none; border-color:var(--acc); box-shadow:0 0 0 3px var(--acc-sf); }
.ek-gr input.hecho{ background:var(--ok-sf); border-color:var(--ok-bd); color:var(--ok); font-weight:600; }
.ek-gr .ek-gr-nh{ font-family:var(--mono); font-size:11px; color:var(--warn); }
.ek-gr .ek-gr-fut{ font-family:var(--mono); font-size:11px; color:var(--fnt); }
/* Reuniones fuera del catálogo (columna «Otras»). A diferencia de las
   columnas fijas, el rótulo va en la CELDA y no en la cabecera: cambia en
   cada fila —«Congreso fyg», «Red de jóvenes»—. Se apilan porque una misma
   semana puede traer varias: lo normal es una, pero la del Congreso trae
   siete y esa fila tiene que crecer en vez de esconderlas. */
.ek-gr .ek-gr-otra{ display:flex; align-items:center; justify-content:space-between;
  gap:8px; padding:3px 0; }
.ek-gr .ek-gr-otra + .ek-gr-otra{ border-top:1px solid var(--ln); }
/* El nombre cede el ancho al número: el input tiene medida fija y el
   rótulo se trunca con «…», que para eso lleva `title` con el completo. */
.ek-gr .ek-gr-otra .ek-sb{ flex:1; min-width:0; text-align:left;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ek-gr .ek-gr-otra input{ flex:0 0 auto; }

/* =====================================================================
   10 · CENTRO DE WHATSAPP (Bienvenida) · ago 2026
   Spec: docs/superpowers/specs/2026-08-23-centro-whatsapp-design.md

   ⚠️ ESTA PANTALLA IMITA A WHATSAPP WEB A PROPÓSITO, por pedido explícito
   del dueño del sistema. Es la ÚNICA del proyecto que no sigue el patrón
   tabla + riel, y también la única donde el verde no significa un estado
   sino una marca ajena: es el color de WhatsApp, y la gente que va a
   operar esto reconoce esa pantalla antes de leerla.
   NO tomar esto como permiso para un segundo estilo: cualquier pantalla
   nueva sigue las reglas de la sección 1 salvo que tenga esta misma
   razón — parecerse a una herramienta que el operador ya usa a diario.
   ================================================================== */

/* Los colores REALES de WhatsApp Web, no una aproximación: si va a
   imitarla, la mitad del valor está en que se reconozca de inmediato.
   Viven acá y no en :root porque son de esta pantalla y de ninguna otra
   — meterlos en los tokens globales invitaría a usarlos en cualquier
   parte, que es exactamente lo que la advertencia de arriba prohíbe. */
.wa-g, .dv-g, .ek-msgq-wa{
  --wa-verde:#d9fdd3;      /* burbuja saliente */
  --wa-verde-bd:#c5f0be;
  --wa-fondo:#f5f6f8;      /* el fondo de la aplicación (era el beige de WhatsApp) */
  --wa-panel:#ffffff;
  --wa-hd:#f0f2f5;         /* cabeceras */
  --wa-ln:#e9edef;
  --wa-tx:#111b21;
  --wa-tx2:#667781;
  --wa-sel:#f0f2f5;        /* fila seleccionada */
  --wa-tick:#53bdeb;       /* el doble check azul */
  /* ⚠️ EL ACENTO DEL CHROME DE LOS CENTROS, y tiene que ser un token
     propio. `--acc` (#0e2a63) está calibrado contra superficie CLARA y
     estas cabeceras son `--wa-hd`, que en oscuro vale #202c33: azul marino
     sobre pizarra es prácticamente invisible —el paso activo del asistente
     de derivación desaparecía del riel—. Y `--acc-nav` tampoco sirve solo:
     es el azul claro del menú y sobre el #f0f2f5 del tema claro queda
     lavado. Son los dos, uno por tema, como el resto de este juego. */
  --wa-acc:#0e2a63;
}

/* ⚠️ EL JUEGO LO COMPARTEN LOS DOS CENTROS (`.wa-g` y `.dv-g`), y por eso
   se declara UNA vez. Copiarlo al bloque 12 era la forma segura de que un
   día el chat y la derivación se vieran de dos verdes distintos — la misma
   trampa que este archivo ya documenta para --gob-* contra EK_AV_TONOS.
   Que el centro de derivación use esta piel es decisión explícita del
   dueño del sistema (23-ago-2026): la excepción de la sección 10 deja de
   ser de una pantalla y pasa a ser el lenguaje de LOS CENTROS. Sigue sin
   ser permiso para una tercera piel: cualquier pantalla que no sea un
   centro es tabla + riel, y el color sigue significando estado en ellas.

   El modo oscuro de WhatsApp Web, con los tres estados de tema que usa
   el resto del sistema. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .wa-g,
  :root:not([data-theme="light"]) .dv-g,
  :root:not([data-theme="light"]) .ek-msgq-wa{
    --wa-verde:#005c4b; --wa-verde-bd:#025144;
    --wa-fondo:#0b141a; --wa-panel:#111b21; --wa-hd:#202c33;
    --wa-ln:#222d34; --wa-tx:#e9edef; --wa-tx2:#8696a0; --wa-sel:#2a3942;
    --wa-acc:#7fa6ff;
  }
}
:root[data-theme="dark"] .wa-g,
:root[data-theme="dark"] .dv-g,
:root[data-theme="dark"] .ek-msgq-wa{
  --wa-verde:#005c4b; --wa-verde-bd:#025144;
  --wa-fondo:#0b141a; --wa-panel:#111b21; --wa-hd:#202c33;
  --wa-ln:#222d34; --wa-tx:#e9edef; --wa-tx2:#8696a0; --wa-sel:#2a3942;
  --wa-acc:#7fa6ff;
}

/* La proporción de WhatsApp Web: la lista ocupa un tercio y no crece
   más — al revés que .visita-g, donde lo ancho va a la izquierda. */
/* ⚠️ `margin-top` PROPIO, no heredado de la pantalla. Este panel se pegaba
   al borde de la cinta de cifras —los dos filetes formaban una sola línea y
   se leía como una tarjeta partida— porque el margen lo ponía cada pantalla
   en un `style=` y ésta no lo tenía. Puesto en la clase, los tres centros
   respiran igual y ninguno puede olvidarlo. */
/* ⚠️ DOS FICHAS, NO UNA CAJA PARTIDA (ago 2026, pedido explícito). El
   centro era un solo rectángulo con un filete al medio, y esa forma decía
   que la lista y la conversación son dos mitades de lo mismo. No lo son:
   una es la cola de trabajo y la otra la persona que se está atendiendo —se
   miran por separado y en el teléfono ni siquiera conviven—. Con dos
   tarjetas, el `gap` dice eso sin una palabra.
   ⚠️ El `overflow:hidden` se MUDÓ a cada columna. Estaba acá y era lo que
   recortaba las esquinas del conjunto; dejado en el grid, las cabeceras
   grises se salían por las esquinas redondeadas de cada ficha. */
.wa-g{ display:grid; grid-template-columns:minmax(300px,.42fr) minmax(0,1fr);
  gap:var(--gap); align-items:stretch;
  margin-top:var(--gap); color:var(--wa-tx);
  /* Alto fijo: en un chat el campo de escribir tiene que quedar siempre
     a la vista sin perseguirlo con la rueda. */
  height:calc(100vh - var(--top-h) - var(--bot-h) - var(--pad)*2 - 96px);
  min-height:460px; }

/* Cada columna es una FICHA: su borde, su radio, su sombra y su recorte. El
   `border-right` que hacía de divisor se fue con la caja única. */
.wa-panel-lista{ background:var(--wa-panel); display:flex; flex-direction:column;
  min-height:0; border:1px solid var(--wa-ln); border-radius:var(--r);
  overflow:hidden; box-shadow:var(--sh); }
/* ---------------------------------------------------------------------
 * EL FONDO DEL HILO: el gris de la aplicación con el emblema de la iglesia,
 * en vez del beige de WhatsApp (ago 2026, pedido explícito del dueño del
 * sistema). Deja de imitar a WhatsApp en lo único que no aportaba —el
 * color— y pasa a ser el mismo fondo que tiene el resto del sistema, con
 * la misma marca. La estructura y el resto de la piel no cambian.
 *
 * ⚠️ VA EN `.wa-conv`, QUE NO SCROLLEA, y no en `.wa-hilo`, que sí. Es
 * exactamente la lección que este archivo ya escribió para `.ek-shell`:
 * puesta en el elemento que scrollea, la marca se va con los mensajes en
 * vez de quedarse detrás, y además obliga a repintar el fondo en cada
 * cuadro. Acá sale gratis porque el contenedor mide lo que mide y está
 * quieto por construcción; `.wa-hilo` queda transparente para dejarlo ver.
 *
 * ⚠️ Y VA COMO `background-image`, NO como un ::before. Un pseudo-elemento
 * posicionado queda ENCIMA de los hijos por orden de pintado — la trampa
 * que ya se pagó con la marca de agua de `.ek-shell`, con `.ek-card-acc` y
 * con la aurora de `.ek-hero`.
 *
 * La opacidad viene horneada en el alfa del PNG: `opacity` no se puede
 * aplicar a una capa de fondo por separado.
 * ------------------------------------------------------------------- */
.wa-conv{ display:flex; flex-direction:column; min-height:0;
  border:1px solid var(--wa-ln); border-radius:var(--r); overflow:hidden;
  box-shadow:var(--sh);
  background-color:var(--wa-fondo);
  background-image:url("/assets/img/logo-renacer-agua.png");
  background-repeat:no-repeat;
  background-position:center;
  background-size:min(58%, 360px); }

/* ---- cabeceras: el gris de WhatsApp, no --sf2 ---- */
.wa-lista-hd{ padding:9px 12px; background:var(--wa-hd); flex-shrink:0; }
/* ⚠️ El fondo NO alcanza: sin `color` ni `border-color`, el input se queda
   con el `--ink` y el `--bd` de tema claro, que son de tema claro SIEMPRE.
   En oscuro daba 1.04:1 — lo que se tecleaba era invisible, con un borde
   blanco alrededor. Su hermano de al lado (`.wa-filtro`) no lo sufría
   porque sí declara los tres. */
.wa-lista-hd .inp{ border-radius:8px; background:var(--wa-panel);
  color:var(--wa-tx); border-color:var(--wa-ln); }
.wa-lista-hd .inp::placeholder{ color:var(--wa-tx2); opacity:.75; }

.wa-hd{ display:flex; align-items:center; gap:11px; padding:9px 14px;
  background:var(--wa-hd); flex-shrink:0; }
.wa-hd-bd{ flex:1; min-width:0; }
.wa-hd-nm{ font-weight:600; font-size:14.5px; color:var(--wa-tx);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.wa-hd-sb{ font-size:12px; color:var(--wa-tx2); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }

/* ---- la lista ---- */
/* El filtro de la lista, EN LA MISMA FILA que el buscador. Fueron cuatro
   chips (chocaban y saltaban de línea) y después un select en fila propia,
   que se comía 43px de una columna de alto fijo — o sea una fila y media de
   contactos menos, en la lista que ES la pantalla.
   ⚠️ `flex:0 0 auto` con `width:auto`: el select se ajusta a su opción más
   larga y no le quita al buscador más de lo que necesita. Con `flex:1` los
   dos quedaban a la mitad y el buscador no aceptaba ni un nombre completo. */
.wa-filtro{ flex:0 0 auto; width:auto; max-width:52%; padding-right:26px;
  border-radius:8px; background:var(--wa-panel); border-color:var(--wa-ln);
  color:var(--wa-tx); font-size:12px; }

.wa-lista{ overflow-y:auto; flex:1; min-height:0; background:var(--wa-panel); }

.wa-c{ display:flex; gap:12px; align-items:center; width:100%;
  padding:10px 14px; border:0; background:transparent; cursor:pointer;
  text-align:left; font:inherit; color:var(--wa-tx);
  border-bottom:1px solid var(--wa-ln); }
.wa-c:hover{ background:var(--wa-sel); }
.wa-c.on{ background:var(--wa-sel); }
.wa-c:focus-visible{ outline:2px solid var(--acc); outline-offset:-2px; }

.wa-c-bd{ flex:1; min-width:0; }
.wa-c-nm{ font-weight:400; font-size:14.5px; color:var(--wa-tx);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.wa-c-tx{ font-size:12.5px; color:var(--wa-tx2); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; margin-top:2px;
  display:flex; align-items:center; gap:4px; }
.wa-c-mt{ display:flex; flex-direction:column; align-items:flex-end; gap:4px;
  flex-shrink:0; }
.wa-c-hr{ font-size:11px; color:var(--wa-tx2); white-space:nowrap; }

/* Las dos marcas de la fila. ⚠️ NO son excluyentes: alguien puede estar
   pendiente de saludo Y tener la ventana abierta. */
.wa-pin{ font-size:9.5px; letter-spacing:.03em; text-transform:uppercase;
  padding:1px 6px; border-radius:9px; font-weight:600; white-space:nowrap; }
.wa-pin.pend{ background:var(--warn-sf); color:var(--warn); }
/* La píldora verde de WhatsApp para los no leídos / ventana viva. */
.wa-pin.viva{ background:#25d366; color:#0b3d24; }

/* ---- el hilo ----
   El fondo con el patrón tenue de WhatsApp, dibujado con gradientes en
   vez de una imagen: no hay que servir un archivo y escala solo. */
/* ⚠️ La conversación es la columna flex del panel, y su display va acá y no
   en línea: escrito en el marcado, le ganaba al atributo `hidden` y el
   estado vacío se pintaba encima de la conversación. Lleva su propio
   `[hidden]` para que el atributo vuelva a mandar. */
.wa-chat{ display:flex; flex-direction:column; flex:1; min-height:0; }
.wa-chat[hidden]{ display:none; }
/* Y que `hidden` gane en todo el panel, no sólo acá: media docena de
   bloques se muestran y esconden con el atributo. */
.wa-conv [hidden]{ display:none; }

/* ⚠️ Transparente: el fondo y la marca los pone `.wa-conv`, que no
   scrollea. El punteado que imitaba el doodle de WhatsApp se retiró — con
   el emblema detrás son dos marcas de agua discutiendo por el mismo
   espacio, y la que dice algo es la de la iglesia. */
.wa-hilo{ flex:1; overflow-y:auto; padding:18px 6%; display:flex;
  flex-direction:column; gap:3px; min-height:0; background:transparent; }

.wa-b{ max-width:65%; padding:6px 9px 8px; border-radius:8px;
  font-size:14.2px; line-height:1.38; white-space:pre-wrap;
  word-break:break-word; position:relative; box-shadow:0 1px .5px rgba(11,20,26,.13); }
/* La colita de la burbuja, el detalle que hace que se lea como WhatsApp. */
.wa-b::after{ content:""; position:absolute; top:0; width:8px; height:13px; }
.wa-b.sal{ align-self:flex-end; background:var(--wa-verde);
  border-top-right-radius:0; }
.wa-b.sal::after{ right:-8px;
  background:linear-gradient(225deg, var(--wa-verde) 50%, transparent 50%); }
.wa-b.ent{ align-self:flex-start; background:var(--wa-panel);
  border-top-left-radius:0; }
.wa-b.ent::after{ left:-8px;
  background:linear-gradient(135deg, var(--wa-panel) 50%, transparent 50%); }
/* Mensajes seguidos del mismo lado: sin colita y más juntos, como allá. */
.wa-b.sal + .wa-b.sal, .wa-b.ent + .wa-b.ent{ border-radius:8px; margin-top:-1px; }
.wa-b.sal + .wa-b.sal::after, .wa-b.ent + .wa-b.ent::after{ display:none; }

/* La hora y el check van dentro de la burbuja, abajo a la derecha. */
.wa-b-mt{ font-size:11px; color:var(--wa-tx2); float:right;
  margin:6px -3px -4px 8px; display:inline-flex; gap:3px; align-items:center; }
.wa-b-mt .leido{ color:var(--wa-tick); }

/* La miniatura de YouTube: pegada a los tres bordes superiores de la
   burbuja (de ahí el margen negativo, igual al padding de .wa-b), como la
   tarjeta de enlace de WhatsApp de verdad. `aspect-ratio` evita que la
   burbuja salte de alto mientras la imagen carga. */
.wa-yt{ display:block; position:relative; margin:-6px -9px 6px; line-height:0;
  overflow:hidden; background:var(--sf2); }
.wa-b.sal .wa-yt{ border-radius:8px 0 0 0; }
.wa-b.ent .wa-yt{ border-radius:0 8px 0 0; }
.wa-yt img{ display:block; width:100%; aspect-ratio:16/9; object-fit:cover; }
.wa-yt-play{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  background:rgba(0,0,0,.15); }
.wa-yt-play i{ width:42px; height:42px; border-radius:50%; background:rgba(0,0,0,.55);
  color:#fff; font-size:15px; display:flex; align-items:center; justify-content:center;
  padding-left:2px; }

.wa-dia{ align-self:center; background:var(--wa-panel); color:var(--wa-tx2);
  font-size:11.5px; padding:4px 11px; border-radius:8px; margin:10px 0 6px;
  box-shadow:0 1px .5px rgba(11,20,26,.13); }

/* ---- el pie ---- */
.wa-ft{ padding:9px 14px; background:var(--wa-hd); flex-shrink:0;
  display:flex; gap:9px; align-items:flex-end; }
.wa-ft textarea{ flex:1; resize:none; min-height:40px; max-height:110px;
  border-radius:9px; border:0; background:var(--wa-panel); padding:10px 13px;
  font-size:14.2px; color:var(--wa-tx); font-family:inherit; }
.wa-ft textarea:focus{ outline:none; box-shadow:0 0 0 2px var(--acc-sf); }
/* El campo con el texto de una plantilla: se ve, pero no se toca.
   ⚠️ `--wa-sel` y NO `--acc-sf`: éste último es un tinte claro pensado
   para la interfaz general, y el chat de WhatsApp tiene su PROPIO tema
   oscuro con texto casi blanco (`--wa-tx`) — un fondo claro ahí deja el
   texto casi ilegible (blanco sobre blanco). `--wa-sel` es el tono que
   este mismo panel ya usa para «fila seleccionada»: distinto del fondo
   normal y con el contraste ya resuelto en los dos temas.
   El selector necesita la misma especificidad que `.wa-ft textarea` (que
   fija el fondo) para ganarle sin `!important`. */
.wa-ft textarea.wa-txt-bloqueado{ background:var(--wa-sel); cursor:not-allowed; }
.wa-ft textarea.wa-txt-bloqueado:focus{ box-shadow:none; }
/* El botón redondo de enviar. */
.wa-env{ width:40px; height:40px; border-radius:50%; border:0; flex-shrink:0;
  background:#00a884; color:#fff; cursor:pointer; font-size:15px; }
.wa-env:disabled{ opacity:.45; cursor:default; }

/* ⚠️ Con la ventana cerrada el campo NO se esconde: se explica por qué.
   Esconderlo deja a quien opera buscándolo. */
.wa-cerrado{ flex:1; background:var(--warn-sf); border:1px solid var(--warn-bd);
  border-radius:9px; padding:9px 12px; font-size:12.5px; color:var(--ink2); }

/* Los dos botones que quedan cuando la ventana está cerrada: copiar el
   saludo o mandarlo desde el teléfono. Van DENTRO del aviso, no al lado:
   son la respuesta a lo que el aviso acaba de decir. */
.wa-cerrado-ac{ display:flex; gap:7px; margin-top:9px; flex-wrap:wrap; }

.wa-vacio{ flex:1; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:10px; color:var(--wa-tx2); font-size:13.5px;
  padding:24px; text-align:center; }

/* El puntito que respira mientras el refresco está activo: dice que la
   pantalla está viva sin gritarlo. */
.wa-vivo{ width:7px; height:7px; border-radius:50%; background:#25d366;
  display:inline-block; flex-shrink:0; }
@media (prefers-reduced-motion:no-preference){
  .wa-vivo{ animation:waLatido 2s ease-in-out infinite; }
}
@keyframes waLatido{ 0%,100%{ opacity:1 } 50%{ opacity:.35 } }

/* ---- la bandeja de números desconocidos ----
   Quien escribió al número de la iglesia sin ser una visita registrada. Va
   en un modal y no en la lista: no son contactos del proceso, son gente que
   todavía no entró al sistema. */
.wa-desc{ display:flex; gap:12px; align-items:center; padding:10px 0;
  border-bottom:1px solid var(--ln); }
.wa-desc:last-child{ border-bottom:0; }
.wa-desc-bd{ flex:1; min-width:0; }
.wa-desc-nm{ font-family:var(--mono); font-size:13.5px; color:var(--ink);
  display:flex; align-items:center; gap:7px; }
.wa-desc-tx{ font-size:12.5px; color:var(--ink2); margin-top:2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.wa-desc-mt{ font-size:11px; color:var(--mut); margin-top:2px; }
.wa-desc-ac{ display:flex; gap:7px; flex-shrink:0; }

/* ⚠️ EL BOTÓN DE LA BARRA SUPERIOR VA EN VERDE DE WHATSAPP, ícono e
   insignia, y no en el rojo de `.ek-globo`. En este sistema el rojo
   significa «esto está mal», y acá no hay nada mal: hay alguien esperando.
   El verde además dice de un vistazo de qué canal viene el aviso, que es lo
   que lo distingue de la campanita de al lado.
   ⚠️ Es la ÚNICA excepción a que el color signifique estado, y se sostiene
   porque acá el color no describe una condición sino un CANAL — igual que
   el azul del menú no dice que algo esté bien o mal. */
.ek-icb-wa i{ color:#25d366; }
.ek-icb-wa:hover i{ color:#1da851; }
.ek-globo-wa{ background:#25d366; color:#0b3d24; }

@media (max-width:640px){
  .wa-desc{ flex-direction:column; align-items:stretch; gap:8px; }
}

/* ---- teléfono ----
   Una columna a la vez, como cualquier app de mensajería. */
.wa-volver{ display:none; }
@media (max-width:1100px){
  .wa-g{ grid-template-columns:1fr; height:calc(100vh - var(--top-h) - var(--bot-h) - 110px); }
  .wa-g[data-vista="lista"] .wa-conv{ display:none; }
  .wa-g[data-vista="hilo"]  .wa-panel-lista{ display:none; }
  .wa-volver{ display:inline-flex; }
  .wa-b{ max-width:82%; }
  .wa-hilo{ padding:14px 12px; }
}

/* =====================================================================
   11 · REGISTRAR VISITA · rediseño ago 2026
   Formulario CENTRADO en vez de la grilla 1.9fr/1fr de .visita-g.

   ⚠️ POR QUÉ SE FUE LA COLUMNA LATERAL: encerraba el formulario en ~600px,
   y con dieciocho campos en dos columnas angostas la pantalla se hacía
   larguísima — había que rodarla dos veces para registrar a una persona
   que está esperando de pie. Lo que vivía ahí NO se perdió: la jornada
   subió a una tira de una línea y «últimas que registraste» bajó al pie,
   en horizontal. Los dos se consultan de reojo; ninguno necesitaba un
   tercio del ancho permanente.
   ================================================================== */

/* ⚠️ SIN TOPE DE ANCHO. Tuvo `max-width:880px` mientras era una columna
   sola con la lista al pie: ahí el tope era correcto —trece campos
   estirados a lo ancho de un monitor no se leen—. Al pasar a dos columnas
   (ago 2026) ese mismo tope dejó el formulario en 567px y la lista en 298
   dentro de una ventana de 1700, con muchísimo margen vacío a los lados y
   una página el doble de alta de lo necesario: exactamente el scroll que
   se venía a evitar. El ancho lo reparte ahora la grilla. */
.cap-wrap{ display:flex; flex-direction:column; gap:var(--gap); }

/* ---- la tira de la jornada ----
   Una línea con lo que la columna decía en tres tarjetas. El aviso de
   «sin teléfono» va acá y no escondido: es lo único de esta pantalla que
   pide actuar AHORA, mientras la persona sigue en la sala. */
.cap-tira{ display:flex; align-items:center; gap:16px; flex-wrap:wrap;
  background:var(--sf); border:1px solid var(--ln); border-radius:var(--r);
  padding:10px 16px; }
.cap-tira-n{ display:flex; align-items:baseline; gap:7px; }
.cap-tira-n b{ font-size:22px; font-family:var(--mono); line-height:1;
  color:var(--acc); }
.cap-tira-n span{ font-size:12.5px; color:var(--mut); }

.cap-cultos{ display:flex; gap:14px; flex-wrap:wrap; flex:1; min-width:0; }
/* ⚠️ Cada culto lleva su BARRA DE PROPORCIÓN, no sólo la cifra. Con los
   números sueltos hay que dividir de cabeza para saber si el de las 10 trajo
   el doble que el de las 12, que es justamente lo que se mira. Es la misma
   barra que tenía la columna lateral antes del rediseño (`.vs-cul-b`), y
   vuelve porque acomodar no era podar.
   Va en columna —rótulo arriba, barra abajo— y no en línea: en una tira
   horizontal cada culto es una celda angosta, y una barra al lado del número
   quedaría de veinte píxeles. */
.cap-cul{ display:flex; flex-direction:column; gap:3px; min-width:104px;
  font-size:12px; color:var(--mut); }
.cap-cul-t{ display:flex; align-items:baseline; gap:5px; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; }
.cap-cul b{ font-family:var(--mono); color:var(--ink); font-size:13px; }
.cap-cul-b{ display:block; height:4px; border-radius:99px;
  background:var(--sf3); overflow:hidden; }
.cap-cul-b i{ display:block; height:100%; border-radius:99px; background:var(--acc); }

.cap-avi{ display:flex; align-items:center; gap:7px; font-size:12.5px;
  background:var(--warn-sf); border:1px solid var(--warn-bd);
  color:var(--ink2); border-radius:var(--r-sm); padding:5px 10px; }
.cap-avi i{ color:var(--warn); }

/* ---- las últimas, al pie y en horizontal ----
   Antes eran filas apiladas en la columna; acá son tarjetas que caben en
   una línea. Se miran para corregir un dato recién tecleado, no para
   recorrerlas. */
.cap-ult{ display:flex; gap:10px; flex-wrap:wrap; }
.cap-u{ display:flex; align-items:center; gap:9px; flex:1 1 220px;
  min-width:0; background:var(--sf); border:1px solid var(--ln);
  border-radius:var(--r-sm); padding:8px 11px; }
/* El vacío de «Últimas que registraste», centrado en el alto de la columna.
   Sólo tiene sentido dentro de `.visita-g`: en el riel del teléfono la misma
   tarjeta mide lo que su contenido y centrar no cambia nada. */
.cap-vacio{ display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:9px; height:100%; min-height:120px; padding:20px 14px; text-align:center;
  color:var(--mut); font-size:12.5px; line-height:1.5; }
.cap-vacio > i{ font-size:20px; color:var(--fnt); }

.cap-u-bd{ flex:1; min-width:0; }
.cap-u-bd .ek-nm{ display:block; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; }

/* ⚠️ EN LA COLUMNA LATERAL EL BOTÓN PIERDE LA PALABRA y queda el lápiz solo.
   Medido: la fila ahí mide 231px y «Corregir» se lleva 72, dejando 93 para el
   nombre — que necesita ~120 y salía cortado en TODAS las filas («Prueba
   Och…»). El nombre es lo único que esta lista existe para dejar leer, así
   que la palabra que se va es la del botón, no la del dato.
   Se acota a `.visita-g` a propósito: en cualquier otro ancho la fila tiene
   espacio de sobra y el botón con texto se explica mejor solo. */
.visita-g .cap-u .cap-u-fix span{ display:none; }
.visita-g .cap-u .cap-u-fix{ padding-left:8px; padding-right:8px; }

@media (max-width:700px){
  .cap-tira{ gap:10px; }
  .cap-u{ flex:1 1 100%; }
}

/* =====================================================================
 * 12 · CENTRO DE DERIVACIÓN  (modulos/bienvenida/bandeja.php)
 *
 * Spec: docs/superpowers/specs/2026-08-23-centro-derivacion-design.md
 *
 * ⚠️ USA LA PIEL DE WHATSAPP WEB, igual que el centro de mensajes, por
 * decisión explícita del dueño del sistema (23-ago-2026). Los tokens NO se
 * redefinen acá: `.dv-g` está en el mismo bloque que `.wa-g` en la sección
 * 10, así que los dos centros no pueden derivar a dos verdes distintos.
 *
 * Esto AMPLÍA la excepción documentada en la sección 10 —era «esta
 * pantalla», ahora es «los centros»— y no la disuelve: cualquier pantalla
 * que no sea un centro sigue siendo tabla + riel, con el color
 * significando ESTADO. Acá los estados siguen vivos donde importan (el
 * aviso de «sin GC», el ámbar de su grupo en la cola): la piel pinta el
 * CHROME, no la información.
 *
 * ⚠️ Y ES MÁS QUE UNA LISTA DE CHATS: el panel derecho EJECUTA el proceso
 * —elegir GC, escribir el motivo, avisar al líder y derivar— sin abrir un
 * modal. Por eso el cuerpo no es un hilo de burbujas sobre el beige, sino
 * una HOJA blanca sobre él: es el mismo gesto de WhatsApp (contenido claro
 * sobre el fondo beige) aplicado a un formulario en vez de a mensajes.
 * ===================================================================== */

/* Dos fichas, igual que `.wa-g` y por la misma razón: la cola de trabajo y
   la persona que se está atendiendo no son dos mitades de lo mismo. */
.dv-g{ display:grid; grid-template-columns:minmax(280px,.38fr) minmax(0,1fr);
  gap:var(--gap); align-items:stretch;
  margin-top:var(--gap); color:var(--wa-tx);
  /* Alto de respaldo: el botón de derivar tiene que quedar siempre a la
     vista sin perseguirlo con la rueda. El valor exacto lo fija ekAlto()
     en la pantalla, porque lo que va encima cambia (el aviso de «sin GC»
     sólo aparece cuando hay alguien en ese caso). */
  height:calc(100vh - var(--top-h) - var(--bot-h) - var(--pad)*2 - 196px);
  min-height:480px; }

/* ---- columna izquierda · la cola ---- */
.dv-col{ background:var(--wa-panel); display:flex; flex-direction:column;
  min-height:0; border:1px solid var(--wa-ln); border-radius:var(--r);
  overflow:hidden; box-shadow:var(--sh); }
.dv-hd{ padding:9px 12px; background:var(--wa-hd); flex-shrink:0; }
/* El buscador redondo sobre la cabecera gris, como el de WhatsApp Web. */
.dv-hd .inp{ border-radius:8px; background:var(--wa-panel);
  border-color:var(--wa-ln); color:var(--wa-tx); }
.dv-lista{ overflow-y:auto; flex:1; min-height:0; background:var(--wa-panel); }

/* Encabezado de tramo. Pegajoso porque la cola se recorre entera y sin él,
   a mitad del scroll, no se sabe si lo que se mira es de esta semana o de
   hace dos años — que es la diferencia entre trabajo y backlog. */
.dv-grp{ position:sticky; top:0; z-index:1; display:flex; align-items:center;
  gap:8px; padding:7px 13px; background:var(--wa-hd);
  border-bottom:1px solid var(--wa-ln); font-size:11px; letter-spacing:.04em;
  text-transform:uppercase; color:var(--wa-tx2); font-weight:600; }
.dv-grp b{ font-family:var(--mono); font-size:12px; color:var(--wa-tx);
  font-weight:600; }
/* ⚠️ El grupo «sin GC» conserva el ámbar de ESTADO. La piel de WhatsApp
   pinta el chrome; lo que informa sigue hablando el idioma del sistema. */
.dv-grp.avi{ background:var(--warn-sf); color:var(--ink2); }
.dv-grp.avi i{ color:var(--warn); }

/* Una persona de la cola. Es un <button>: se llega con Tab y se dispara con
   Enter, cosa que un <div onclick> no hace. */
.dv-c{ display:flex; gap:12px; align-items:center; width:100%; text-align:left;
  padding:9px 13px; border:0; border-bottom:1px solid var(--wa-ln);
  background:none; cursor:pointer; font:inherit; color:inherit; }
.dv-c:hover{ background:var(--wa-sel); }
.dv-c.on{ background:var(--wa-sel); box-shadow:inset 4px 0 0 var(--wa-tick); }
.dv-c:focus-visible{ outline:2px solid var(--acc); outline-offset:-2px; }
/* ⚠️ Las tres son <span>: dentro de un <button> sólo cabe contenido de
   frase, así que un <div> ahí es marcado inválido. Por eso llevan
   `display:block` a mano — un span no lo trae. */
.dv-c-bd{ display:block; flex:1; min-width:0; }
.dv-c-nm{ display:block; font-weight:400; font-size:14.5px; color:var(--wa-tx);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dv-c-tx{ display:block; font-size:12.5px; color:var(--wa-tx2);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; margin-top:1px; }
.dv-c-mt{ display:block; font-size:11px; color:var(--wa-tx2);
  white-space:nowrap; flex-shrink:0; align-self:flex-start; padding-top:2px;
  text-align:right; }
/* ⚠️ LA FECHA EXACTA, BAJO EL «hace…». Las listas decían sólo cuánto
   tiempo pasó —«hace 3 semanas»— y eso sirve para barrer la cola por
   urgencia, pero no para trabajar: quien llama a alguien necesita saber
   QUÉ DÍA vino, y quien revisa un caso necesita la fecha para cruzarla con
   lo que tiene anotado por fuera. Las dos, no una: el relativo se lee de
   un vistazo y la fecha se lee cuando hace falta, así que va más chica y
   en mono, que es como este sistema escribe los datos duros. */
.dv-c-fe{ display:block; margin-top:1px; font-family:var(--mono);
  font-size:10px; color:var(--wa-tx2); opacity:.75; }

/* ---- columna derecha · el panel de trabajo ---- */
/* El mismo fondo y la misma marca que el hilo del chat: son los tres
   paneles de trabajo del mismo ministerio y no hay razón para que uno se
   vea de otro color. Mismas dos reglas: va en el contenedor que no
   scrollea (`.dv-pan-bd` es el que se mueve) y como `background-image`. */
.dv-pan{ display:flex; flex-direction:column; min-height:0;
  border:1px solid var(--wa-ln); border-radius:var(--r); overflow:hidden;
  box-shadow:var(--sh);
  background-color:var(--wa-fondo);
  background-image:url("/assets/img/logo-renacer-agua.png");
  background-repeat:no-repeat;
  background-position:center;
  background-size:min(58%, 360px); }
/* ⚠️ EL PANEL DE TRABAJO ES LA COLUMNA FLEX, Y SIN ESTA REGLA TODO SE
   ROMPE EN SILENCIO. `#dvPanel` es el que reparte la altura entre cabecera,
   tira, cuerpo y pie; sin `display:flex`, el `flex:1` del cuerpo no lo lee
   nadie y éste crece hasta su contenido —983px medidos dentro de una
   grilla de 480—, así que el pie con el botón de derivar queda fuera y
   `overflow:hidden` recorta lo que sobra: la pantalla se ve entera y NO
   SE PUEDE BAJAR. Ya pasó una vez, al reescribir esta sección para la piel
   de WhatsApp: la regla se perdió y nada falló, sólo dejó de scrollear.
   Lleva su propio `[hidden]` para que el atributo le gane a este display
   aunque la clase se use fuera de `.dv-pan`. */
.dv-work{ display:flex; flex-direction:column; min-height:0; flex:1; }
.dv-work[hidden]{ display:none; }

/* La barra de la conversación: gris de WhatsApp, no el medianoche del
   sistema — es el mismo lugar donde el chat pone a su interlocutor. */
.dv-pan-hd{ display:flex; align-items:center; gap:11px; padding:9px 14px;
  background:var(--wa-hd); border-bottom:1px solid var(--wa-ln);
  flex-shrink:0; }
.dv-pan-hd-bd{ flex:1; min-width:0; }
.dv-pan-nm{ font-weight:600; font-size:14.5px; color:var(--wa-tx);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dv-pan-sb{ font-size:12px; color:var(--wa-tx2); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; margin-top:2px; }

/* La tira de datos duros, sobre la cabecera y fuera del cuerpo
   scrolleable — igual que en el riel: su fondo y su filete están dibujados
   para ir de borde a borde. Necesita `flex-shrink:0` (va en línea) porque
   es hermana flex de un cuerpo `flex:1`: sin eso sale cortada por la
   mitad, y no lo detecta ninguna prueba de estado. */
.dv-pan .ek-rail-sum{ background:var(--wa-hd); border:0;
  border-bottom:1px solid var(--wa-ln); }
.dv-pan .ek-rail-sum dt{ color:var(--wa-tx2); }
.dv-pan .ek-rail-sum dd{ color:var(--wa-tx); }

/* ⚠️ SIN HOJA BLANCA: el cuerpo va directo sobre el fondo. La tuvo mientras
   el panel era beige —sobre ese crema los campos y las tarjetas, dibujados
   contra superficie clara, salían teñidos— y la hoja era el equivalente de
   la burbuja del chat. Al pasar el fondo al gris de la aplicación (--bg) el
   motivo desapareció: es el mismo gris contra el que está dibujado todo
   formulario del sistema. Y la hoja tapaba por completo la marca de agua de
   la iglesia, que es justamente lo que este fondo vino a mostrar. */
.dv-pan-bd{ flex:1; overflow-y:auto; min-height:0; padding:16px 5%; }

/* ⚠️ `hidden` TIENE QUE GANAR DENTRO DEL PANEL. El atributo esconde con una
   regla del navegador (`[hidden]{display:none}`) de especificidad mínima,
   así que cualquier clase con `display` la anula: un `.btn-secondary` es
   `inline-flex` y seguía a la vista con el atributo puesto. Media docena de
   bloques de este panel se muestran y esconden así —el buscador, el motivo,
   el aviso de WhatsApp, los rótulos, el botón de abrir la búsqueda—, y
   arreglarlos de a uno es la forma segura de que el próximo nazca roto.
   Esta regla (0,1,1) le gana a cualquier clase suelta sin !important. */
.dv-pan [hidden]{ display:none; }

/* El pie, sobre el gris de la barra de escribir del chat. */
.dv-pan-ft{ flex-shrink:0; padding:9px 14px; background:var(--wa-hd);
  border-top:1px solid var(--wa-ln); display:flex; gap:10px;
  align-items:center; }

/* ---- el asistente de derivación ----
   Reusa `.ek-tabs`/`.ek-tab` (sección 2) en vez de un componente nuevo: es
   el mismo riel de pasos del asistente de 2FA, y acá el orden ES una
   secuencia real —no se puede confirmar sin haber elegido un GC—, así que
   la numeración dice algo cierto.

   ⚠️ Los pasos son <button> y no <span> como en perfil_2fa.php: a los ya
   recorridos se vuelve pulsándolos. Un botón trae su propio fondo, borde y
   tipografía del navegador, así que hay que apagarlos o el riel sale como
   una fila de botones grises. */
/* ⚠️ `margin-bottom:0` NO ES COSMÉTICO. `.ek-tabs` trae de fábrica un
   margen NEGATIVO (`calc(var(--gap) * -1 + 2px)`) para pegarse al cuerpo
   de una tarjeta, y acá su hermano es `.dv-pan-bd`, que scrollea: el
   cuerpo empezaba 12px ANTES de que terminara el riel, así que las
   tarjetas pasaban por encima del riel al desplazarse. Es un solape de
   layout, no un problema de capas: subirle el z-index al riel lo habría
   tapado sin corregir los 12px que el cuerpo tiene de más. */
.dv-wiz-nav{ flex-shrink:0; background:var(--wa-hd);
  border-bottom:1px solid var(--wa-ln); padding:0 8px; margin-bottom:0; }
.dv-wiz-nav:empty{ display:none; }
/* ⚠️ LOS COLORES SALEN DEL JUEGO `--wa-*`, NO DE :root. `.ek-tab` está
   dibujado contra superficie clara (`--fnt` apagado, `--acc` en el activo)
   y acá el fondo es la cabecera del centro, que en tema oscuro es #202c33:
   el paso activo salía en azul marino sobre pizarra, o sea invisible. */
.dv-wiz-nav .ek-tab{ background:none; border:0; border-bottom:2px solid transparent;
  font:inherit; cursor:pointer; color:var(--wa-tx2); }
.dv-wiz-nav .ek-tab:hover{ color:var(--wa-tx); }
.dv-wiz-nav .ek-tab.on{ color:var(--wa-acc); border-bottom-color:var(--wa-acc); }
/* Los pasos que vienen no se pueden pulsar: saltarse la elección del GC
   deja el asistente en un paso que no se puede completar. Se ven, porque
   decir cuánto falta es la mitad del valor del riel.
   ⚠️ `:not(.on)` NO es decorativo. El paso ACTUAL también va `disabled`
   —pulsar donde ya estás no hace nada—, así que sin esa exclusión el
   atenuado caía sobre él y el riel se leía al revés: el paso en el que
   estás parado apagado y los que faltan, encendidos. */
.dv-wiz-nav .ek-tab[disabled]{ cursor:default; }
.dv-wiz-nav .ek-tab[disabled]:not(.on){ opacity:.6; }
.dv-wiz-nav .ek-tab[disabled]:not(.on):hover{ color:var(--wa-tx2); }

/* Un paso por vez. `[hidden]` ya lo cubre `.dv-pan [hidden]`, que le gana a
   cualquier clase suelta. */
.dv-wiz-p{ display:block; }

/* Las dos salidas de la lista de sugeridos, a lados opuestos de una fila:
   «ver más de lo mismo» y «buscar fuera de la lista» son alternativas
   entre sí, no pasos de una secuencia — apiladas se leían como lo segundo.
   El hueco de la izquierda queda vacío cuando no hay más que ver, y el de
   buscar se va solo a la derecha. En un panel angosto se apilan antes que
   truncarse. */
.dv-acc{ display:flex; align-items:center; justify-content:space-between;
  gap:10px; margin-top:12px; flex-wrap:wrap; }
.dv-acc > #dv-abrir{ margin-left:auto; }
.dv-acc .btn-secondary{ white-space:nowrap; }
@media (max-width:520px){
  .dv-acc{ flex-direction:column; align-items:stretch; }
  .dv-acc > #dv-abrir{ margin-left:0; }
  .dv-acc .btn-secondary{ justify-content:center; }
}

/* ⚠️ EL PIE EMPUJA CON LA FICHA, no con un `margin-left:auto` en el
   primario. «Atrás» se muestra y se esconde según el paso, así que colgar
   el empuje de él lo dejaba caer al centro en los pasos donde no está. */
/* ⚠️ EL PIE ALINEA A LA DERECHA POR SÍ MISMO. Repartía sólo gracias al
   `margin-right:auto` de «Ver ficha», y «Recordar a líderes» no tiene ese
   botón a propósito: sin nada que empujara, sus botones se amontonaban a la
   izquierda dejando 722px muertos a 1024px, con el primario pegado al
   borde. El `flex-end` es de la barra; el `margin-right:auto` sigue siendo
   lo que manda «Ver ficha» al otro extremo cuando existe. */
.dv-pan-ft{ justify-content:flex-end; }
.dv-pan-ft > .dv-ft-ficha{ margin-right:auto; }

/* La barra de acciones del asistente va un punto más alta que un botón
   suelto (40 contra 34): es el control que se pulsa una y otra vez en la
   pantalla que más se opera del ministerio. */
.dv-pan-ft .btn-primary,
.dv-pan-ft .btn-secondary{ height:40px; }

/* ⚠️ La ficha pierde su ETIQUETA, no su tamaño, cuando el ancho aprieta.
   Estuvo como ícono cuadrado siempre —para que los tres controles cupieran
   en 375px— y en el escritorio quedaba diminuta al lado de un primario de
   170px con medio pie vacío en medio. Acá el problema era el ancho del
   teléfono, así que se paga sólo en el teléfono. */
@media (max-width:560px){
  .dv-pan-ft > .dv-ft-ficha span{ display:none; }
  .dv-pan-ft > .dv-ft-ficha{ width:40px; padding:0; justify-content:center; }
  .dv-pan-ft > .dv-ft-ficha i{ font-size:15px; }
}
/* Ancho cómodo pero PROPIO: el primario dice «Continuar» o «Confirmar
   derivación», y estirado al ancho del panel se lee como una banda de
   color y no como un botón. */
.dv-pan-ft .btn-primary{ min-width:170px; justify-content:center; }

/* ---- el paso de confirmación ----
   ⚠️ REEMPLAZA a una tabla de siete filas rótulo/valor, todas del mismo
   peso y con el valor pegado al borde derecho. Tenía dos defectos que se
   ven de inmediato: el nombre del GC —la respuesta a la pregunta de toda
   la pantalla— se leía igual que «Campus», y en un panel ancho el rótulo
   quedaba a medio metro de su valor, así que el ojo no los unía. */
/* ⚠️ TINTA DEL PANEL, NO LA GLOBAL. Este párrafo va DIRECTO sobre el fondo
   del centro (`--wa-fondo`, #0b141a en oscuro) y no dentro de la tarjeta
   blanca. Con `--ink` —#14161b, calibrado contra superficie clara— el
   nombre de la persona quedaba casi negro sobre casi negro: contraste 1:1,
   invisible. Es la misma trampa que ya se pagó con la burbuja de WhatsApp
   en este mismo modal. Lo que está DENTRO de `.dv-cf-card` sí usa la tinta
   global, porque esa tarjeta pinta su propio `--sf`. */
/* ---- LAS FICHAS DE ESTE PANEL PERTENECEN AL JUEGO `--wa-*` ----
   ⚠️ Estaban dibujadas con los tokens GLOBALES (`--sf`, `--ln`, `--ink`),
   que son light-only, dentro de un panel cuyos tokens SÍ cambian con el
   tema. El resultado, medido:
     · claro  → ficha blanca sobre panel #f5f6f8 = 1.08:1. Invisible: se
                veía el texto flotando sin caja.
     · oscuro → la MISMA ficha blanca sobre #0b141a = 18.6:1. Un bloque
                que no pertenece al panel.
   Un token global dentro de una caja con tokens propios siempre termina
   así: coincide en un tema y choca en el otro.

   ⚠️ En claro la ficha y el panel son casi el mismo blanco A PROPÓSITO
   —es la piel de WhatsApp— así que lo que la separa NO es la luminancia
   sino la SOMBRA. Sin ella no hay contraste que subir sin romper el
   parecido; con ella la ficha se levanta y se lee como una hoja encima. */
/* ⚠️ `--sh` SOLO NO ALCANZA acá: es `0 1px 2px rgba(16,24,40,.06)`, un
   filete de apoyo pensado para tarjetas que YA contrastan con su fondo. En
   este panel la ficha y el fondo difieren 1.08:1, así que la sombra es lo
   único que la separa y tiene que levantarla de verdad. Se suma
   `--sh-open`, la elevación que el sistema ya usa para lo que se abre por
   encima de algo. */
.dv-pan .dv-cf-card{
  background:var(--wa-panel);
  border-color:var(--wa-ln);
  box-shadow:var(--sh), var(--sh-open);
}
/* Los avisos son secundarios: se apoyan, no se levantan. */
.dv-pan .dv-cf-nota{
  background:var(--wa-panel);
  border-color:var(--wa-ln);
  box-shadow:var(--sh);
}
.dv-pan .dv-cf-ttl{ color:var(--wa-tx); }
.dv-pan .dv-cf-sub{ color:var(--wa-tx2); }
/* La pastilla del ícono seguía el acento global —azul marino sobre un
   lavado claro—, que sobre una ficha oscura es una mancha clara pegada.
   Va con el acento del chrome del centro, el mismo del riel de etapas. */
.dv-pan .dv-cf-ico{ background:var(--wa-sel); color:var(--wa-acc); }

/* La tira de celdas y sus filetes. */
.dv-pan .dv-cf-datos{ background:var(--wa-hd); border-top-color:var(--wa-ln); }
.dv-pan .dv-cf-datos > div{ box-shadow:-1px 0 0 var(--wa-ln), 0 -1px 0 var(--wa-ln); }
.dv-pan .dv-cf-datos dt{ color:var(--wa-tx2); }
.dv-pan .dv-cf-datos dd{ color:var(--wa-tx); }
.dv-pan .dv-cf-datos dd.na{ color:var(--wa-tx2); }

/* El equipo del GC y lo que falta. */
.dv-pan .dv-gc-sc{ color:var(--wa-tx2); }
.dv-pan .dv-gc-eq li{ border-bottom-color:var(--wa-ln); }
.dv-pan .dv-gc-eq-nm{ color:var(--wa-tx); }
.dv-pan .dv-gc-eq-sb{ color:var(--wa-tx2); }
.dv-pan .dv-gc-vacio,
.dv-pan .dv-gc-desc{ color:var(--wa-tx2); }
.dv-pan .dv-gc-desc{ border-top-color:var(--wa-ln); }
.dv-pan .dv-gc-nota,
.dv-pan .ek-msgq-nota{ background:var(--wa-hd); color:var(--wa-tx2); }
.dv-pan .dv-gc-nota b,
.dv-pan .ek-msgq-nota b{ color:var(--wa-tx); }
.dv-pan .dv-gc-nota i,
.dv-pan .ek-msgq-nota i{ color:var(--wa-tx2); }
.dv-pan .dv-cf-nota b{ color:var(--wa-tx); }
.dv-pan .dv-cf-nota{ color:var(--wa-tx2); }
.dv-pan .dv-cf-nota i{ color:var(--wa-acc); }

/* «Cómo se decidió»: el contexto de auditoría de una derivación. Va en
   ficha porque NO es parte de la etapa en curso —no cambia al avanzar— y
   suelto entre la tira y el riel se leía como el principio de ella. Se
   apoya (`--sh`), no se levanta: es contexto, no la decisión. */
#dr-ctx{ margin:0 0 4px; padding:12px 16px 13px; border-radius:var(--r);
  background:var(--wa-panel); border:1px solid var(--wa-ln); box-shadow:var(--sh); }
#dr-ctx:empty{ display:none; }
.dr-ctx-tx{ font-size:12.5px; color:var(--wa-tx2); line-height:1.5; }
.dr-ctx-tx + .dr-ctx-tx{ margin-top:3px; }

/* Los chips de estado subieron al subtítulo de la cabecera, que es el
   renglón del panel donde el resto del sistema pone el estado. Ahí van en
   línea y sin el margen que traen dentro de una tabla. */
.dv-pan-sb{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.dv-pan-sb .ek-est{ white-space:nowrap; }

/* La ficha de formulario: lo que se ESCRIBE en una etapa, con el mismo
   peso visual que lo que se revisa. Suelto sobre el fondo del panel se leía
   como un formulario huérfano colgando de la nada. */
.dv-cf-form{ margin-top:14px; padding:14px 16px 16px; border-radius:var(--r);
  background:var(--wa-panel); border:1px solid var(--wa-ln);
  box-shadow:var(--sh), var(--sh-open); }
.dv-cf-form-tt{ font-size:10.5px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--wa-tx2); margin-bottom:11px; }

/* ⚠️ LOS CAMPOS TAMBIÉN SON DEL PANEL. `.inp` se dibuja con `--sf2` y
   `--ink`, light-only: sobre una ficha oscura quedaba una caja blanca con
   su etiqueta gris clarísima al lado. Es la misma corrección que el resto
   de esta sección, aplicada a los controles.
   Alcanza también a los campos del buscador de la primera etapa, que viven
   directo sobre el fondo del panel. */
.dv-pan .inp{ background:var(--wa-hd); border-color:var(--wa-ln); color:var(--wa-tx); }
.dv-pan .inp:focus{ background:var(--wa-panel); border-color:var(--wa-acc);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--wa-acc) 22%, transparent); }
.dv-pan .inp::placeholder{ color:var(--wa-tx2); opacity:.75; }
.dv-pan .ek-lbl,
.dv-pan .ek-hint,
.dv-pan .ek-sb,
/* ⚠️ `.ek-est` FALTABA en esta lista, y es la que más importa: sobre el
   panel oscuro daba 1.42:1, o sea se veía el punto de color y no la
   PALABRA. Y eso rompe la regla de la casa —el color de estado nunca puede
   ser la única señal—, justo en el lugar donde el anillo del avatar ya está
   diciendo lo mismo sólo con color. */
.dv-pan .ek-est,
/* Y en la COLUMNA de la lista, que este remapeo no alcanzaba: «4 grupos»
   quedaba en 3.41:1. */
.dv-col .ek-sb{ color:var(--wa-tx2); }
/* ⚠️ PERO NO DENTRO DE UNA TARJETA BLANCA. Las tarjetas de GC candidato
   (`.ek-opt`) se pintan sobre `--sf` —blanco en los dos temas, porque son
   hojas que flotan sobre el chrome oscuro del panel, igual que las burbujas
   de WhatsApp— así que ahí el remapeo de arriba deja un gris claro sobre
   blanco: 3.05:1, PEOR que la tinta original. El remapeo es para lo que se
   apoya en el panel, no para lo que trae su propia superficie. */
.dv-pan .ek-opt .ek-est,
.dv-pan .ek-opt .ek-sb,
.dv-pan .ek-opt .ek-hint,
.dv-pan .ek-opt .ek-lbl{ color:var(--ink2); }
.dv-pan .ek-rail-sc{ color:var(--wa-tx2); }

/* ⚠️ EL CHECKLIST TAMBIÉN CAMBIÓ DE FONDO. `.ek-prog-*` se dibujó para
   vivir dentro de un modal, que pinta `--sf` (blanco), y al pasar el
   resultado a una ETAPA quedó sobre `--wa-fondo`: el título salía en
   `--ink` con contraste 1.03:1 — los íconos y las notas se veían y las
   líneas parecían no tener nombre. Sólo se redefine DENTRO del panel: en
   el modal, donde sigue usándose (derivaciones antiguas, otras
   pantallas), la tinta global es la correcta. */
/* ⚠️ Y el AVISO, por lo mismo. `.ek-note` pinta `--sf` (blanco) con tinta
   `--ink`: sobre `--wa-fondo` en oscuro es una tarjeta blanca ajena, y en
   claro se pierde contra el panel. El filete de la izquierda se conserva
   —dice el nivel y no es texto, así que `--warn` sirve en los dos temas—;
   lo que se remapea es la caja y las dos tintas. */
.dv-pan .ek-note{ background:var(--wa-panel); border-color:var(--wa-ln);
  border-left-color:var(--warn); box-shadow:var(--sh), var(--sh-open);
  margin-bottom:10px; }
.dv-pan .ek-note-tt{ color:var(--wa-tx); }
.dv-pan .ek-note-tx{ color:var(--wa-tx2); }

/* ⚠️ Y EL BLOQUE DE WHATSAPP, EN LOS DOS CENTROS. `.ek-wa-bloque` pinta
   `--wa-sf`, un verde TRANSLÚCIDO (10 %): sobre una tarjeta blanca compone
   verde claro y sobre un panel oscuro, verde oscuro. Se adapta solo —
   salvo su tinta, que es `--ink` (casi negro) y sobre el oscuro daba
   **1.24:1**, o sea el teléfono invisible. Es la misma trampa de `--ink`
   sobre superficie oscura que ya se pagó con `.dv-cf-lead` y
   `.ek-prog-tt`; la diferencia es que acá el fondo es translúcido y una
   medición ingenua la esconde: hay que componer el alfa contra el panel.
   ⚠️ Va también en `.wa-conv` —el pie de «Enviar bienvenida» monta el
   mismo bloque desde que la previa vive ahí— y el `.ek-hint` de adentro
   entra con ella: 2.81:1 no es legible tampoco. */
.dv-pan .ek-wa-bloque .ek-nm,
.wa-conv .ek-wa-bloque .ek-nm{ color:var(--wa-tx); }
/* ⚠️ `--wa-tx2` sobre el verde compuesto daba 3.86:1, bajo el mínimo para
   texto de 11px. Se probó bajarle la opacidad para que no compitiera con
   el teléfono y salió PEOR (1.77): una tinta clara translúcida se funde
   con el verde en vez de separarse. Va la tinta plena. Queda un punto más
   fuerte de lo que un aviso pide, y es el precio correcto: se lee. */
.wa-conv .ek-wa-bloque .ek-hint{ color:var(--wa-tx); }

.dv-pan .ek-prog-tt{ color:var(--wa-tx); }
.dv-pan .ek-prog-nt{ color:var(--wa-tx2); }
.dv-pan .ek-prog-ln{ border-bottom-color:var(--wa-ln); }

.dv-cf-lead{ margin:2px 0 12px; font-size:13px; color:var(--wa-tx2); }
.dv-cf-lead b{ color:var(--wa-tx); font-weight:600; }

.dv-cf-card{ background:var(--sf); border:1px solid var(--ln);
  border-radius:var(--r); overflow:hidden; }
.dv-cf-hd{ display:flex; align-items:center; gap:12px; padding:14px 16px; }
/* La pastilla del ícono va en el tinte de acento, como toda sección del
   sistema (`.ek-form-sec .ek-ic`): un color por módulo competiría con el
   color que acá significa estado. */
.dv-cf-ico{ width:38px; height:38px; border-radius:10px; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--acc-sf); color:var(--acc); font-size:15px; }
.dv-cf-hd-bd{ min-width:0; display:flex; flex-direction:column; gap:2px; }
.dv-cf-ttl{ font-size:15.5px; font-weight:600; color:var(--ink);
  line-height:1.25; overflow-wrap:anywhere; }
.dv-cf-sub{ font-size:12px; color:var(--mut); overflow-wrap:anywhere; }

/* Rótulo ARRIBA y valor abajo, en celdas que se reparten el ancho: el
   mismo patrón de `.ek-rail-sum`, que esta pantalla ya usa para la ficha
   de la persona. Los filetes van en `box-shadow` de la celda y no en el
   `gap` — con tres celdas en dos columnas sobra media pista, y ese hueco
   pintado del color del filete se lee como una celda vacía. */
.dv-cf-datos{ display:grid; grid-template-columns:repeat(auto-fit,minmax(168px,1fr));
  margin:0; background:var(--sf2); border-top:1px solid var(--ln); overflow:hidden; }
.dv-cf-datos > div{ padding:10px 16px; min-width:0;
  box-shadow:-1px 0 0 var(--ln2), 0 -1px 0 var(--ln2); }
.dv-cf-datos dt{ font-size:10.5px; color:var(--fnt); letter-spacing:.04em;
  text-transform:uppercase; }
.dv-cf-datos dd{ margin:3px 0 0; font-size:12.5px; color:var(--ink);
  overflow-wrap:anywhere; }
/* Lo que FALTA se dice, no se omite: un GC sin líder cargado o sin nadie
   derivado todavía cambia la decisión. En tinta apagada, para que se lea
   como ausencia y no como valor. */
.dv-cf-datos dd.na{ color:var(--fnt); font-style:italic; }

/* Las consecuencias de ESTA derivación —el motivo que queda escrito, el
   WhatsApp que sale o no— van como avisos y no como más filas de datos:
   no son atributos del grupo. */
.dv-cf-nota{ display:flex; gap:10px; align-items:flex-start; margin-top:10px;
  padding:10px 14px; border:1px solid var(--ln); border-radius:var(--r);
  background:var(--sf); font-size:12.5px; color:var(--mut); }
.dv-cf-nota i{ margin-top:2px; color:var(--acc); flex-shrink:0; }
.dv-cf-nota b{ display:block; color:var(--ink); font-weight:600;
  font-size:12.5px; margin-bottom:1px; }
.dv-cf-nota span{ min-width:0; overflow-wrap:anywhere; }
.dv-cf-nota.apagada{ background:var(--sf2); }
.dv-cf-nota.apagada i{ color:var(--fnt); }

/* ---- el mensaje que se va a mandar, en la ventana del resultado ----
   La ventana decía «WhatsApp · 2 destinatarios · en cola» y nunca QUÉ se
   mandaba. Acá se muestra el texto de CADA persona, con la misma piel de
   WhatsApp que usa el centro de «Enviar bienvenida»: quien aprueba un
   envío tiene que ver lo que verá quien lo recibe.

   ⚠️ LOS TOKENS NO SE COPIAN: `.ek-msgq-wa` se agregó a la declaración de
   `.wa-g, .dv-g` (sección 12), que es donde el juego `--wa-*` vive UNA
   vez. Duplicar los valores acá sería la forma segura de que un día el
   chat y esta ventana se vieran de dos verdes distintos — la trampa que
   ese bloque advierte. Y hace falta declararlos en algún selector propio
   porque este modal se emite al final del <body>, fuera de `.dv-g`. */
/* ⚠️ `color` NO ES OPCIONAL ACÁ. `.wa-b` no fija tinta: en el centro la
   hereda de `.wa-conv`, que sí la declara. Suelta dentro del modal
   heredaba `--ink` —la tinta OSCURA de la aplicación— y en tema oscuro la
   burbuja quedaba verde oscuro sobre verde oscuro: el mensaje existía y
   no se podía leer. Es la trampa de siempre: un color calibrado contra
   otra superficie. */
.ek-msgq-wa{ margin-top:12px; padding:14px 16px; border-radius:var(--r);
  border:1px solid var(--wa-ln); background:var(--wa-fondo);
  color:var(--wa-tx); }

/* Quién recibe ESTE mensaje. Va afuera de la burbuja: adentro sería parte
   del texto que la persona lee, y no lo es. */
.ek-msgq-dest + .ek-msgq-dest{ margin-top:14px; }
.ek-msgq-nom{ display:flex; align-items:center; gap:7px; margin-bottom:5px;
  font-size:12px; color:var(--wa-tx2); }
.ek-msgq-nom b{ color:var(--wa-tx); font-weight:600; }
.ek-msgq-nom i{ color:#25d366; }

/* El hilo: una burbuja SALIENTE, que es lo que somos acá — el mensaje lo
   manda la iglesia. Reusa `.wa-b.sal` (sección 12) con su colita; esto
   sólo la alinea, porque fuera de `.wa-hilo` no hay contenedor flex que
   respete su `align-self`. */
.ek-msgq-hilo{ display:flex; flex-direction:column; align-items:flex-end; }
.ek-msgq-hilo .wa-b{ max-width:100%; }

/* La casilla de «a quién le aviso», en la línea del nombre. La etiqueta
   entera es el blanco: una casilla de 14px suelta es un blanco pobre. */
label.ek-msgq-nom{ cursor:pointer; }
.ek-msgq-ck{ flex-shrink:0; margin:0; cursor:pointer; }
/* Desmarcado se ATENÚA, no se esconde: sigue siendo del equipo, y verlo
   apagado es lo que dice que se decidió no avisarle. */
.ek-msgq-dest.off{ opacity:.45; }
.ek-msgq-dest.off .wa-b{ filter:grayscale(1); }

/* El encabezado del bloque de aviso: a cuántos les llega. */
/* Mismo caso: encabeza el bloque de mensajes sobre el fondo del panel. */
.ek-msgq-tt{ margin-top:14px; font-size:12.5px; color:var(--wa-tx2); }
.ek-msgq-tt b{ color:var(--wa-tx); font-weight:600; }
/* Mientras se resuelve a quién avisarle, y también el caso de que no haya
   nadie: el mismo lugar, para que la respuesta aparezca donde se la
   estaba esperando. */
.ek-msgq-load{ margin-top:14px; font-size:12.5px; color:var(--wa-tx2); }
/* El selector de plantilla, sólo cuando hay más de una. */
.ek-msgq-pla{ margin-top:9px; }
.ek-msgq-pla .ek-lbl{ display:block; margin-bottom:4px; }

/* Lo que NO va a llegar y por qué —quien no tiene teléfono, quien quedó
   sin vincular—. Va después de los mensajes y en tono apagado: no es una
   alarma, es un dato que falta en la ficha de esa persona. */
.ek-msgq-nota{ display:flex; gap:10px; align-items:flex-start; margin-top:8px;
  padding:10px 13px; border:1px solid var(--ln); border-radius:var(--r);
  background:var(--sf2); font-size:12.5px; color:var(--mut); }
.ek-msgq-nota i{ margin-top:2px; color:var(--fnt); flex-shrink:0; }
.ek-msgq-nota b{ display:block; color:var(--ink); font-weight:600; margin-bottom:1px; }
.ek-msgq-nota span{ min-width:0; overflow-wrap:anywhere; }

/* La identidad en la ficha (modal): avatar + estado en una fila, al
   principio del cuerpo. Van acá porque ek_modal() —a diferencia de
   ek_riel_hd()— no tiene ranura de marca ni de estado, y agregarle una
   habría sido una segunda cabecera de modal que mantener. */
.fk-id{ display:flex; align-items:center; gap:11px; margin-bottom:16px; }
.fk-id:empty{ display:none; }

/* ⚠️ El aviso de «no hay GC en su campus» NO esconde el panel: explica por
   qué la lista viene vacía y deja abierto el buscador manual. Esconderlo
   dejaba a quien deriva mirando un hueco, que es exactamente lo que hacía
   la pantalla anterior treinta y dos veces seguidas. */
.dv-sin{ background:var(--warn-sf); border:1px solid var(--warn-bd);
  border-radius:var(--r-sm); padding:11px 13px; font-size:12.5px;
  color:var(--ink2); margin-bottom:14px; }
.dv-sin b{ color:var(--ink); }

/* Estado vacío: sin nadie elegido, el panel dice qué hacer en vez de
   quedarse en blanco. */
.dv-vacio{ flex:1; display:flex; flex-direction:column; align-items:center;
  justify-content:center; gap:11px; color:var(--wa-tx2); font-size:13.5px;
  padding:28px; text-align:center; }
.dv-vacio i{ font-size:30px; opacity:.5; }

/* ---- teléfono: una columna a la vez, como cualquier centro ---- */
.dv-volver{ display:none; }
@media (max-width:1100px){
  .dv-g{ grid-template-columns:1fr;
    height:calc(100vh - var(--top-h) - var(--bot-h) - 150px); }
  .dv-g[data-vista="lista"] .dv-pan{ display:none; }
  .dv-g[data-vista="panel"] .dv-col{ display:none; }
  .dv-volver{ display:inline-flex; }
  .dv-pan-bd{ padding:14px 12px; }
}


/* =====================================================================
 * 13 · LA FICHA DE UNA PERSONA  (includes/ficha_modal.php)
 *
 * Spec: docs/superpowers/specs/2026-08-23-centro-derivacion-design.md
 *
 * ⚠️ DOS COLUMNAS, y ésa es toda la idea. La ficha tenía una sola: ocho
 * pares rótulo/valor apilados, después el recorrido, después el historial
 * completo de contactos — un modal que había que scrollear para ver quién
 * era la persona. Partida en «quién es» / «cómo va», entra de una sola
 * mirada y el modal deja de necesitar ancho para nada.
 *
 * ⚠️ Un valor VACÍO no se pinta. Ocho filas con «—» son ocho renglones que
 * no dicen nada y empujan hacia abajo los que sí. Lo decide el JS al armar
 * cada fila.
 * ===================================================================== */

/* Avatar + estado, al principio del cuerpo: ek_modal() no tiene ranura de
   marca ni de estado (ek_riel_hd() sí). */
.fk-id{ display:flex; align-items:center; gap:11px; margin-bottom:14px; }
.fk-id:empty{ display:none; }

.fk-cols{ display:grid; grid-template-columns:1fr 1fr; gap:22px; }

/* Rótulo de sección, más chico y más callado que el del riel: acá hay
   cuatro en el mismo cuerpo y con el peso de `.ek-rail-sc` competían con
   los datos que encabezan. */
.fk-sc{ font-size:10.5px; font-weight:600; letter-spacing:.07em;
  text-transform:uppercase; color:var(--mut); margin:0 0 8px; }
.fk-cols > div > .fk-sc:not(:first-child){ margin-top:18px; }
.fk-de{ font-family:var(--mono); font-weight:400; letter-spacing:0;
  text-transform:none; opacity:.75; }

/* ⚠️ Rótulo y valor en DOS COLUMNAS de la misma fila, no uno encima del
   otro. Apilados, ocho datos son dieciséis renglones; al lado, son ocho —y
   el ojo baja por una sola columna de valores en vez de zigzaguear. El
   rótulo se trunca antes que el valor: «Oración de fe o iglesia previa» es
   largo y lo que importa es el sí o el no. */
.fk-dl{ display:flex; flex-direction:column; gap:0; margin:0; }
.fk-d{ display:grid; grid-template-columns:minmax(0,auto) minmax(0,1fr);
  gap:12px; align-items:baseline; padding:5px 0;
  border-bottom:1px solid var(--ln); }
.fk-d:last-child{ border-bottom:0; }
.fk-d dt{ font-size:11.5px; color:var(--mut); overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.fk-d dd{ margin:0; font-size:13px; color:var(--ink); text-align:right;
  word-break:break-word; }

.fk-obs{ margin-top:10px; font-size:12.5px; color:var(--ink2);
  background:var(--sf2); border:1px solid var(--ln);
  border-radius:var(--r-sm); padding:9px 11px; }

/* El recorrido, más apretado que el del riel: acá conviven dos listas en la
   misma columna y el aire del original las separaba media pantalla. */
.fk-time{ margin:0; }
.fk-time li{ padding-bottom:11px; }
.fk-time li:last-child{ padding-bottom:0; }

@media (max-width:640px){
  .fk-cols{ grid-template-columns:1fr; gap:16px; }
  .fk-cols > div:last-child > .fk-sc:first-child{ margin-top:4px; }
}


/* =====================================================================
 * 14 · LA PREVIA DE UNA PLANTILLA DEL AGENTE
 *   (includes/ficha… no: modulos/config/mensajeria.php + api/plantilla_agente_previa.php)
 *
 * Dos piezas y la segunda es la que importa: el texto tal como lo va a leer
 * la persona, y el mapeo posicional que viaja a Meta. El texto puede verse
 * perfecto y el mensaje salir mal igual — Meta no conoce los {tokens},
 * recibe {{1}}, {{2}} y una lista de valores en orden.
 * ===================================================================== */

/* El texto, como una burbuja de WhatsApp: es lo que se va a leer en un
   teléfono, y verlo en un párrafo de formulario no dice lo mismo.
   ⚠️ `pre-wrap`: las plantillas llevan saltos de línea y son parte del
   mensaje — colapsarlos muestra un texto que nadie va a recibir. */
.ek-wa-previa{ white-space:pre-wrap; word-break:break-word;
  background:#d9fdd3; border:1px solid #c5f0be; border-radius:8px;
  padding:10px 12px; font-size:13px; line-height:1.5; color:#111b21; }
:root[data-theme="dark"] .ek-wa-previa{ background:#005c4b; border-color:#025144; color:#e9edef; }
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .ek-wa-previa{ background:#005c4b; border-color:#025144; color:#e9edef; }
}

/* El mapeo. Tabla de tres columnas angostas dentro de un riel de 392px:
   la posición en mono, el token apagado y el valor de muestra en tinta. */
.ek-prev-map td{ padding:5px 8px; font-size:12px; vertical-align:top; }
.ek-prev-map td:first-child{ width:46px; color:var(--acc); font-weight:600; }
.ek-prev-map td:nth-child(2){ width:82px; }
.ek-prev-map td:last-child{ color:var(--ink); word-break:break-word; }

/* ---------------------------------------------------------------------
 * SUB-SECCIÓN DENTRO DE UNA TARJETA
 *
 * ⚠️ Nace en el Centro de mensajería (ago 2026), donde «Envío» tenía CUATRO
 * tarjetas: cada transporte partido en «configurar» y «probar». Configurar
 * arriba y bajar a otra caja para comprobar si sirve es exactamente la
 * secuencia que uno hace siempre, y estaban separadas. Juntas, guardar y
 * probar quedan a un palmo.
 * Es un filete y un rótulo chico, no una tarjeta anidada: dos bordes
 * concéntricos leen como dos cosas distintas, que es justo lo que se vino a
 * quitar.
 * ------------------------------------------------------------------- */
.ek-sub-sec{ margin-top:18px; padding-top:15px; border-top:1px solid var(--ln2); }
.ek-sub-sec-tt{ font-size:11px; font-weight:600; letter-spacing:.07em;
  text-transform:uppercase; color:var(--mut); margin-bottom:6px; }

/* ---- Centro de mensajería: piezas propias del panel ---- */
/* Los interruptores del evento, en fila. Antes eran tres casillas sueltas
   en tres columnas de una tabla, sin más rótulo que el encabezado — o sea
   que fuera de la tabla no se sabía cuál era cuál.
   ⚠️ `flex:0 0 auto` y `width:auto`: `.ek-opt` es una opción de formulario
   a ancho completo, así que sin esto los tres quedaban apilados ocupando
   toda la tarjeta, que es lo contrario de una fila de interruptores. */
.msg-sw{ display:flex; gap:10px; flex-wrap:wrap; }
.msg-sw .ek-opt{ margin:0; flex:0 0 auto; width:auto; padding:8px 13px;
  /* `display:flex` explícito: `.ek-opt` no lo trae, así que el `gap` no
     aplicaba y la casilla quedaba pegada a su rótulo. */
  display:flex; gap:9px; align-items:center; }
/* Lo que se lee, bajo el editor de cada canal: el editor muestra el texto
   CRUDO con {{tokens}}, y esto lo mismo ya resuelto. */
.msg-previa{ white-space:pre-wrap; word-break:break-word; font-size:12.5px;
  line-height:1.5; color:var(--ink2); background:var(--sf2);
  border:1px solid var(--ln); border-radius:var(--r-sm); padding:9px 11px; }
.msg-previa.vacia{ color:var(--fnt); font-style:italic; }
.msg-canal{ margin-bottom:14px; }

/* =====================================================================
   15 · LOS DOCUMENTOS LEGALES · política de privacidad y términos

   Se pintan en DOS superficies con el mismo marcado: los modales de la
   aplicación (`ek_legal_modales()`) y la página pública `/legal.php`.
   Por eso `.lg-doc` no fija ancho ni fondo — se lo pone el contenedor —
   y todo lo de `.lg-page` para abajo es exclusivo de la página.

   ⚠️ La MEDIDA de lectura es lo único que de verdad importa acá. Un
   documento legal se abandona por muro de texto, no por falta de color:
   `.lg-doc p` va a 68ch y con interlínea alta. En el modal (880px) eso
   deja aire a los costados a propósito.
   ===================================================================== */

/* --- el documento, común a las dos superficies --------------------- */
.lg-doc{ font-size:13.5px; line-height:1.65; color:var(--ink2); }
.lg-doc p{ max-width:68ch; margin:0 0 11px; }
.lg-lead{ font-size:14.5px; line-height:1.6; color:var(--ink);
  padding-bottom:13px; margin-bottom:18px; border-bottom:1px solid var(--ln2); }

.lg-h{ font-size:14.5px; font-weight:650; color:var(--ink);
  margin:26px 0 9px; padding-top:3px; letter-spacing:-.01em; }
.lg-h:first-of-type{ margin-top:6px; }

.lg-doc b{ color:var(--ink); font-weight:600; }

/* Listas. `.lg-ul-d` es la de derechos: cada ítem abre con el nombre del
   derecho en negrita, así que necesita más aire entre uno y otro. */
.lg-ul{ max-width:68ch; margin:0 0 12px; padding-left:19px; }
.lg-ul li{ margin-bottom:5px; }
.lg-ul-d li{ margin-bottom:9px; }

/* La ficha del responsable. Rejilla y no tabla: son pares rótulo/valor,
   no datos comparables entre sí. */
.lg-dl{ display:grid; gap:1px; background:var(--ln2); border:1px solid var(--ln);
  border-radius:var(--r-sm); overflow:hidden; margin:0 0 14px; max-width:68ch; }
.lg-dl > div{ display:grid; grid-template-columns:minmax(0,190px) minmax(0,1fr);
  gap:12px; background:var(--sf); padding:9px 13px; }
.lg-dl dt{ font-size:12px; color:var(--mut); }
.lg-dl dd{ margin:0; font-size:13px; color:var(--ink); }

/* --- las tablas ---------------------------------------------------- */
/* ⚠️ El envoltorio con scroll propio es obligatorio: la tabla de
   destinatarios tiene cuatro columnas y en el teléfono no entra. Sin
   esto el desbordamiento se lo come el modal y la página entera scrollea
   de lado. */
.lg-tabla{ width:100%; border-collapse:collapse; margin:0 0 15px;
  font-size:12.5px; display:block; overflow-x:auto; }
.lg-tabla thead th{ text-align:left; font-weight:600; font-size:11px;
  text-transform:uppercase; letter-spacing:.04em; color:var(--mut);
  background:var(--sf2); padding:8px 11px; border-bottom:1px solid var(--ln);
  white-space:nowrap; }
.lg-tabla td{ padding:9px 11px; border-bottom:1px solid var(--ln2);
  vertical-align:top; line-height:1.55; min-width:120px; }
.lg-tabla tbody tr:last-child td{ border-bottom:0; }

/* La fila de un dato sensible se marca, porque el trato que recibe es
   distinto y el documento lo promete más abajo. Tinte + etiqueta: el
   color no puede ser la única señal. */
.lg-sens td{ background:var(--warn-sf); }
.lg-tag{ display:inline-block; font-size:10px; font-weight:600;
  text-transform:uppercase; letter-spacing:.04em; color:var(--warn);
  border:1px solid var(--warn-bd); border-radius:999px;
  padding:1px 7px; margin-left:4px; white-space:nowrap; }

/* --- notas y cierre ------------------------------------------------ */
.lg-nota{ max-width:68ch; background:var(--sf2); border-left:3px solid var(--ln);
  border-radius:0 var(--r-sm) var(--r-sm) 0; padding:10px 13px;
  margin:0 0 14px; font-size:12.5px; color:var(--ink2); }
.lg-firma{ margin-top:22px; padding-top:12px; border-top:1px solid var(--ln2);
  font-family:var(--mono); font-size:11.5px; color:var(--mut); }

/* El marcador de lo que falta por completar. Va en rojo y no en gris: es
   un dato ausente en un documento que obliga, no una omisión menor. */
.lg-falta{ font-family:var(--mono); font-size:12px; color:var(--danger);
  background:var(--dan-sf); border:1px dashed var(--dan-bd);
  border-radius:var(--r-sm); padding:0 5px; }
.lg-borrador{ display:flex; gap:10px; align-items:flex-start;
  background:var(--dan-sf); border:1px solid var(--dan-bd);
  border-radius:var(--r-sm); padding:11px 13px; margin:0 0 18px;
  font-size:12.5px; line-height:1.55; color:var(--ink2); }
.lg-borrador i{ color:var(--danger); margin-top:2px; }
.lg-borrador code{ font-family:var(--mono); font-size:11.5px;
  background:var(--sf); border:1px solid var(--ln); border-radius:3px;
  padding:0 4px; }

/* --- los enlaces al pie de un formulario --------------------------- */
/* ⚠️ `.lg-lnk` es un <button>, no un <a>: abre un modal, no navega. Se
   le quita toda la piel de botón para que se lea como enlace — un botón
   con aspecto de botón ahí compite con el de enviar el formulario. */
.lg-pie{ font-size:11.5px; color:var(--mut); }
.lg-lnk{ background:none; border:0; padding:0; font:inherit; font-size:inherit;
  color:var(--acc); text-decoration:underline; text-underline-offset:2px;
  cursor:pointer; }
.lg-lnk:hover{ color:var(--ink); }
.lg-lnk:focus-visible{ outline:2px solid var(--acc); outline-offset:2px;
  border-radius:2px; }

/* =====================================================================
   15b · La PÁGINA pública /legal.php

   Reusa el lienzo azul de las pantallas de acceso (`.au-body` y su
   aurora) y repite su gesto: el campo azul es de la iglesia, la hoja
   blanca es el documento.
   ===================================================================== */
/* ⚠️ `.lg-body` ES AUTOSUFICIENTE: se pinta su propio azul y NO se apoya en
   `.au-body`, el lienzo del login. Estuvo apoyada en él para heredarle el
   color y fue un error por dos motivos.
   El primero, de CASCADA: `ekklesia-auth.css` se enlaza DESPUÉS que este
   archivo, así que `.au-body::before` le ganaba a `.lg-body::before` por
   orden de fuente —misma especificidad (0,1,1)— y ninguna anulación de
   aquí surtía efecto. Pelear eso con `!important` o subiendo
   especificidad habría escondido el segundo motivo, que es el de fondo:
   ese lienzo está dibujado para una pantalla de UNA VISTA. Centra con
   `place-items:center`, se fija `min-height:100vh` y cuelga un emblema de
   660px de `bottom:-230px`. En un documento que scrollea, ese emblema
   queda anclado al final del DOCUMENTO —no del viewport— y deja un vacío
   enorme con el logo gigante debajo del texto.
   Consecuencia buscada: legal.php tampoco carga ya ekklesia-auth.css. */
.lg-body{ margin:0; box-sizing:border-box; background:var(--nav); color:#fff; }

/* ⚠️ 880 y no 1000: la medida de lectura son 68ch (~570px), así que un
   pliego de 925px útiles dejaba 350px muertos a la derecha de cada
   párrafo mientras las tablas sí llegaban al borde — el conjunto se leía
   descuadrado. 880 deja el pliego ajustado al texto y todavía da 784px a
   las tablas, que es lo que necesita la de destinatarios (4 columnas). */
.lg-page{ max-width:880px; margin:0 auto; padding:34px 20px 56px;
  position:relative; z-index:1; }

.lg-top{ text-align:center; margin-bottom:22px; }
.lg-marca{ display:inline-block; }
.lg-marca img{ width:198px; height:54px; object-fit:contain; }
.lg-top-sub{ margin:9px 0 0; font-size:12px; letter-spacing:.03em;
  color:rgba(255,255,255,.62); }

.lg-nav{ display:flex; gap:8px; justify-content:center; flex-wrap:wrap;
  margin-bottom:20px; }
.lg-nav-a{ display:inline-flex; align-items:center; gap:7px;
  font-size:12.5px; font-weight:500; text-decoration:none;
  color:rgba(255,255,255,.78); background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.16); border-radius:999px;
  padding:7px 15px; transition:background var(--t-fast) var(--ease); }
.lg-nav-a:hover{ background:rgba(255,255,255,.15); color:#fff; }
.lg-nav-a.k{ background:#fff; border-color:#fff; color:var(--nav); }

.lg-hoja{ background:var(--sf); border-radius:var(--r-lg);
  box-shadow:var(--sh-lg); padding:34px 38px 38px; }
.lg-sec{ scroll-margin-top:20px; }
.lg-t1{ font-size:23px; font-weight:680; color:var(--ink);
  letter-spacing:-.02em; margin:0 0 4px; text-wrap:balance; }
.lg-ver{ font-family:var(--mono); font-size:11.5px; color:var(--mut);
  margin:0 0 20px; }
.lg-corte{ border:0; border-top:1px solid var(--ln); margin:40px 0 34px; }

.lg-fin{ text-align:center; margin-top:26px; font-size:11.5px;
  color:rgba(255,255,255,.55); }
.lg-fin p{ margin:3px 0; }

@media (max-width:720px){
  .lg-page{ padding:24px 13px 44px; }
  .lg-hoja{ padding:22px 17px 26px; border-radius:var(--r); }
  .lg-t1{ font-size:19px; }
  .lg-dl > div{ grid-template-columns:1fr; gap:2px; }
}

/* Un documento legal se imprime y se archiva: hay que dejarlo salir
   limpio, sin el lienzo azul ni la navegación entre documentos. */
@media print{
  .lg-body{ background:#fff; }
  .lg-top, .lg-nav, .lg-fin, .au-aurora{ display:none !important; }
  .lg-page{ max-width:none; padding:0; }
  .lg-hoja{ box-shadow:none; padding:0; border-radius:0; }
  .lg-sec{ break-inside:auto; }
  .lg-h{ break-after:avoid; }
  .lg-tabla{ display:table; overflow:visible; break-inside:avoid; }
}

/* =====================================================================
   15c · La PUERTA de aceptación

   ⚠️ Los documentos van DENTRO del modal, plegados en <details>. Pedir
   que alguien acepte algo que tiene que ir a buscar a otra pestaña es la
   forma segura de que nadie lo lea — y de que el consentimiento sea
   nominal. Plegados y no abiertos porque son largos: lo que tiene que
   caber sin scroll es el botón, no el documento.
   ===================================================================== */
.lg-gate-docs{ display:grid; gap:9px; margin-bottom:15px; }
.lg-gate-d{ border:1px solid var(--ln); border-radius:var(--r-sm);
  background:var(--sf); overflow:hidden; }
.lg-gate-d > summary{ cursor:pointer; list-style:none; padding:11px 13px;
  font-size:13px; font-weight:600; color:var(--ink); background:var(--sf2);
  display:flex; align-items:center; gap:9px; }
.lg-gate-d > summary::-webkit-details-marker{ display:none; }
.lg-gate-d > summary::after{ content:'\f078'; font-family:'Font Awesome 6 Free';
  font-weight:900; font-size:10px; color:var(--mut); margin-left:auto;
  transition:transform var(--t-fast) var(--ease); }
.lg-gate-d[open] > summary::after{ transform:rotate(180deg); }
.lg-gate-d > summary > i{ color:var(--acc); }
.lg-gate-v{ font-family:var(--mono); font-size:10.5px; font-weight:500;
  color:var(--mut); background:var(--sf3); border-radius:999px; padding:1px 7px; }

/* ⚠️ Alto máximo con scroll PROPIO: sin esto el documento estira el modal
   hasta empujar el pie —y con él la casilla y el botón— fuera de la
   pantalla, o sea que la puerta no se puede contestar. */
.lg-gate-bd{ max-height:290px; overflow-y:auto; padding:14px 15px;
  border-top:1px solid var(--ln); }
.lg-gate-bd .lg-doc{ font-size:12.5px; }
.lg-gate-bd .lg-lead{ font-size:13px; }

.lg-gate-ok{ display:flex; gap:10px; align-items:flex-start; cursor:pointer;
  background:var(--acc-sf,var(--sf2)); border:1px solid var(--ln);
  border-radius:var(--r-sm); padding:12px 14px; font-size:13px;
  line-height:1.5; color:var(--ink); }
.lg-gate-ok input{ margin-top:2px; flex-shrink:0; width:16px; height:16px;
  accent-color:var(--acc); cursor:pointer; }

/* El puente entre los dos documentos, al pie. Existe porque son páginas
   independientes: la navegación de la cabecera queda a varios scrolls en
   cuanto el documento crece, y sobre todo en el teléfono. Va más claro
   que el resto del pie —es una acción, no un dato de contacto—. */
.lg-fin-otro{ padding-bottom:10px; margin-bottom:10px;
  border-bottom:1px solid rgba(255,255,255,.12); color:rgba(255,255,255,.72); }
.lg-fin-otro a{ color:#fff; text-decoration:underline; text-underline-offset:3px; }

/* La nota que reemplazó al interruptor de WhatsApp en el panel de un
   evento. No es un aviso de error: explica por qué ese canal no se ofrece
   —las plantillas del motor no se pueden registrar en Meta, y el disparo
   automático de WhatsApp está descartado a propósito— y dónde sí ocurre.
   Va en el verde de la marca porque habla de WhatsApp, no de un problema. */
.msg-nota-wa{ display:flex; gap:10px; align-items:flex-start; margin-top:11px;
  background:var(--wa-sf); border:1px solid var(--wa); border-left-width:3px;
  border-radius:var(--r-sm); padding:10px 12px; font-size:12.5px;
  line-height:1.55; color:var(--ink2); }
.msg-nota-wa i{ color:var(--wa); font-size:14px; margin-top:2px; flex-shrink:0; }
.msg-nota-wa b{ color:var(--ink); }

/* La acción de la cabecera de un grupo del listado (hoy: «Actualizar
   estados» sobre las plantillas de WhatsApp). Va discreta y a la derecha:
   el grupo lo encabeza su nombre y su cuenta, no un botón. */
.dv-grp{ display:flex; align-items:center; gap:8px; }
.dv-grp-ac{ margin-left:auto; display:inline-flex; align-items:center; gap:5px;
  background:none; border:1px solid var(--ln); border-radius:999px;
  padding:2px 9px; font:inherit; font-size:10.5px; color:var(--mut);
  cursor:pointer; white-space:nowrap;
  transition:border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.dv-grp-ac:hover{ border-color:var(--acc-bd); color:var(--acc); }
.dv-grp-ac i{ font-size:9.5px; }

/* Una fila de la cola que se acaba de derivar. ⚠️ NO se borra ni se
   descuentan las cifras de la cinta: ésas las calculó el servidor y
   tocarlas desde el navegador las dejaría diciendo un número que no salió
   de ninguna consulta. Se marca lo único que se sabe cierto —esta fila ya
   no está pendiente— y «Listo» recarga para que todo vuelva a cuadrar. */
.dv-c.hecha{ opacity:.5; cursor:default; }
.dv-c.hecha:hover{ background:transparent; }
.dv-c.hecha .dv-c-mt{ color:var(--ok); }

/* ---- el detalle de un Grupo de Conexión ----
   ⚠️ Vive SÓLO en el resumen de «Confirmar». Estuvo también bajo la
   tarjeta marcada en las dos listas de elección y sobraba: ahí se está
   comparando grupos y lo que hace falta es lo que la tarjeta ya dice
   —proximidad, cuánta gente recibió—; el equipo, la cobertura y el
   horario son para revisar la decisión tomada, no para tomarla. Repetirlo
   en tres sitios alargaba la lista y decía dos veces lo mismo. */
.dv-gc-sc{ font-size:10.5px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--fnt); margin:12px 0 7px; }
/* ⚠️ EL BLOQUE DEL EQUIPO PONE SU PROPIO MARGEN. `.dv-cf-card` no tiene
   padding —lo ponen sus hijos: la cabecera 14/16 y cada celda de la tira
   10/16—, así que lo que se cuelgue ahí sin padding queda pegado al
   filete. Medido: el subtítulo, la lista y la descripción salían a 1px del
   borde.
   La tira de señas es la excepción y se sale a propósito: sus celdas ya
   traen su padding y sus filetes van de borde a borde, así que se le
   devuelve el ancho completo con el margen negativo. */
.dv-cf-eq{ padding:0 16px 14px; }
.dv-cf-eq:empty{ display:none; }
.dv-cf-eq > .dv-cf-datos{ margin:0 -16px; }
.dv-cf-eq .dv-gc-sc:first-child{ margin-top:14px; }

/* Cada persona del equipo. La inicial va sin tono: acá no se clasifica a
   nadie por grupo objetivo — son quienes sirven en el GC, no visitas. */
.dv-gc-eq{ list-style:none; margin:0; padding:0; display:flex;
  flex-direction:column; gap:1px; }
.dv-gc-eq li{ display:flex; align-items:center; gap:10px; padding:7px 0;
  border-bottom:1px solid var(--ln2); }
.dv-gc-eq li:last-child{ border-bottom:0; }
.dv-gc-eq-bd{ flex:1; min-width:0; }
.dv-gc-eq-nm{ display:block; font-size:13px; color:var(--ink); font-weight:500;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dv-gc-eq-sb{ display:block; font-size:11.5px; color:var(--fnt); }
/* Quien no tiene teléfono: es quien NO va a recibir el aviso de la última
   etapa, y enterarse acá —eligiendo— vale más que enterarse después. */
.dv-gc-eq-no{ flex-shrink:0; color:var(--warn); font-size:12px; }

/* ---- el equipo, cuando además se ELIGE a quién escribirle -----------
   `.dv-gc-eq` nace para MOSTRAR un equipo; acá cada fila lleva además su
   casilla, así que la línea entera es la etiqueta. ⚠️ El <label> tiene que
   ser el flex —no el <li>—, porque es él quien envuelve la casilla, el
   avatar y el nombre: dejándolo en bloque, los tres se apilaban uno bajo
   otro y la fila pasaba de 34 a 96px. */
.rl-eq .rl-eq-li{ padding:0; }
.rl-eq .rl-eq-lb{ display:flex; align-items:center; gap:10px; width:100%;
  padding:7px 4px; border-radius:var(--r-sm); cursor:pointer; }
.rl-eq .rl-eq-lb:hover{ background:var(--wa-sel, var(--sf2)); }
.rl-eq .rl-eq-lb input{ flex-shrink:0; margin:0; cursor:pointer; }
/* Quien no puede recibir se ve, y se ve POR QUÉ (el subtítulo lo dice):
   esconderlo haría parecer que no es del equipo. */
.rl-eq .rl-eq-li.no .rl-eq-lb{ cursor:default; opacity:.55; }
.rl-eq .rl-eq-li.no .rl-eq-lb:hover{ background:none; }
.rl-eq .rl-eq-li.on .rl-eq-lb{ background:var(--wa-sel, var(--acc-sf)); }

/* ---- Recordar a líderes: la cinta y el «cómo funciona», lado a lado ---
   ⚠️ `.ek-kpis` es un grid propio y NO se toca: se le pone un contenedor
   encima que reparte el ancho. Cambiarle las columnas a `.ek-kpis` afecta
   a las 18 pantallas que la usan. */
.rl-top{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,340px);
  gap:var(--gap); align-items:stretch; }
.rl-top > .ek-kpis{ margin:0; }
@media (max-width:1100px){ .rl-top{ grid-template-columns:minmax(0,1fr); } }

.rl-como{ background:var(--sf); border:1px solid var(--ln); border-radius:var(--r);
  box-shadow:var(--sh); padding:11px 14px; align-self:start; }
.rl-como-tt{ display:flex; align-items:center; gap:7px; font-size:12px;
  font-weight:600; color:var(--ink); margin-bottom:7px; }
.rl-como-tt i{ color:var(--acc); }
/* Numeración propia: la del navegador se alinea fuera de la caja y con
   `padding-left` suficiente para meterla, el texto queda angosto. */
.rl-como-ol{ list-style:none; margin:0; padding:0; counter-reset:rlc; }
.rl-como-ol li{ position:relative; padding-left:20px; margin-bottom:4px;
  font-size:11px; line-height:1.4; color:var(--mut); counter-increment:rlc; }
.rl-como-ol li:last-child{ margin-bottom:0; }
.rl-como-ol li::before{ content:counter(rlc); position:absolute; left:0; top:1px;
  width:15px; height:15px; border-radius:50%; background:var(--acc-sf);
  color:var(--acc); font-size:9.5px; font-weight:700;
  display:flex; align-items:center; justify-content:center; }
.rl-como-ol b{ color:var(--ink); font-weight:600; }

/* El plazo, en la fila de filtros. */
.rl-plazo{ display:flex; align-items:center; gap:7px; }
.rl-plazo .ek-sb{ white-space:nowrap; }

/* ---- «Enviar bienvenida»: los dos caminos y la previa en el pie -------
   El pie del chat deja de ser sólo un compositor: mientras la visita sigue
   pendiente ofrece los DOS caminos con su nombre, y elegido uno muestra la
   burbuja tal como la va a recibir la persona. */
.wa-vias{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; width:100%; }
.wa-vias-tt{ font-size:11.5px; color:var(--wa-tx2); margin-right:2px; }
.wa-via{ display:inline-flex; align-items:center; gap:7px; padding:7px 12px;
  border-radius:999px; font-size:12.5px; cursor:pointer;
  border:1px solid var(--wa-ln); background:var(--wa-panel); color:var(--wa-tx); }
.wa-via:hover{ border-color:var(--wa-acc); }
.wa-via .fa-whatsapp{ color:var(--wa); }

/* ⚠️ SÓLO EL MEDIO SCROLLEA. Con el tope de alto en el contenedor entero,
   un saludo largo —el real son siete párrafos— empujaba «Atrás» y «Enviar»
   fuera del pie: la previa se veía completa y no había cómo confirmarla.
   Cabecera y acciones van fijas; lo que crece es la burbuja. */
.wa-previa{ width:100%; display:flex; flex-direction:column; gap:9px;
  max-height:52vh; min-height:0; }
.wa-previa-hd,
.wa-previa-ac{ flex-shrink:0; }
.wa-previa-cp{ flex:1; min-height:0; overflow-y:auto; }
.wa-previa-hd{ display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.wa-previa-tt{ font-size:11.5px; font-weight:600; color:var(--wa-tx2); }
.wa-previa-pl{ flex:1; min-width:140px; height:30px; padding:0 8px; font-size:12px; }
.wa-previa .ek-msgq-wa{ margin-top:0; padding:10px 12px; }
.wa-previa-ac{ display:flex; gap:8px; justify-content:flex-end; }

/* ---- Los tres estados del panel de una persona -----------------------
   `.wa-cuerpo` es hermano de `.wa-hilo` y ocupa el mismo hueco: la ficha y
   el camino elegido se leen, así que scrollean y llevan el aire de una
   página, no el de una tira de burbujas. */
.wa-cuerpo{ flex:1; min-height:0; overflow-y:auto; }
.wa-cp{ padding:16px 5%; display:flex; flex-direction:column; gap:12px; }
.wa-cp .dv-cf-form-tt{ color:var(--wa-tx2); }
.wa-cp .ek-note{ background:var(--wa-panel); border-color:var(--wa-ln);
  border-left-color:var(--warn); }
.wa-cp .ek-note.d{ border-left-color:var(--danger); }
/* La ventana ABIERTA es una oportunidad, no una advertencia: el filete va
   en verde. `.ek-note` nace en ámbar y ese es el único cambio. */
.wa-cp .ek-note.ek-note-ok{ border-left-color:var(--ok); }
.wa-cp .ek-note-tt{ color:var(--wa-tx); }
.wa-cp .ek-note-tx{ color:var(--wa-tx2); }
.wa-cp .ek-msgq-wa{ margin-top:0; }
.wa-cp .wa-previa-hd{ margin-bottom:2px; }

/* Lo que se registró de la persona: pares rótulo/valor en dos columnas.
   ⚠️ `auto-fit` con un mínimo, no dos columnas fijas: en el teléfono el
   panel mide 340px y dos columnas parten «Estado civil» en tres líneas. */
.wa-ficha-dl{ margin:0; display:grid; gap:1px 14px;
  grid-template-columns:repeat(auto-fit, minmax(160px, 1fr)); }
.wa-ficha-dl > div{ padding:5px 0; border-bottom:1px solid var(--wa-ln); }
.wa-ficha-dl dt{ font-size:10.5px; letter-spacing:.03em; text-transform:uppercase;
  color:var(--wa-tx2); }
.wa-ficha-dl dd{ margin:1px 0 0; font-size:13px; color:var(--wa-tx); }
.wa-ficha-obs{ margin-top:11px; font-size:12.5px; color:var(--wa-tx2); }
.wa-ficha-obs b{ display:block; font-size:10.5px; letter-spacing:.03em;
  text-transform:uppercase; color:var(--wa-tx2); margin-bottom:3px; }

.wa-vias-tt2{ font-size:11.5px; font-weight:600; color:var(--wa-tx2); }

/* ---- Los dos caminos para contactar, al final de la etapa 1 ----------
   Son la ACCIÓN de esa etapa, así que se ven como tarjetas pulsables y no
   como botones de barra: cada una dice a dónde lleva y qué cuesta. */
/* ⚠️ DOS COLUMNAS FIJAS, no `auto-fit`. Con `minmax(250px,1fr)` los dos
   caminos se apilaban en cuanto el panel bajaba de ~520px —que es la
   mitad de las veces— y el pedido es que ocupen el ancho, lado a lado.
   Se apilan sólo donde el centro entero ya se apiló (1100px), que es el
   único ancho donde de verdad no caben. */
.rl-vias,
.wa-vias-cp{ margin-top:14px; display:grid; gap:8px;
  grid-template-columns:1fr 1fr; }
@media (max-width:1100px){
  .rl-vias,
  .wa-vias-cp{ grid-template-columns:1fr; }
}
/* El rótulo ocupa la fila entera: es de los dos, no del primero. */
.wa-vias-cp{ margin-top:0; }
.wa-vias-tt2{ grid-column:1/-1; }
/* Lado a lado, la tarjeta crece hacia abajo en vez de a lo ancho: el
   subtítulo de dos líneas es lo que dice qué cuesta cada camino. */
.rl-via{ align-items:flex-start; }
.rl-via-ch{ align-self:center; }
.rl-via{ display:flex; align-items:center; gap:11px; width:100%; text-align:left;
  padding:11px 13px; border-radius:var(--r);
  border:1px solid var(--wa-ln, var(--ln)); background:var(--wa-panel, var(--sf));
  box-shadow:var(--sh); cursor:pointer; }
.rl-via:hover{ border-color:var(--wa-acc, var(--acc)); }
/* ⚠️ EL CAMINO ELEGIDO TIENE QUE VERSE. Esta regla no existía —un
   `str.replace` que no calzó y no avisó— y las dos tarjetas salían
   idénticas: se elegía un camino y nada en pantalla lo decía. El anillo
   solo tampoco basta: dos tarjetas con un borde un punto más oscuro no se
   distinguen de un vistazo, así que se tiñe el fondo y el nombre toma el
   acento. */
.rl-via.on{ border-color:var(--wa-acc, var(--acc));
  background:color-mix(in srgb, var(--wa-acc, var(--acc)) 10%, var(--wa-panel, var(--sf)));
  box-shadow:0 0 0 2px color-mix(in srgb, var(--wa-acc, var(--acc)) 30%, transparent); }
.rl-via.on .rl-via-nm{ color:var(--wa-acc, var(--acc)); }
.rl-via-ic{ flex-shrink:0; width:30px; height:30px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; font-size:13px;
  background:var(--wa-hd, var(--sf2)); color:var(--wa-tx2, var(--mut)); }
/* Verde SÓLO en el de la plataforma: es el que sale por WhatsApp de la
   iglesia. El otro es tu teléfono, y pintarlo igual borraría la
   diferencia que estos dos botones existen para hacer. */
.rl-via-ic.ok{ background:color-mix(in srgb, var(--wa) 16%, transparent); color:var(--wa); }
.rl-via-bd{ flex:1; min-width:0; }
.rl-via-nm{ display:block; font-size:13px; font-weight:600; color:var(--wa-tx, var(--ink)); }
.rl-via-sb{ display:block; margin-top:2px; font-size:11px; line-height:1.4;
  color:var(--wa-tx2, var(--mut)); }
.rl-via-ch{ flex-shrink:0; font-size:11px; color:var(--wa-tx2, var(--mut)); }

/* El navegador entre personas del camino propio. */
.rl-mia-nav{ border:1px solid var(--wa-ln, var(--ln)); background:transparent;
  color:var(--wa-tx2, var(--mut)); border-radius:var(--r-sm);
  width:22px; height:22px; line-height:1; margin-left:4px; cursor:pointer; }
.rl-mia-nav:disabled{ opacity:.4; cursor:default; }

/* «Ver conversación», al final de la fila del equipo. Va discreto: la
   acción de esta etapa es marcar, y esto es una salida lateral. */
.rl-eq .rl-eq-li{ display:flex; align-items:center; gap:6px; }
.rl-eq .rl-eq-lb{ flex:1; min-width:0; }
.rl-eq-ver{ flex-shrink:0; display:inline-flex; align-items:center; gap:5px;
  border:1px solid var(--wa-ln, var(--ln)); background:transparent;
  color:var(--wa-tx2, var(--mut)); border-radius:var(--r-sm);
  padding:5px 9px; font-size:11.5px; cursor:pointer; white-space:nowrap; }
.rl-eq-ver:hover{ color:var(--wa-tx, var(--ink)); border-color:var(--wa-acc, var(--acc)); }

/* Por qué un GC volvió a la cola, en la fila de la lista. El punto de
   color es de ESTADO —ámbar «hay trabajo nuevo», verde «al día»—, no
   decoración: es la misma escala del resto del sistema. */
.rl-nuevas{ display:inline-flex; align-items:center; gap:5px; margin-top:3px;
  font-size:11px; color:var(--warn); }
.rl-nuevas.ok{ color:var(--ok); }
/* ⚠️ `--warn` está calibrado contra superficie CLARA: sobre estas listas
   oscuras daba 2.37:1 en la fila seleccionada. `--warn-nav` es ese mismo
   estado en el chrome oscuro y existe para esto — es la misma pareja que
   `--ok`/`--ok-nav` ya usa el riel. */
.dv-pan .rl-nuevas,
.dv-col .rl-nuevas{ color:var(--warn-nav); }

/* La conversación de la etapa de contacto: el hilo y, debajo, el bloque
   para seguir escribiendo desde el WhatsApp propio. */
.rl-chat + .rl-chat{ margin-top:16px; }
.rl-chat-wa{ margin-top:9px; }

.dv-gc-vacio{ font-size:12.5px; color:var(--mut); }
.dv-gc-desc{ margin-top:10px; font-size:12.5px; color:var(--mut);
  padding-top:10px; border-top:1px solid var(--ln2); }

/* Lo que falta y por qué. Mismo tono que `.ek-msgq-nota`: no es una
   alarma, es un dato pendiente en la ficha del GC. */
.dv-gc-nota{ display:flex; gap:9px; align-items:flex-start; margin-top:9px;
  padding:9px 12px; border-radius:var(--r); background:var(--sf2);
  font-size:12px; color:var(--mut); }
.dv-gc-nota i{ margin-top:2px; color:var(--fnt); flex-shrink:0; }
.dv-gc-nota b{ display:block; color:var(--ink); font-weight:600; margin-bottom:1px; }
.dv-gc-nota span{ min-width:0; overflow-wrap:anywhere; }
