/* Panel de administración — Flash Carwash.
   Archivo propio del panel: no toca public/demo/** (ver
   docs/parallel/OWNERSHIP.md). */

/* ═══════════════════════════════════════════════════════════════════════
   SISTEMA VISUAL — CRM Erika, sobre la estructura de Flash Control ERP

   DESDE EL 2026-10-27 rige la opción A «Vidrio Flash»: los tokens de abajo
   tienen los valores del ERP (violeta #5B4BFF, grafito, Plus Jakarta Sans)
   y el armazón de vidrio vive en vidrio.css, que se carga al final. Donde
   un comentario de esta hoja hable de navy, azul Flash o WhatsApp, manda
   el valor del token, no el comentario.

   Del ERP del negocio, Flash Control, se toma la estructura: tipografía,
   radios, armazón, foco y densidad. La paleta (desde el 2026-10-01) es
   sobria: barra lateral navy, superficies neutras y UN acento, el azul
   Flash, en el botón primario, el foco, los enlaces y lo elegido. Sin
   degradados, brillos ni neones: es una herramienta de trabajo de jornada
   completa, no una portada.

   Los colores se guardan como tripletes RGB, sin `rgb()`, para poder
   aplicarles opacidad: `rgb(var(--color-brand) / 0.1)`. Los nombres de
   los tokens son los de Flash Control; los valores, los del CRM. Cada par
   texto/fondo está medido: 4.5:1 o más en texto, 3:1 en iconos y bordes.

   Tema claro por defecto; el oscuro es la clase `.dark` en <html>, que
   pone lib/tema.js antes de pintar.

   Los nombres viejos (`--primary`, `--ink`, `--fc-*`…) se conservan como
   ALIAS de los tokens nuevos: los usan decenas de reglas y varias vistas,
   y renombrarlos sería un cambio mecánico enorme sin ningún beneficio.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  color-scheme: light;

  /* ── Paleta del CRM, tema claro ───────────────────────────────────────
     Fondo de la app gris claro (#E2E3E9) bajo una ventana de vidrio,
     tarjetas blancas, tintas grafito. Acento violeta #5B4BFF (5.4:1 con
     blanco; texto en #4838E6, 6.5:1). Los semánticos dan 4.5:1 como texto
     sobre blanco; dentro de una insignia, vidrio.css los oscurece. */
  /* Rediseño «Vidrio Flash» (opción A, 2026-10-27): tokens del ERP Flash
     Control. Violeta #5B4BFF (5.4:1 con blanco), tintas grafito y el lima
     sólo en la barra del ítem activo. El armazón de vidrio vive en
     vidrio.css. */
  --color-app: 226 227 233;
  --color-surface: 255 255 255;
  --color-sidebar: 246 246 250;
  --color-ink-primary: 17 18 24;
  --color-ink-secondary: 40 42 52;
  --color-ink-muted: 92 95 108;
  --color-ink-faint: 107 110 124;
  --color-border: 214 216 224;
  --color-border-soft: 230 231 237;
  --color-brand: 91 75 255;
  --color-brand-hover: 72 56 230;
  --color-success: 21 128 61;
  --color-warning: 161 98 7;
  --color-danger: 220 38 38;
  --color-info: 37 99 235;
  --color-lime: 101 163 13;
  --color-overlay: 17 18 24;

  /* Roles fijos, iguales en los dos temas (2026-10-28): ningún color suelto
     en las reglas. Blanco sobre un relleno de color, el blanco y el negro
     para transparencias, y el color de cada canal en la insignia del avatar
     (blanco encima ≥ 3:1: WhatsApp 4.1, Instagram 5.1, voz 10). */
  --sobre-relleno: #ffffff;
  --color-blanco: 255 255 255;
  --color-negro: 0 0 0;
  --canal-whatsapp: #128c7e;
  --canal-instagram: #c13584;
  --canal-voz: #334155;

  /* La barra del ítem activo del menú: el lima del ERP. */
  --sidebar-acento: rgb(var(--color-lime));

  /* Rellenos con texto blanco encima: el primario es violeta #5B4BFF (5.4:1
     con blanco) y al pasar el puntero #4838E6 (6.5:1); el resto, los mismos
     semánticos. En oscuro se fijan los del tema claro para que el blanco
     siga dando 4.5:1. */
  --relleno-marca-a: rgb(var(--color-brand));
  --relleno-marca-b: rgb(var(--color-brand-hover));
  --relleno-exito: rgb(var(--color-success));
  --relleno-peligro: rgb(var(--color-danger));
  --relleno-aviso: rgb(var(--color-warning));

  /* ── Alias con nombre de rol ─────────────────────────────────────────── */
  --surface: rgb(var(--color-surface));
  --surface-sunken: rgb(var(--color-app));
  --ink: rgb(var(--color-ink-primary));
  --ink-secondary: rgb(var(--color-ink-secondary));
  --ink-muted: rgb(var(--color-ink-muted));
  /* Etiquetas de KPI, encabezados de tabla y placeholders. El faint CLARO
     (#94A3B8) no llega a AA sobre blanco: en claro se usa ink-muted
     (7.6:1 sobre blanco, 7.2:1 sobre la app). En oscuro el faint sí
     cumple (5.7:1 sobre tarjeta) y se usa tal cual. */
  --ink-label: rgb(var(--color-ink-muted));
  /* Placeholders: más claros que un valor escrito (#475569 se confundía
     con texto cargado), pero en AA: #64748B da 4.8:1 sobre blanco. */
  --ink-placeholder: rgb(var(--color-ink-faint));
  /* Avisos neutros: grafito casi negro; en oscuro, un tono por encima del
     fondo para que no se pierdan contra él. */
  --toast-fondo: rgb(17 18 24);
  --hairline: rgb(var(--color-border));
  --hairline-soft: rgb(var(--color-border-soft));

  --primary: rgb(var(--color-brand));
  /* Para TEXTO de acento se usa brand-hover, el violeta más hondo (6.5:1
     sobre blanco). */
  --primary-strong: rgb(var(--color-brand-hover));
  --primary-soft: rgb(var(--color-brand) / 0.1);

  /* Alias heredados, con los valores nuevos. `--fc-white` es SUPERFICIE:
     el texto sobre un relleno de color va en #fff explícito. */
  --fc-black: var(--ink);
  --fc-black-soft: var(--ink-secondary);
  --fc-yellow: var(--primary);
  --fc-yellow-dark: rgb(var(--color-brand-hover));
  --fc-white: var(--surface);
  --fc-gray-50: var(--surface-sunken);
  --fc-gray-100: var(--hairline-soft);
  --fc-gray-200: var(--hairline);
  --fc-gray-300: rgb(var(--color-ink-faint) / 0.6);
  --fc-gray-500: var(--ink-muted);
  --fc-gray-700: var(--ink-muted);

  /* Semánticos: texto en el color, fondo en su tinte. El aviso (naranja)
     va al 8% en claro: 5.0:1 sobre su tinte encima de la app. El
     informativo es un cian hondo, distinto del azul del acento. */
  --fc-danger: rgb(var(--color-danger));
  --fc-danger-bg: rgb(var(--color-danger) / 0.1);
  --fc-warning: rgb(var(--color-warning));
  --fc-warning-bg: rgb(var(--color-warning) / 0.08);
  --fc-ok: rgb(var(--color-success));
  --fc-ok-bg: rgb(var(--color-success) / 0.1);
  --fc-info: rgb(var(--color-info));
  --fc-info-bg: rgb(var(--color-info) / 0.1);

  /* Chat (Conversaciones y Derivaciones): la paleta de WhatsApp Business,
     a pedido del dueño. NO sigue la identidad de Flash Control a propósito.
     La hora usa #54656F y no el #667781 de WhatsApp: sobre la burbuja
     verde #667781 da 4.19:1 y #54656F da 5.46:1. */
  /* Opción A: el chat deja la paleta de WhatsApp. Cliente en blanco,
     Erika en lavanda y la persona del panel en violeta con texto blanco
     (5.4:1). La hora sobre lavanda en #5C5F6C da 5.6:1. */
  --chat-fondo: transparent;
  --chat-entrante: #ffffff;
  --chat-saliente: #eceaff;
  --chat-operador: #5b4bff;
  --chat-tinta: #111218;
  --chat-tinta-suave: #5c5f6c;
  --chat-dia: rgb(255 255 255 / 0.72);
  --chat-sombra: 0 1px 2px rgba(17, 18, 24, 0.06);
  /* 4.13.0: la cita de una respuesta, los fijados y los enlaces del chat. */
  --chat-cita: rgba(11, 20, 26, 0.06);
  --chat-acento: #008069;
  --chat-enlace: #027eb5;

  /* ── Escalas del sistema ─────────────────────────────────────────────
     Tipografía: la escala de la guía, 12/14/16/20/24/32. Cuerpo y tablas
     14px, títulos de sección 20px y nada por debajo de 12px (las etiquetas,
     pills y ayudas estaban en 11px: se leían con esfuerzo). Los textos del lienzo
     de flujos (.fc-node-*, .fc-edge-label) siguen en px fijos: viven dentro
     de nodos SVG de medida fija y el lienzo se acerca con el zoom. */
  --text-xs: 12px;
  --text-sm: 14px;
  --text-base: 14px;
  --text-md: 16px;
  --text-lg: 20px;
  --text-xl: 24px;
  --text-2xl: 32px;

  --leading-tight: 1.25;
  --leading-normal: 1.55;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-bold: 600;

  /* Espacio: base 4. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;

  /* Radios de Flash Control: control 8 · control-lg 10 · card 13 ·
     card-lg 17 · modal 22. */
  --radius-sm: 8px;
  --radius: 10px;
  --radius-md: 14px;
  --radius-lg: 14px;
  --radius-card-lg: 18px;
  --radius-modal: 22px;
  --radius-window: 24px;
  --radius-pill: 9999px;

  /* Elevación. El borde de 1px sigue siendo el límite principal; la sombra
     solo da profundidad. */
  --shadow: 0 1px 2px rgb(var(--color-overlay) / 0.05), 0 10px 28px -10px rgb(var(--color-overlay) / 0.16);
  --shadow-sm: 0 1px 2px rgb(var(--color-overlay) / 0.05);
  --shadow-md: 0 12px 32px rgb(var(--color-overlay) / 0.14);
  --shadow-lg: 0 16px 40px rgb(var(--color-overlay) / 0.14);
  --shadow-drawer: -16px 0 46px rgb(var(--color-overlay) / 0.18);
  --fondo-overlay: rgb(var(--color-overlay) / 0.42);

  --focus-ring: 0 0 0 3px rgb(var(--color-brand) / 0.2);

  /* Movimiento: 150ms en controles, 220ms en el cajón y el menú móvil. */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --dur-control: 150ms;
  --dur-drawer: 220ms;

  /* Una sola familia, también para cifras (con dígitos tabulares). */
  --font-display: "Plus Jakarta Sans", system-ui, sans-serif;
  --font-body: "Plus Jakarta Sans", system-ui, sans-serif;
  --font-mono: "Plus Jakarta Sans", system-ui, sans-serif;

  /* Proporciones del armazón. */
  --nav-width: 232px;
  --inspector-width: 380px;

  font-size: 16px;
}

/* ── Tema oscuro ───────────────────────────────────────────────────────
   Grafito, no negro puro: las tarjetas (#18181E) se separan del fondo
   (#07070A) por tono y por su borde. No es el claro invertido: cada valor
   está elegido aparte y medido sobre su propio fondo. */
.dark {
  color-scheme: dark;

  --color-app: 7 7 10;
  --color-surface: 24 24 30;
  --color-sidebar: 16 16 20;
  --color-ink-primary: 245 245 248;
  --color-ink-secondary: 201 202 211;
  --color-ink-muted: 150 152 165;
  --color-ink-faint: 134 137 152;
  --color-border: 48 49 58;
  --color-border-soft: 34 35 42;
  /* Violeta claro para TEXTO sobre el fondo oscuro (#8B80FF, 5.5:1 sobre
     la tarjeta); los rellenos con texto blanco siguen en #5B4BFF. */
  --color-brand: 139 128 255;
  --color-brand-hover: 170 162 255;
  --color-lime: 132 204 22;
  --color-success: 52 211 153;
  --color-warning: 251 146 60;
  --color-danger: 251 113 133;
  --color-info: 34 211 238;
  --color-overlay: 0 0 0;

  /* Los semánticos oscuros son claros para funcionar como TEXTO; como
     relleno con texto blanco se oscurecen: violeta #5B4BFF (5.4:1) a
     #4838E6 (6.5:1), y los semánticos del tema claro. */
  --relleno-marca-a: rgb(91 75 255);
  --relleno-marca-b: rgb(72 56 230);
  --relleno-exito: #15803d;
  --relleno-peligro: #dc2626;
  /* El ámbar oscuro con blanco no llega; se usa el del tema claro. */
  --relleno-aviso: #a16207;

  --ink-label: rgb(var(--color-ink-faint));
  --ink-placeholder: rgb(var(--color-ink-faint));
  --toast-fondo: rgb(40 40 48);
  --fc-warning-bg: rgb(var(--color-warning) / 0.1);

  /* El chat oscuro de WhatsApp. Antes colgaba de `data-theme="dark"`, que
     nada ponía; ahora se enciende con el mismo `.dark` que todo el panel. */
  --chat-fondo: transparent;
  --chat-entrante: #24242c;
  --chat-saliente: #2e2a5c;
  --chat-operador: #5b4bff;
  --chat-tinta: #f5f5f8;
  --chat-tinta-suave: #c9cad3;
  --chat-dia: rgb(24 24 30 / 0.8);
  --chat-sombra: 0 1px 0.5px rgba(0, 0, 0, 0.35);
  --chat-cita: rgba(255, 255, 255, 0.08);
  --chat-acento: #06cf9c;
  --chat-enlace: #53bdeb;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

/* Fondo plano y neutro en los dos temas, como un tablero: sin brillos ni
   grano detrás del contenido. Las casillas, radios y barras de rango del
   navegador toman el azul del acento. */
:root {
  accent-color: rgb(var(--color-brand));
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background-color: rgb(var(--color-app));
  color: var(--ink);
  overflow-x: hidden; /* B9: nunca scroll horizontal del body */
}

a {
  color: var(--primary-strong);
}

button {
  font-family: inherit;
}

/* Todo lo que se pulsa lo dice con el puntero. Sin especificidad
   (`:where`): cualquier regla con clase que pida otro cursor gana. */
:where(button:not(:disabled), summary, label[for], [role="option"]) {
  cursor: pointer;
}

/* Foco: solo con teclado, anillo de marca separado 2px del control. */
:focus-visible {
  outline: 2px solid rgb(var(--color-brand));
  outline-offset: 2px;
}

/* Movimiento de los controles: 150ms, la curva de Flash Control. */
button,
a,
input,
select,
textarea,
summary {
  transition:
    background-color var(--dur-control),
    border-color var(--dur-control),
    color var(--dur-control),
    box-shadow var(--dur-control),
    opacity var(--dur-control),
    transform var(--dur-control);
  transition-timing-function: var(--ease);
}

button:not(:disabled):active {
  transform: scale(0.98);
}

/* Toda cifra en monoespaciada lleva dígitos tabulares. */
.mono,
.stat-value,
.stat-strip dd {
  font-variant-numeric: tabular-nums;
}

/* ---------- Armazón: barra lateral + contenido ---------- */

.app-shell {
  display: flex;
  height: 100%;
  min-height: 0;
}

.contenido {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* ---------- Barra lateral ----------
   (2026-10-28) Sólo la estructura: los colores de la barra navy vieja se
   quitaron; los de la opción A están en vidrio.css.
   Navy opaco en los dos temas, plano. Sus colores son fijos: los rótulos
   en #94A3B8 dan 6.9:1, las entradas en #CBD5E1 10:1, y el ítem activo
   lleva fondo, peso y la barra del acento claro. El foco, en ese mismo
   acento: el azul del panel no se distingue del navy. */

.sidebar {
  position: relative;
  z-index: 20;
  flex: none;
  width: var(--nav-width);
  display: flex;
  flex-direction: column;
  min-height: 0;
}


.sidebar-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 18px 16px 14px;
}

.sidebar-logo {
  flex: none;
  width: auto;
  height: 28px;
}

.brand {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.brand-name {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 600;
  letter-spacing: -0.025em;
  white-space: nowrap;
}

.brand-tagline {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.025em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sidebar-cerrar {
  display: none;
  margin-left: auto;
  width: 36px;
  height: 36px;
  place-items: center;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  cursor: pointer;
}


.nav {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Barra de desplazamiento fina e invisible hasta pasar el puntero. */
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
}

.nav::-webkit-scrollbar {
  width: 6px;
}

.nav::-webkit-scrollbar-thumb {
  border-radius: 3px;
  background: transparent;
}

/* Cuenta de derivaciones abiertas, a la derecha de su etiqueta. */
.nav-cuenta {
  margin-left: auto;
  min-width: 20px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--relleno-peligro);
  color: var(--sobre-relleno);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 20px;
  text-align: center;
}

.nav-cuenta[hidden] {
  display: none;
}

/* Novedades sin mirar (lib/avisos.js): en el color de marca, para no
   confundirse con la cuenta roja de abiertas. Se borra al entrar. */
.nav-nuevas {
  margin-left: auto;
  min-width: 20px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--relleno-marca-a);
  color: var(--sobre-relleno);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 20px;
  text-align: center;
}

.nav-cuenta:not([hidden]) + .nav-nuevas {
  margin-left: 4px;
}

.nav-nuevas[hidden] {
  display: none;
}

.nav-group {
  margin: 0;
  padding: 12px 10px 6px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.025em;
}

.nav-btn {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  padding: 8px 12px 8px 14px;
  border: none;
  border-radius: var(--radius);
  background: transparent;
  text-align: left;
  cursor: pointer;
  font-size: var(--text-base);
  font-weight: 400;
  line-height: 20px;
}


/* Activo: fondo, peso Y barra de acento a la izquierda. Nunca solo color. */
.nav-btn.active {
  font-weight: 500;
}

.nav-btn.active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  bottom: 8px;
  width: 3px;
  border-radius: 3px;
  background: var(--sidebar-acento);
}

.nav-icon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  color: currentColor;
  opacity: 0.85;
}

.nav-btn.active .nav-icon {
  opacity: 1;
}

.sidebar-pie {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 12px 16px 16px;
}

.session-chip {
  max-width: 100%;
  font-size: var(--text-sm);
  font-weight: 500;
  overflow-wrap: anywhere;
}

.sidebar-salir {
  min-height: 36px;
  margin-left: -8px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  font-size: var(--text-base);
  cursor: pointer;
}


.sidebar-fondo {
  display: none;
}

/* ---------- Barra superior ---------- */

.topbar {
  flex: none;
  min-height: 60px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
  position: relative;
  z-index: 10;
}

.topbar-titulo {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--ink-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Botón de icono de la barra superior: 36×36 (el alto de campos y botones),
   radio 10, con borde. */
.icon-btn {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink-muted);
  cursor: pointer;
}

.icon-btn:hover {
  background: var(--surface-sunken);
  border-color: rgb(var(--color-ink-faint));
  color: var(--ink);
}

.menu-btn {
  display: none;
}

/* Luna en claro, sol en oscuro. */
.icono-sol,
.dark .icono-luna {
  display: none;
}

.dark .icono-sol {
  display: block;
}

/* ---------- Píldora de modo (barra superior) ----------
   Dice si las respuestas salen de verdad por WhatsApp. Al pulsarla se
   abre el detalle debajo, alineado a la derecha. El punto es naranja con
   la entrega real encendida; gris si no sale nada. */

.modo {
  position: relative;
}

.modo[hidden] {
  display: none;
}

.modo-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 12px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-secondary);
  font-size: var(--text-sm);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}

.modo-pill::-webkit-details-marker {
  display: none;
}

.modo-pill:hover {
  border-color: rgb(var(--color-ink-faint));
}

.modo-punto {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgb(var(--color-ink-faint));
}

.modo[data-tono="real"] .modo-punto {
  background: rgb(var(--color-warning));
}

/* Abierto al público: es el estado buscado, va en verde (dueño, 2026-10-02). */
.modo[data-tono="abierto"] .modo-punto {
  background: var(--fc-ok);
}

.modo-detalle {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 30;
  width: min(340px, calc(100vw - 32px));
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  color: var(--ink-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* En teléfono sólo el punto: el texto sigue en el nombre accesible. */
@media (max-width: 520px) {
  .modo-pill #modo-texto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
}

/* ---------- Contenido ---------- */

.main {
  flex: 1;
  min-width: 0;
  min-height: 0;
  padding: 16px;
  overflow-y: auto;
}

@media (min-width: 640px) {
  .main {
    padding: 24px;
  }
  .topbar {
    padding: 0 24px;
  }
}

/* Sin tope de ancho: la vista crece con el monitor (dueño, 2026-10-30). */
.view {
  display: none;
}
.view.active {
  display: block;
}

h1 {
  margin: 0 0 4px;
}
h2 {
  margin: 0 0 10px;
}

/* ---------- Tarjetas / paneles ---------- */

.card {
  background: var(--fc-white);
  border: 1px solid var(--fc-gray-200);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 16px;
  margin-bottom: 16px;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}

/* Tarjeta de KPI de Flash Control: etiqueta mono 9.5px en mayúsculas y
   gris, valor mono 600 de 18px. */
.stat {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  padding: 14px;
}
.stat-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--ink-label);
  text-transform: uppercase;
  letter-spacing: 0.025em;
}
.stat-value {
  margin-top: 6px;
  font-family: var(--font-mono);
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--ink);
}

/* Badges y botones: sección COMPONENTES, más abajo. */

.toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.toolbar-spacer {
  flex: 1;
}

/* ---------- Formularios ---------- */

/* `.form-row` (Seguimientos) es el mismo par etiqueta/campo/ayuda. Un campo
   suelto no se estira más allá de una línea cómoda de leer: a 1400px de
   ancho un correo o un nombre se perdía en la caja. */
.field-group,
.form-row {
  max-width: 48rem;
  margin-bottom: var(--space-3);
}
.field-label,
.form-row > label {
  display: block;
  margin-bottom: var(--space-1);
}
.field-hint {
  margin-top: var(--space-1);
}
.input,
.select,
.textarea {
  width: 100%;
}
.textarea {
  resize: vertical;
}
.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--text-sm);
}

/* ---------- Estados (vacío / error / cargando / sin permisos / dependencia caída) ---------- */

/* El vacío es una frase centrada en gris, no una tabla vacía. Error y
   falta de permiso van como los mensajes en flujo de Flash Control: tinte
   del estado, borde al 30% y el texto en su color. */
.state-box {
  padding: 24px 16px;
  text-align: center;
  border: 1px dashed var(--hairline);
  border-radius: var(--radius-lg);
  color: var(--ink-muted);
  background: var(--surface);
  font-size: var(--text-sm);
}
.state-box.state-error {
  border: 1px solid rgb(var(--color-danger) / 0.3);
  color: var(--fc-danger);
  background: rgb(var(--color-danger) / 0.05);
}
.state-box.state-noperm {
  border: 1px solid rgb(var(--color-warning) / 0.3);
  color: var(--fc-warning);
  background: var(--fc-warning-bg);
}
.state-box strong {
  display: block;
  margin-bottom: 6px;
  font-size: var(--text-md);
  font-weight: 600;
}
/* La acción del vacío («Crear el primero», «Reintentar») va centrada bajo el
   texto, no pegada al margen izquierdo de una caja centrada. */
.state-box > .toolbar {
  justify-content: center;
  margin: var(--space-3) 0 0;
}
.spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border: 2px solid var(--fc-gray-300);
  border-top-color: var(--fc-black);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  vertical-align: -3px;
  margin-right: 6px;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.unsaved-banner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  background: var(--fc-warning-bg);
  color: var(--fc-warning);
  border: 1px solid rgb(var(--color-warning) / 0.3);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  margin-bottom: var(--space-3);
}
/* Conflicto y error del editor, y el aviso informativo: el mismo bloque en
   el tono de su estado (antes, con estilos en línea que una CSP estricta
   descarta). */
.unsaved-banner.banner-peligro {
  background: var(--fc-danger-bg);
  color: var(--fc-danger);
  border-color: rgb(var(--color-danger) / 0.3);
}
.unsaved-banner.banner-info {
  background: var(--fc-info-bg);
  color: var(--fc-info);
  border-color: rgb(var(--color-info) / 0.3);
}

/* ---------- Tabla de flujos ---------- */

/* Envoltorio con scroll PROPIO para tablas anchas.
   El body tiene overflow-x: hidden (B9: nunca scroll horizontal del body),
   asi que una tabla mas ancha que su contenedor no producia una barra: se
   RECORTABA en silencio y las ultimas columnas simplemente no se veian. En
   una pantalla de proyector (1024x768) eso le esconde datos a quien mira.
   La barra vive en el contenedor de la tabla, no en la pagina. */
.table-wrap {
  overflow-x: auto;
  width: 100%;
}

/* El resto de la tabla vive en «Tablas», más abajo: aquí había una
   primera versión que esa sección pisaba entera. */
.row-clickable {
  cursor: pointer;
}

/* ---------- Editor de flujos ---------- */

/* Lienzo dominante e inspector acotado: la proporción del constructor de
   referencia. El inspector crece con la pantalla hasta un tope, para que en
   un monitor grande no se convierta en una columna vacía. */
.editor-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(320px, 26vw, var(--inspector-width));
  gap: var(--space-3);
  height: calc(100vh - 230px);
  min-height: 480px;
}

.editor-canvas-wrap {
  position: relative;
  background: var(--fc-white);
  border: 1px solid var(--fc-gray-200);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.editor-palette {
  position: absolute;
  top: 10px;
  left: 10px;
  background: var(--fc-white);
  border: 1px solid var(--fc-gray-200);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 5;
}
.palette-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  padding: 6px 8px;
  font-size: var(--text-sm);
  cursor: grab;
  text-align: left;
}
.palette-btn:hover {
  background: var(--fc-gray-100);
  border-color: var(--fc-gray-300);
}
.palette-swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex-shrink: 0;
}

.editor-zoom-controls {
  position: absolute;
  bottom: 10px;
  left: 10px;
  display: flex;
  gap: 4px;
  background: var(--fc-white);
  border: 1px solid var(--fc-gray-200);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 4px;
  z-index: 5;
}

.editor-issues-toggle {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 5;
}

svg.flow-canvas {
  width: 100%;
  height: 100%;
  display: block;
  cursor: default;
  touch-action: none;
}
svg.flow-canvas.panning {
  cursor: grabbing;
}

.fc-node-rect {
  fill: var(--fc-white);
  stroke: var(--fc-gray-300);
  stroke-width: 1.5;
  rx: 8;
}
.fc-node.selected .fc-node-rect {
  stroke: var(--fc-info);
  stroke-width: 2.5;
}
.fc-node.invalid .fc-node-rect {
  stroke: var(--fc-danger);
  stroke-width: 2.5;
  stroke-dasharray: 4 2;
}
.fc-node-kind-pill {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.fc-node-label {
  font-size: 12px;
  fill: var(--fc-black);
}
.fc-node-sub {
  font-size: 11px;
  fill: var(--fc-gray-500);
}
.fc-edge-path {
  fill: none;
  stroke: var(--fc-gray-500);
  stroke-width: 1.75;
}
.fc-edge-path.default-edge {
  stroke-dasharray: none;
}
.fc-edge-path.conditional-edge {
  stroke: var(--fc-info);
}
.fc-edge-path.dangling {
  stroke: var(--fc-danger);
  stroke-dasharray: 3 3;
}
.fc-edge-label {
  font-size: 11px;
  fill: var(--fc-gray-700);
}
.fc-edge-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 14;
  cursor: pointer;
}
.fc-pending-edge {
  fill: none;
  stroke: var(--fc-yellow-dark);
  stroke-width: 2;
  stroke-dasharray: 4 3;
}
.fc-port {
  fill: var(--fc-gray-300);
  stroke: var(--fc-white);
  stroke-width: 1;
  cursor: crosshair;
}
.fc-port:hover,
.fc-port.active {
  fill: var(--fc-yellow-dark);
}

.editor-side {
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  min-height: 0;
}

.issues-panel {
  max-height: 220px;
  overflow-y: auto;
}
.issue-item {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  padding: 6px 0;
  border-bottom: 1px solid var(--fc-gray-100);
  font-size: var(--text-sm);
}
.issue-item:last-child {
  border-bottom: none;
}
.issue-code {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--fc-danger);
  background: var(--fc-danger-bg);
  padding: 1px 5px;
  border-radius: 4px;
  flex-shrink: 0;
}
.issue-link {
  background: none;
  border: none;
  color: var(--fc-info);
  text-decoration: underline;
  cursor: pointer;
  font-size: var(--text-sm);
  padding: 0;
}

/* ---------- Inspector de nodo ---------- */

.inspector-empty {
  color: var(--fc-gray-500);
  font-size: var(--text-sm);
  text-align: center;
  padding: 20px 10px;
}
.protection-note {
  background: var(--fc-gray-50);
  border-left: 3px solid var(--fc-black);
  padding: 8px 10px;
  font-size: var(--text-sm);
  color: var(--fc-gray-700);
  border-radius: 0 6px 6px 0;
  margin-top: 4px;
}
.tool-checklist {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.chip-row {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.chip {
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
  padding: 2px 8px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

/* ---------- Simulador ---------- */

.simulator-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 1100px) {
  .simulator-grid {
    grid-template-columns: 1fr;
  }
}
.trace-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 420px;
  overflow-y: auto;
}
.trace-item {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  font-size: var(--text-sm);
  padding: 6px 8px;
  border-radius: 6px;
  background: var(--fc-gray-50);
}
.trace-time {
  color: var(--fc-gray-500);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  flex-shrink: 0;
  width: 66px;
}
.trace-dot {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  margin-top: 0.45em;
  border-radius: var(--radius-pill);
  background: rgb(var(--color-ink-faint));
}
.trace-dot[data-tono="exito"] { background: var(--fc-ok); }
.trace-dot[data-tono="aviso"] { background: var(--fc-warning); }
.trace-dot[data-tono="peligro"] { background: var(--fc-danger); }
.run-meta-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 8px;
  margin-bottom: 12px;
}

/* ---------- WhatsApp / sucursales ---------- */

.branch-strip {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.branch-pill {
  border: 1px solid var(--fc-gray-200);
  border-radius: var(--radius);
  padding: 10px 14px;
  min-width: 180px;
}
.branch-pill.current {
  border-color: var(--primary);
  background: var(--primary-soft);
}

/* ---------- Pantalla de ingreso ----------
   Pantalla completa aparte, como la de Flash Control: el navy de la barra
   lateral, plano, y una tarjeta centrada de 380px, radio de modal, 32px de
   aire y el logo de 48px arriba. El navy es fijo en los dos temas; la
   tarjeta sigue el tema. */

.app-shell[hidden],
.login-pantalla[hidden] {
  display: none;
}

.login-pantalla {
  min-height: 100%;
  display: grid;
  place-items: center;
  padding: 24px 16px;
  background-color: rgb(var(--color-sidebar));
}

.login-contenedor {
  width: 100%;
  max-width: 380px;
}

.login-tarjeta {
  padding: 32px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-modal);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  color: var(--ink);
}

.dark .login-tarjeta {
  border-color: rgb(var(--color-blanco) / 0.08);
}

.login-logo {
  display: block;
  width: auto;
  height: 48px;
  margin: 0 0 16px;
}

.login-tarjeta h1 {
  margin: 0;
  color: var(--ink);
}

.login-marca {
  margin: 2px 0 24px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.025em;
  color: var(--ink-muted);
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.login-form .field-group {
  margin: 0;
}

.login-form .input,
.login-form .btn {
  height: 40px;
}

.login-form .btn {
  width: 100%;
}

/* El error va en el flujo, sobre el botón, en el tinte de peligro. */
.login-error {
  margin: 0;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  background: var(--fc-danger-bg);
  color: var(--fc-danger);
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: var(--leading-normal);
}

.login-error:empty {
  display: none;
}

/* «Tu sesión expiró», «Contraseña actualizada»: un aviso, no un error. */
.login-error[data-tono="aviso"] {
  background: var(--fc-info-bg);
  color: var(--fc-info);
}

/* Mensaje de error del login: hereda el tamano de .field-hint pero en el
   rojo de la paleta, que ya cumple contraste sobre fondo claro. */
.field-hint.state-error-text {
  color: var(--fc-danger);
  font-weight: 600;
}

/* ---------- Utilidades ---------- */

.mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
}
.text-muted {
  color: var(--fc-gray-500);
}
/* El título de cada vista ya lo dice la barra superior: el <h1> queda para
   el lector de pantalla (y para el `aria-labelledby` de la sección), sin
   repetirse en pantalla. El editor de flujo es la excepción: su <h1> es el
   nombre del flujo, que la barra superior no dice. */
.visually-hidden,
.view:not(#view-flow-editor) h1 {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- Menú lateral en teléfono ----------
   Por debajo de 768px la barra lateral sale de la pantalla y entra desde
   el borde con el botón de menú, en 220ms, sobre el fondo de overlay.
   Cerrada queda `visibility: hidden`: fuera de vista y fuera del Tab. */
@media (max-width: 767.98px) {
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 950;
    width: min(var(--nav-width), 85vw);
    transform: translateX(-100%);
    visibility: hidden;
    transition:
      transform var(--dur-drawer) var(--ease),
      visibility 0s linear var(--dur-drawer);
  }
  .menu-abierto .sidebar {
    transform: none;
    visibility: visible;
    transition: transform var(--dur-drawer) var(--ease);
  }
  .menu-abierto .sidebar-fondo:not([hidden]) {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 940;
    background: var(--fondo-overlay);
  }
  .menu-btn,
  .sidebar-cerrar {
    display: inline-grid;
  }
}

@media (max-width: 900px) {
  /* El inspector deja de competir por el ancho y pasa DEBAJO del lienzo,
     con su propio desplazamiento. En una columna de 375px, dos paneles lado
     a lado dejan los dos inservibles. */
  .editor-shell {
    grid-template-columns: minmax(0, 1fr);
    height: auto;
    gap: var(--space-4);
  }
  .editor-canvas-wrap {
    height: 60vh;
    min-height: 360px;
  }
  .editor-side {
    max-height: none;
    overflow: visible;
  }
}

@media (max-width: 620px) {
  .editor-canvas-wrap {
    height: 52vh;
    min-height: 300px;
  }
  /* Toda tabla ancha se desplaza dentro de su contenedor: el body nunca. */
  .table-wrap {
    max-width: 100%;
  }
  .row-actions {
    flex-wrap: wrap;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   SISTEMA DE OVERLAYS  (lib/overlay.js)

   Reemplaza a window.alert/confirm/prompt. Densidad y proporciones tomadas
   de la referencia de constructores de agentes: panel angosto, mucho aire
   interior, titulo grande, descripcion en gris, acciones alineadas a la
   derecha con la destructiva separada del boton de escape.
   ═══════════════════════════════════════════════════════════════════════ */

body.fc-overlay-abierto {
  overflow: hidden;
}

.fc-overlay-layer {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: 24px;
}

.fc-overlay-backdrop {
  position: absolute;
  inset: 0;
  background: var(--fondo-overlay);
}

.fc-overlay-panel {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-modal);
  box-shadow: var(--shadow-lg);
  padding: 24px;
  width: 100%;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  animation: fc-overlay-in 140ms ease-out;
}

.fc-overlay-sm { max-width: 420px; }
.fc-overlay-md { max-width: 560px; }
.fc-overlay-lg { max-width: 760px; }

@keyframes fc-overlay-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .fc-overlay-panel { animation: none; }
}

.fc-overlay-title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--fc-black);
  line-height: 1.25;
}

.fc-overlay-desc {
  margin: 0;
  color: var(--fc-gray-500);
  font-size: var(--text-md);
  line-height: 1.5;
}

.fc-overlay-list {
  margin: 0;
  padding-left: 18px;
  color: var(--fc-gray-700);
  font-size: var(--text-base);
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.fc-overlay-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.fc-overlay-error {
  margin: 0;
  background: var(--fc-danger-bg);
  border: 1px solid var(--fc-danger);
  border-radius: var(--radius);
  color: var(--fc-danger);
  padding: 9px 12px;
  font-size: var(--text-base);
}

.fc-overlay-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 2px;
}

/* La accion destructiva se separa del boton de escape: nunca queda pegada
   al que se pulsa por costumbre. */
.fc-overlay-actions .btn-danger {
  margin-left: 6px;
}

.fc-overlay-panel.is-pending {
  cursor: progress;
}

/* Variante cajon lateral, para el inspector en pantallas angostas. */
.fc-overlay-drawer {
  max-width: 420px;
  margin-left: auto;
  margin-right: 0;
  align-self: stretch;
  max-height: none;
  border-radius: 14px 0 0 14px;
}

/* ── Avisos no bloqueantes ─────────────────────────────────────────── */

.fc-toasts {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 1100;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: min(380px, calc(100vw - 40px));
}

.fc-toast {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: var(--fc-black);
  color: var(--fc-white);
  border-radius: 10px;
  padding: 11px 12px 11px 14px;
  box-shadow: var(--shadow);
  font-size: var(--text-base);
  line-height: 1.45;
  animation: fc-overlay-in 140ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .fc-toast { animation: none; }
}

.fc-toast-ok { background: var(--fc-ok); }
.fc-toast-error { background: var(--fc-danger); }
.fc-toast-warn { background: var(--fc-warning); }

.fc-toast-text { flex: 1; }

.fc-toast-close {
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  font-size: var(--text-sm);
  line-height: 1;
  padding: 2px 4px;
  border-radius: 4px;
  opacity: 0.8;
}

.fc-toast-close:hover { opacity: 1; }

@media (max-width: 620px) {
  .fc-overlay-layer { padding: 12px; align-items: flex-end; }
  .fc-overlay-panel { max-height: calc(100vh - 24px); padding: 20px 18px; }
  .fc-overlay-actions { flex-direction: column-reverse; }
  .fc-overlay-actions .btn { width: 100%; }
  .fc-overlay-actions .btn-danger { margin-left: 0; }
  .fc-toasts { right: 12px; left: 12px; bottom: 12px; max-width: none; }
}

/* Aviso de recuperación (borrador antiguo sin nodo de inicio). Se distingue
   del aviso de "cambios sin guardar" porque ofrece una ACCIÓN, no informa. */
.recovery-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* Acción de borrado del nodo SELECCIONADO. Solo aparece en el seleccionado:
   ponerla en todos llenaría el lienzo de controles destructivos. */
.fc-node-delete {
  cursor: pointer;
}

.fc-node-delete circle {
  fill: var(--fc-white);
  stroke: var(--fc-danger);
  stroke-width: 1.2;
}

.fc-node-delete-cruz {
  fill: none;
  stroke: var(--fc-danger);
  stroke-width: 1.6;
  stroke-linecap: round;
  pointer-events: none;
}

.fc-node-delete:hover circle {
  fill: var(--fc-danger);
}

.fc-node-delete:hover .fc-node-delete-cruz {
  stroke: var(--sobre-relleno);
}

.fc-arrow-head {
  fill: rgb(var(--color-ink-muted));
}

.fc-node-delete:focus-visible circle {
  outline: none;
  stroke-width: 2.5;
}

/* ── Ciclo de vida de flujos en la lista ───────────────────────────── */

.toolbar-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-base);
  color: var(--fc-gray-700);
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--radius);
}

.toolbar-check:hover {
  background: var(--fc-gray-50);
}

/* Un flujo archivado se atenúa, PERO su estado también se dice con una
   palabra en la columna Estado: el color nunca es la única señal. */
.row-archived td {
  opacity: 0.72;
}

.row-actions {
  display: flex;
  gap: 6px;
  white-space: nowrap;
}

/* El nombre del flujo es un botón real, no una fila entera clicable: así
   las acciones de la fila no disparan la navegación por accidente, y el
   nombre es alcanzable con Tab. */
.link-btn {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--fc-info);
  text-align: left;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.link-btn:hover {
  color: var(--fc-black);
}


/* ═══════════════════════════════════════════════════════════════════════
   PREFERENCIA DE MOVIMIENTO REDUCIDO — regla general

   Las dos reglas de arriba cubrían solo los overlays y los avisos. Esta
   cubre todo lo demás (transiciones de botones, hover, desplazamientos
   suaves) sin tener que acordarse componente por componente. No se anula
   el movimiento a cero absoluto: 0.01ms mantiene los eventos `transitionend`
   que algún componente podría estar esperando.
   ═══════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ═══════════════════════════════════════════════════════════════════════
   COMPONENTES — idioma visual de Flash Control

   1. El borde de 1px es el límite principal; la sombra solo da
      profundidad, mínima en tarjetas y grande sólo en lo que flota
      (diálogos, menús, avisos). En oscuro separan el tono y el borde.
   2. Títulos y marca en Familjen Grotesk, texto en DM Sans, cifras y
      etiquetas en JetBrains Mono con dígitos tabulares.
   3. Etiquetas pequeñas, en mayúsculas, monoespaciadas y en gris sobre
      valores grandes: la firma de las tarjetas de KPI.
   4. Un solo acento, el azul Flash, en botón primario, foco, enlaces y
      lo elegido; sobre el navy de la barra lateral, su versión clara.
   ═══════════════════════════════════════════════════════════════════════ */

h1, h2, h3, h4,
.fc-overlay-title {
  color: var(--ink-secondary);
}

/* Título de página: display 600, apretado. */
h1,
.fc-overlay-title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: var(--leading-tight);
}

/* Título de tarjeta o sección: 14px sans 600. */
h2 {
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 600;
  letter-spacing: normal;
}

h3,
h4 {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
}

/* La frase que explica una vista: gris, y a un largo de línea que se lee
   de un tirón (antes `.view-intro` no tenía estilo y corría a 1400px). */
.view-subtitle,
.view-intro {
  max-width: 72ch;
  margin: 0 0 var(--space-5);
  color: var(--ink-muted);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

/* ── Tarjetas ───────────────────────────────────────────────────────── */

/* Superficies: borde de 1px y una sombra mínima. Una sombra difusa en cada
   tarjeta de un tablero hace que todo flote y nada se distinga; la
   profundidad grande queda para lo que de verdad está encima (diálogos,
   menús, avisos). En oscuro, la separación la da el tono y el borde. */
.card,
.table-wrap,
.stat-strip,
.buzon-cuerpo,
.lead-row,
.editor-canvas-wrap {
  background-color: var(--surface);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-sm);
}

.card,
.table-wrap,
.stat-strip,
.buzon-cuerpo,
.editor-canvas-wrap {
  border-radius: var(--radius-lg);
}

.lead-row {
  border-radius: var(--radius-md);
}

.dark .card,
.dark .table-wrap,
.dark .stat-strip,
.dark .buzon-cuerpo,
.dark .lead-row,
.dark .editor-canvas-wrap,
.dark .fc-overlay-panel {
  border-color: rgb(var(--color-blanco) / 0.08);
}

.dark .card,
.dark .table-wrap,
.dark .stat-strip,
.dark .buzon-cuerpo,
.dark .lead-row,
.dark .editor-canvas-wrap {
  box-shadow: none;
}

/* Una tabla o lista DENTRO de una tarjeta no repite la sombra. */
.card .table-wrap,
.card .lead-row {
  box-shadow: none;
}

/* Una tarjeta hundida: la ficha de solo lectura del inspector. */
.card.card-hundida {
  background-color: var(--surface-sunken);
  box-shadow: none;
}

/* ── Botones ──────────────────────────────────────────────────────────
   Primario: azul plano, azul hondo al pasar el puntero; sin degradado ni
   sombra de color. `.btn` a secas, `.btn-accent` y `.btn-primary` son el
   primario; el secundario es de superficie con borde; el de peligro, rojo.
   Deshabilitado: 50% y el cursor que lo dice. */

/* 36px de alto, el de los campos, para que alineen en una barra. Sin
   `display` propio: el atributo `hidden` tiene que seguir escondiéndolo. */
.btn {
  padding: 7px 16px;
  line-height: 20px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--relleno-marca-a);
  color: var(--sobre-relleno);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}

.btn:hover:not(:disabled) {
  background: var(--relleno-marca-b);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-secondary {
  background: var(--surface);
  border-color: var(--hairline);
  color: var(--ink);
  font-weight: 500;
}

.btn-secondary:hover:not(:disabled) {
  background: var(--surface-sunken);
  border-color: rgb(var(--color-ink-faint));
}

.btn-danger {
  background: var(--relleno-peligro);
  color: var(--sobre-relleno);
}

.btn-danger:hover:not(:disabled) {
  background: var(--relleno-peligro);
  filter: brightness(0.88);
}

/* Botón compacto de cabecera y de fila. */
.btn-sm {
  padding: 5px 12px;
  line-height: 18px;
  font-size: var(--text-sm);
  font-weight: 500;
  border-radius: var(--radius);
}

.link-btn {
  color: var(--primary-strong);
  font-weight: 500;
}

.link-btn:hover {
  color: var(--ink);
}

/* ── Campos ───────────────────────────────────────────────────────────
   36px de alto, fondo SIEMPRE de superficie, también en oscuro y en
   autocompletado. `color-scheme` (en :root y .dark) hace que el navegador
   dibuje calendarios, listas y barras en el tema correcto. */

.input,
.select {
  min-height: 36px;
}

.input,
.textarea,
.select {
  padding: 0 12px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
}

.input:hover:not(:disabled):not(:focus),
.textarea:hover:not(:disabled):not(:focus),
.select:hover:not(:disabled):not(:focus) {
  border-color: rgb(var(--color-ink-faint));
}

.textarea {
  min-height: 80px;
  padding: 8px 12px;
  line-height: var(--leading-normal);
}

.input[type="number"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.input::placeholder,
.textarea::placeholder,
.buzon-buscar::placeholder {
  color: var(--ink-placeholder);
  opacity: 1;
}

.input:focus,
.textarea:focus,
.select:focus,
.buzon-buscar:focus {
  border-color: var(--primary);
  outline: none;
  box-shadow: var(--focus-ring);
}

.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible,
.buzon-buscar:focus-visible {
  outline: 2px solid rgb(var(--color-brand));
  outline-offset: 2px;
}

/* Autocompletado de Chrome: se fuerza al fondo y la tinta del tema. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
select:-webkit-autofill {
  -webkit-text-fill-color: rgb(var(--color-ink-primary));
  box-shadow: 0 0 0 1000px rgb(var(--color-surface)) inset;
  caret-color: rgb(var(--color-ink-primary));
}

.field-label,
.form-row > label {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink-secondary);
}

.field-hint {
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--ink-muted);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--surface-sunken);
  color: var(--ink-muted);
  cursor: not-allowed;
}

.input[aria-invalid="true"],
.select[aria-invalid="true"],
.textarea[aria-invalid="true"] {
  border-color: var(--fc-danger);
}

/* Casillas y radios a 18px: los 13px del navegador se fallan con el dedo.
   La de `casilla()` (adminControlClient.js) pide 24px. */
input[type="checkbox"],
input[type="radio"] {
  width: 18px;
  height: 18px;
  flex: none;
  vertical-align: -3px;
}

/* ── Pills de estado ──────────────────────────────────────────────────
   Radio 8, mono 12px. Sin mayúsculas: casi todas son frases de estado
   («publicado v3»), no categorías. El estado se dice con la palabra; el
   color acompaña. */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  color: var(--ink-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 18px;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
}

/* Sobre una tarjeta blanca el gris de la app casi no se ve: el neutro lleva
   un filo para que la pill exista. */
.badge-archived,
.badge-neutral,
.badge:not([class*="badge-"]) {
  box-shadow: inset 0 0 0 1px var(--hairline);
}

.badge-real,
.badge-published {
  background: var(--fc-ok-bg);
  color: var(--fc-ok);
}

.badge-fixture {
  background: var(--fc-warning-bg);
  color: var(--fc-warning);
}

.badge-draft {
  background: var(--fc-info-bg);
  color: var(--fc-info);
}

.badge-danger {
  background: var(--fc-danger-bg);
  color: var(--fc-danger);
}

.badge-archived,
.badge-neutral {
  background: var(--surface-sunken);
  color: var(--ink-muted);
}

.badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* ── Tablas ───────────────────────────────────────────────────────────
   13px con dígitos tabulares (las cifras se alinean columna abajo);
   encabezado mono 12px en mayúsculas, gris, sobre el tono hundido; filas
   separadas por el borde suave y resaltadas al pasar el puntero. */

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.table th,
.table td {
  text-align: left;
  padding: 10px 16px;
}

.table th {
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--hairline);
  color: var(--ink-label);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.025em;
  white-space: nowrap;
  vertical-align: bottom;
}

.table td {
  border-bottom: 1px solid var(--hairline-soft);
  color: var(--ink);
}

/* La última fila no dibuja un borde contra el borde de la tarjeta. */
.table tbody tr:last-child td {
  border-bottom: 0;
}

.table tbody tr:hover td,
.row-clickable:hover td {
  background: var(--surface-sunken);
}

.dark .table tbody tr:hover td,
.dark .row-clickable:hover td {
  background: rgb(var(--color-blanco) / 0.03);
}

/* ── Lienzo y nodos ─────────────────────────────────────────────────── */

.fc-node-rect {
  rx: 12;
  ry: 12;
}

/* ── Overlays ─────────────────────────────────────────────────────────
   Modal de radio 22 y fondo de overlay al 42%. El cajón entra desde el
   borde en 220ms. */

.fc-overlay-panel.fc-overlay-drawer {
  border-radius: 0;
  box-shadow: var(--shadow-drawer);
  animation: fc-drawer-in var(--dur-drawer) var(--ease);
}

@keyframes fc-drawer-in {
  from { transform: translateX(100%); }
  to { transform: none; }
}

.fc-overlay-error {
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--fc-danger-bg);
  color: var(--fc-danger);
  font-size: var(--text-sm);
  padding: 8px 12px;
}

/* Avisos: el relleno de la barra lateral con su tinta; los de estado van
   en el relleno semántico que aguanta texto blanco en los dos temas.
   Las vistas piden «ok» o «exito» indistintamente: sin la segunda, cada
   «Conversación cerrada» salía en el gris neutro de un aviso cualquiera. */
.fc-toast {
  background: var(--toast-fondo);
  color: var(--sobre-relleno);
  border: 1px solid rgb(var(--color-blanco) / 0.08);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  font-size: var(--text-base);
}

.fc-toast-ok,
.fc-toast-exito { background: var(--relleno-exito); color: var(--sobre-relleno); }
.fc-toast-error { background: var(--relleno-peligro); color: var(--sobre-relleno); }
.fc-toast-warn { background: var(--relleno-aviso); color: var(--sobre-relleno); }

/* La cruz de cerrar, dibujada: el carácter «✕» cambia de forma y de grosor
   con la fuente de cada sistema. */
.fc-toast-close {
  position: relative;
  flex: none;
  width: 28px;
  height: 28px;
  margin: -4px -4px -4px 0;
  padding: 0;
  border-radius: var(--radius-sm);
}

.fc-toast-close::before,
.fc-toast-close::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 1.5px;
  border-radius: 1px;
  background: currentColor;
  transform: translate(-50%, -50%) rotate(45deg);
}

.fc-toast-close::after {
  transform: translate(-50%, -50%) rotate(-45deg);
}

.fc-toast-close:hover {
  background: rgb(var(--color-blanco) / 0.12);
}

.fc-toasts :focus-visible {
  outline-color: currentColor;
}

/* Sin movimiento: ni la escala al pulsar. */
@media (prefers-reduced-motion: reduce) {
  button:not(:disabled):active {
    transform: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   FRANJA DE CIFRAS

   Cinco tarjetas para cinco números de un dígito era más cromo que dato:
   cada una traía borde, sombra y 16px de relleno para envolver un "0". Una
   `dl` en línea dice lo mismo en un cuarto del alto y deja la pantalla para
   el trabajo.
   ═══════════════════════════════════════════════════════════════════════ */
.stat-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin: 0 0 var(--space-5);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
}
/* Etiqueta y valor de KPI de Flash Control: mono 9.5px en mayúsculas y
   gris arriba, mono 600 de 18–20px abajo. */
.stat-strip dt {
  flex: 1 1 auto;
  min-width: 96px;
  padding: 14px var(--space-4) 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.025em;
  color: var(--ink-label);
  order: 0;
}
.stat-strip dd {
  margin: 0;
  padding: 6px var(--space-4) 14px;
  font-family: var(--font-mono);
  font-size: var(--text-xl);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  order: 0;
}
/* Cada par etiqueta/valor ocupa una columna propia. */
.stat-strip { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; grid-template-rows: auto auto; }
.stat-strip dt + dd { border: 0; }
.stat-strip dt:not(:first-of-type),
.stat-strip dd:not(:first-of-type) { box-shadow: inset 1px 0 0 var(--hairline); }

@media (max-width: 720px) {
  /* En angosto, columna por columna deja tipografía de 4px. Se apila. */
  .stat-strip { grid-auto-flow: row; grid-template-columns: 1fr 1fr; grid-template-rows: none; }
  .stat-strip dt { padding-bottom: 0; }
  .stat-strip dt:not(:first-of-type),
  .stat-strip dd:not(:first-of-type) { box-shadow: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   DETALLE TÉCNICO

   El nombre exacto de la variable, la ruta, el código del error: nada de eso
   se borró, se plegó. Arriba queda la frase en castellano; esto se abre solo
   si alguien lo va a buscar.
   ═══════════════════════════════════════════════════════════════════════ */
.tech-detail {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
}
.tech-detail > summary {
  cursor: pointer;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  padding: var(--space-1) 0;
  list-style: none;
}
.tech-detail > summary::-webkit-details-marker { display: none; }
/* Galón dibujado (no un carácter «›», que cada fuente dibuja distinto):
   apunta a la derecha cerrado y hacia abajo abierto. Lo comparten los
   desplegables del panel. */
.tech-detail > summary::before,
.buzon-detalles > summary::before {
  content: "";
  display: inline-block;
  width: 5px;
  height: 5px;
  margin: 0 8px 1px 2px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-control) var(--ease);
}
.tech-detail[open] > summary::before,
.buzon-detalles[open] > summary::before {
  transform: rotate(45deg);
}
.tech-detail > summary:hover { color: var(--ink); }
.tech-detail > summary:focus-visible {
  border-radius: var(--radius-sm);
}
.tech-list {
  margin: var(--space-2) 0 0;
  padding: var(--space-3);
  list-style: none;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.7;
  color: var(--ink-muted);
  overflow-x: auto;
}

.provider-state {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
}

/* Volver: el control de menor peso de la barra, con su flecha dibujada en
   CSS y no como carácter suelto en el texto (un "◀" lo lee el lector de
   pantalla como "triángulo apuntando a la izquierda"). */
.btn-back::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin: 0 6px 1px 2px;
  border-left: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}

/* Dato que identifica la pantalla — la clave del flujo, un identificador
   corto. No es una explicación: no lleva el peso de un subtítulo. */
.page-meta {
  margin: calc(var(--space-1) * -1) 0 var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* ═══════════════════════════════════════════════════════════════════════
   ETIQUETAS: MONO, PEQUEÑAS Y EN GRIS

   La firma de Flash Control: encabezados de tabla y etiquetas de dato en
   JetBrains Mono de 9.5–10px, en mayúsculas con interletraje 0.025em y en
   gris, sobre un valor más grande. Las pills y la píldora de nodo van en
   mono sin mayúsculas, porque son frases de estado.
   ═══════════════════════════════════════════════════════════════════════ */
.fc-node-kind-pill {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: normal;
}

/* ═══════════════════════════════════════════════════════════════════════
   CONSTRUCTOR DE FLUJOS

   Es la pantalla donde se hace el trabajo, así que es la que más gana
   cuando el resto se calla.

   · El lienzo lleva una malla de puntos muy tenue. Un plano blanco no dice
     dónde está el papel ni cuánto se movió al arrastrar; la malla da esa
     referencia sin competir con los nodos.
   · La paleta pasa de lista flotante sin encabezado a panel con título:
     antes parecía un desplegable que alguien dejó abierto.
   · El nodo pierde la barra de color de 6px a todo el ancho —peso de
     titular para un dato secundario— y gana un punto junto al tipo.
   ═══════════════════════════════════════════════════════════════════════ */
.editor-canvas-wrap {
  background-color: var(--surface);
  background-image: radial-gradient(circle, rgb(var(--color-ink-faint) / 0.35) 1px, transparent 1px);
  background-size: 22px 22px;
}

.editor-palette {
  padding: var(--space-2);
  gap: 1px;
  border-color: var(--hairline);
  border-radius: var(--radius-md);
  /* Sombra de desplegable: flota un plano sobre el lienzo, no cinco. */
  box-shadow: var(--shadow-md);
}
.palette-title {
  margin: 0 0 var(--space-1);
  padding: 0 var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--ink-muted);
}
.palette-btn {
  min-height: 30px;
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--ink);
  cursor: pointer;
}
.palette-btn:hover:not(:disabled) {
  background: var(--surface-sunken);
  border-color: transparent;
}
.palette-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.palette-swatch { width: 7px; height: 7px; border-radius: 999px; }

/* Familia del tipo de nodo (canvas.js, KIND_META): el punto y el rótulo del
   nodo y la muestra de la paleta. Por atributo y no con `style` en línea:
   una CSP sin 'unsafe-inline' descarta esos estilos y el color no salía. */
.fc-node,
.palette-swatch { --familia: var(--color-ink-muted); }
[data-familia="acento"] { --familia: var(--color-brand); }
[data-familia="trabajo"] { --familia: var(--color-success); }
[data-familia="alerta"] { --familia: var(--color-danger); }
.fc-node-dot,
.fc-node-kind-pill { fill: rgb(var(--familia)); }
.palette-swatch { background: rgb(var(--familia)); }

.fc-node-rect {
  /* Un pelo mas oscuro que --hairline: sobre la malla de puntos el borde
     del tono de borde se perdia y el nodo parecia un rectangulo fantasma. */
  stroke: var(--fc-gray-300);
  stroke-width: 1;
  rx: 10;
}
.fc-node.selected .fc-node-rect { stroke: var(--primary-strong); stroke-width: 2; }
.fc-node-warn {
  fill: none;
  stroke: var(--fc-danger);
  stroke-width: 1.4;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* El código del error acompaña al mensaje; no es el mensaje. En rojo sobre
   fondo rojo competía con el texto que sí hay que leer. */
.issue-code {
  color: var(--ink-muted);
  background: var(--surface-sunken);
}
.issues-panel h2 {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ═══════════════════════════════════════════════════════════════════════
   CAJA DE ESTADO: VACÍO ≠ AVISO

   `.state-box` servía para dos cosas distintas con el mismo dibujo:
   el vacío ("todavía no hay nada acá") y el aviso de estado ("el proveedor
   está apagado"). Centrado y con 28px de aire está bien para lo primero
   —es una pantalla sin contenido y el ojo no tiene dónde ir— y mal para lo
   segundo: una frase de estado centrada, en el medio de una tarjeta con
   texto alineado a la izquierda, se lee como un titular.

   `.state-inline` es la variante de aviso: pegada al margen izquierdo como
   el resto del texto, compacta, y con una barra de color que dice de qué
   tono es sin gritar.
   ═══════════════════════════════════════════════════════════════════════ */
/* Mensaje en el flujo, como en Flash Control: bloque de radio 17 con el
   tinte del estado y borde al 30%. El título va en el color del estado; la
   explicación, en gris. */
.state-inline {
  display: block;
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--surface-sunken);
  color: var(--ink);
  font-size: var(--text-sm);
}
.state-inline > strong { display: block; margin-bottom: 2px; }
/* Sin `:not(.badge)` esta regla le ganaba a la insignia y la dejaba gris:
   «Error» y «Sin permiso» perdían su color. */
.state-inline > span:not(.badge) { color: var(--ink-muted); }
.state-inline > .badge { margin-bottom: var(--space-1); }
.state-inline > .btn:not([hidden]) { display: block; margin-top: var(--space-3); }
.state-inline.state-error {
  border-color: rgb(var(--color-danger) / 0.3);
  background: rgb(var(--color-danger) / 0.05);
}
.state-inline.state-error > strong { color: var(--fc-danger); }
.state-inline.state-noperm {
  border-color: rgb(var(--color-warning) / 0.3);
  background: var(--fc-warning-bg);
}
.state-inline.state-noperm > strong { color: var(--fc-warning); }

/* ═══════════════════════════════════════════════════════════════════════
   PARES ETIQUETA/VALOR: SIN CAJA

   `.run-meta-grid > .stat` dibujaba una tarjeta —fondo gris, borde,
   radio, 14px de relleno— alrededor de cada par etiqueta/valor. Seis
   tarjetas en fila para seis datos de una palabra es la forma más cara
   posible de escribir seis datos: el 60% del área es marco.

   La separación entre columnas ya la da la cuadrícula. La jerarquía
   dentro de cada par ya la dan el tamaño y el color. La caja no aportaba
   ninguna de las dos.
   ═══════════════════════════════════════════════════════════════════════ */
.run-meta-grid {
  gap: var(--space-2) var(--space-6);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--space-4);
}
.run-meta-grid > .stat {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
}
.run-meta-grid .stat-label {
  margin-bottom: 1px;
}
.run-meta-grid .stat-value {
  margin-top: 2px;
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--ink);
  line-height: var(--leading-tight);
}

/* ═══════════════════════════════════════════════════════════════════════
   ACCIONES DE UNA FILA: QUE ENTREN

   `.row-actions` era `white-space: nowrap` en una sola línea. Con dos
   botones y una etiqueta larga —«Restaurar» + «Borrar definitivamente»— la
   columna empujaba la tabla más allá de su ancho, y el contenedor con
   scroll dejaba la acción DESTRUCTIVA medio fuera de vista: se veía
   «Borrar d…» y había que desplazar para leer qué hacía.

   Un botón cortado es peor que uno chico. Las acciones se apilan cuando no
   entran, en vez de empujar la tabla.
   ═══════════════════════════════════════════════════════════════════════ */
.row-actions {
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-1) var(--space-2);
}
.row-actions > .btn {
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════════
   PIPELINE DE LEADS

   Lista, no tabla: cada fila tiene un texto libre (el interés que escribió
   el motor) que no entra en una celda, y un grupo de acciones que cambia de
   tamaño según el estado. Una tabla obligaría a recortar lo único que dice
   qué quiere el cliente.
   ═══════════════════════════════════════════════════════════════════════ */

.lead-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}
.lead-count { color: var(--ink-muted); font-size: var(--text-sm); font-variant-numeric: tabular-nums; }

.lead-list {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.lead-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-4);
  padding: var(--space-4);
}
/* Un lead con baja se apaga pero NO se esconde: sigue siendo el registro de
   que esa persona pidió no ser contactada, y esconderlo haría que alguien lo
   volviera a cargar desde cero. */
.lead-row[data-opted-out="true"] { background: var(--surface-sunken); }
/* Reconectar clientes: el ya avisado queda atenuado. */
.lead-row[data-avisado="true"] { background: var(--surface-sunken); }

.lead-ident { display: flex; flex-direction: column; gap: var(--space-1); align-items: flex-start; }
.lead-meta { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.lead-interest { margin: 0; color: var(--ink); font-weight: 500; }
.lead-sub { color: var(--ink-muted); font-size: var(--text-sm); }
.lead-trace { color: var(--ink-muted); font-size: var(--text-xs); }

.lead-actions {
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--space-2);
  flex-wrap: wrap;
  max-width: 280px;
}
.lead-hint { color: var(--ink-muted); font-size: var(--text-sm); }

@media (max-width: 860px) {
  .lead-row { grid-template-columns: 1fr; }
  .lead-actions { justify-content: flex-start; max-width: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   DETALLE DE UN LEAD  (etapa 6)

   La lista responde "cuántos hay y en qué estado". El detalle responde la
   pregunta que hace falta para TRABAJARLO: en qué se apoya, qué falta, cuál
   es el paso siguiente y qué pasó antes. Va debajo de la lista y no en un
   diálogo: mirar un lead no debería tapar el pipeline del que salió.
   ═══════════════════════════════════════════════════════════════════════ */

.lead-next { color: var(--ink); font-size: var(--text-sm); }

.lead-datos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-3) var(--space-4);
  margin: var(--space-4) 0;
}
.lead-dato { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lead-dato-label { color: var(--ink-label); font-family: var(--font-mono); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.025em; }
.lead-dato-valor { color: var(--ink); overflow-wrap: anywhere; }

.lead-evidencia,
.lead-faltantes {
  margin: var(--space-2) 0 var(--space-4);
  padding-left: var(--space-5);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
/* La evidencia es una CITA del cliente: se distingue del resto para que nadie
   la confunda con una nota escrita por el equipo. */
.lead-evidencia li { color: var(--ink-muted); font-style: italic; }

.lead-objecion { margin-bottom: var(--space-4); }

.lead-historial {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.lead-historial li {
  display: grid;
  grid-template-columns: minmax(0, 14rem) minmax(0, 11rem) minmax(0, 1fr);
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-top: 1px solid var(--hairline);
  font-size: var(--text-sm);
}
.lead-hist-tipo { color: var(--ink); font-family: var(--font-mono); overflow-wrap: anywhere; }
.lead-hist-fecha { color: var(--ink-muted); font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.lead-hist-detalle { color: var(--ink-muted); overflow-wrap: anywhere; }
/* Historial escrito como frases («Tomó la derivación»), no como códigos:
   en monoespaciada se leía como un volcado técnico. */
.lead-historial-hechos .lead-hist-tipo { font-family: inherit; }

/* Explicación de por qué alguien está o no en una audiencia. Es un cálculo
   del servidor, no una cita del cliente: sin la cursiva de .lead-evidencia. */
.lista-explicacion { margin: var(--space-2) 0 0; padding-left: 1.1rem; color: var(--ink-muted); font-size: var(--text-sm); }
.lista-explicacion li { overflow-wrap: anywhere; }

@media (max-width: 860px) {
  .lead-historial li { grid-template-columns: 1fr; gap: 2px; }
}

/* ── Historial de derivaciones (etapa 6) ─────────────────────────────────
   Se abre debajo de la fila del cliente, así que hereda el ancho de la
   tabla y no puede empujar las columnas. La lista es vertical a propósito:
   en pantalla angosta las tarjetas se apilan sin esconder el estado, que es
   el dato que el operador necesita ver primero. */
.handoff-historial {
  background: var(--surface-sunken);
  padding: 12px 16px;
}
.handoff-lista {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.handoff-item {
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  background: var(--surface);
}
.handoff-item-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.handoff-datos {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 2px 12px;
  margin: 8px 0 0;
  font-size: 0.92em;
}
.handoff-datos dt {
  color: var(--ink-muted);
}
.handoff-datos dd {
  margin: 0;
}
.handoff-tecnico {
  margin-top: 8px;
  font-size: 0.9em;
}
/* El foco tiene que verse: este historial se puede recorrer solo con Tab. */
.handoff-item :focus-visible,
.handoff-historial :focus-visible {
  outline: 2px solid rgb(var(--color-brand));
  outline-offset: 2px;
}
@media (max-width: 720px) {
  .handoff-datos {
    grid-template-columns: 1fr;
  }
  .handoff-datos dt {
    margin-top: 6px;
  }
}


/* ─────────────────────────────────────────────────────────────────────────
   PLANTILLAS DE MENSAJES — vista previa sintética
   ─────────────────────────────────────────────────────────────────────────
   Un encuadre sobrio, no un teléfono dibujado. Lo que importa es que se lea
   el mensaje tal como saldría, con el ancho real de una conversación: una
   ilustración de dispositivo agrega ruido y no agrega información.

   El texto se inserta con `textContent`, nunca con `innerHTML`: una variable
   con contenido tipo script se lee como texto y no se ejecuta.
   ───────────────────────────────────────────────────────────────────────── */

.preview-telefono {
  /* Ancho de una burbuja real de WhatsApp en un teléfono común. Estrecharlo
     es lo que revela un texto que "en la pantalla del panel entraba". */
  max-width: 22rem;
  margin: 0.5rem 0 1rem;
  padding: 0.875rem;
  background: var(--surface-sunken);
  border: 1px solid var(--hairline);
  border-radius: 12px;
}

.preview-burbuja {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px 12px 12px 4px;
  padding: 0.75rem 0.875rem;
  font-size: var(--text-md);
  line-height: 1.5;
  color: var(--ink);
  /* `pre-wrap` conserva los saltos que el operador escribió y los que agrega
     la instrucción de baja; `break-word` evita que una variable larga
     desborde el contenedor en horizontal. */
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: break-word;
}

/* La ficha de gobernanza en una sola columna cuando no hay ancho: en dos
   columnas estrechas las etiquetas y los valores se separan tanto que dejan
   de leerse como pares. */
@media (max-width: 640px) {
  .preview-telefono {
    max-width: 100%;
  }
}

/* Medido en el navegador a 375 px: la tarjeta no encogía y quedaba de 625 px
   dentro de una columna de 335. El contenido seguía siendo alcanzable —`.main`
   tiene scroll horizontal y el `body` no—, pero obligaba a desplazarse para
   leer la vista previa.

   La causa es el default de CSS Grid: un ítem tiene `min-width: auto`, así que
   se dimensiona por su contenido y no por la columna. `min-width: 0` lo deja
   encoger. Va acotado a esta sección: `.simulator-grid` es compartida y no se
   toca para las demás. */
#view-plantillas .simulator-grid > * {
  min-width: 0;
}

/* La tabla de plantillas tiene diez columnas. Sin un ancho mínimo, en
   pantallas medianas «Propósito» se comprime hasta partir cada palabra en una
   línea. Con el mínimo, las columnas respiran y el desborde lo resuelve el
   scroll de `.table-wrap`, que ya existía. */
#view-plantillas .table-wrap > table {
  min-width: 62rem;
}

/* Las columnas de METADATO no envuelven: son etiquetas cortas y cerradas
   (categoria, consentimiento, idioma, version, estados, fecha). Envolviendolas
   se parte "Aprobada por el negocio" en tres lineas y la fila crece sin que
   nadie gane nada.

   Al no envolver, el ancho sobrante queda para las dos columnas de PROSA
   --nombre y proposito--, que son las unicas donde envolver tiene sentido.
   Medido en el navegador: sin esto, "Verificacion en navegador del panel de
   plantillas" salia partido en cinco lineas de una palabra. */
#view-plantillas .table-wrap > table th:nth-child(n + 3),
#view-plantillas .table-wrap > table td:nth-child(n + 3) {
  white-space: nowrap;
}

/* La columna de proposito se queda con el espacio libre. */
#view-plantillas .table-wrap > table td:nth-child(2) {
  min-width: 18rem;
}

/* La ficha de gobernanza en una sola columna cuando no hay ancho: dos columnas
   estrechas separan tanto etiqueta y valor que dejan de leerse como pares. */
@media (max-width: 720px) {
  #view-plantillas .lead-datos {
    grid-template-columns: 1fr;
  }
}

/* ─────────────────────────────────────────────────────────────────────────
   CHAT — la transcripción como en WhatsApp Business (lib/burbujasDeChat.js)
   ─────────────────────────────────────────────────────────────────────────
   El cliente a la izquierda en blanco; Erika y los mensajes manuales a la
   derecha en verde. Un manual se ve en cursiva: quién lo registró, no lo
   que dijo. El texto entra como nodo de texto, nunca con `innerHTML`.

   Conserva el aspecto de WhatsApp a pedido del dueño; no sigue la identidad
   de Flash Control. Sus colores oscuros viven en `.dark`, arriba. */

.chat-lista {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--chat-fondo);
  border-radius: var(--radius);
  color: var(--chat-tinta);
}

.chat-dia {
  align-self: center;
  margin: var(--space-3) 0 var(--space-1);
}

.chat-dia:first-child {
  margin-top: 0;
}

.chat-dia span {
  display: inline-block;
  padding: 5px 12px;
  border-radius: var(--radius-sm);
  background: var(--chat-dia);
  box-shadow: var(--chat-sombra);
  color: var(--chat-tinta-suave);
  font-size: var(--text-xs);
}

.chat-burbuja {
  position: relative;
  max-width: 75%;
  margin-top: 10px;
  padding: 6px 8px 8px 9px;
  border-radius: 8px;
  box-shadow: var(--chat-sombra);
  line-height: 1.35;
}

/* Del mismo lado que el anterior: pegada y sin colita. */
.chat-seguida {
  margin-top: 0;
}

.chat-entrante {
  align-self: flex-start;
  background: var(--chat-entrante);
}

.chat-saliente {
  align-self: flex-end;
  background: var(--chat-saliente);
}

/* La colita, del color de la burbuja, en la esquina de arriba. */
.chat-burbuja:not(.chat-seguida)::before {
  content: "";
  position: absolute;
  top: 0;
  width: 8px;
  height: 13px;
  background: inherit;
}

.chat-entrante:not(.chat-seguida) {
  border-top-left-radius: 0;
}

.chat-entrante:not(.chat-seguida)::before {
  left: -8px;
  clip-path: polygon(0 0, 100% 0, 100% 100%);
}

.chat-saliente:not(.chat-seguida) {
  border-top-right-radius: 0;
}

.chat-saliente:not(.chat-seguida)::before {
  right: -8px;
  clip-path: polygon(0 0, 100% 0, 0 100%);
}

.chat-texto {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.chat-manual .chat-texto {
  font-style: italic;
  color: var(--chat-tinta-suave);
}

/* El lugar de la hora al final de la última línea, para que el texto no
   pase por debajo de ella. */
.chat-hueco {
  display: inline-block;
  width: 4.5rem;
}

.chat-hora {
  position: absolute;
  right: 8px;
  bottom: 4px;
  font-size: var(--text-xs);
  color: var(--chat-tinta-suave);
  white-space: nowrap;
}

@media (max-width: 620px) {
  .chat-lista {
    padding: var(--space-2) var(--space-3);
  }

  .chat-burbuja {
    max-width: 85%;
  }
}

.chat-contacto {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Respuesta de una persona desde el panel (4.6.0): verde como lo que sale del
   negocio, con su nombre arriba y cómo va el envío abajo. */
.chat-autor {
  display: block;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--chat-tinta-suave);
}

.chat-entrega {
  display: block;
  padding-right: 4.5rem;
  font-size: var(--text-xs);
  color: var(--chat-tinta-suave);
}

.chat-entrega[data-entrega="fallido"] {
  color: var(--fc-danger);
  font-weight: 600;
}

/* Foto, nota de voz, video o archivo del cliente (lib/medios.js, 4.12.0). */
.chat-medio {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  margin-bottom: 2px;
}

.chat-medio-estado {
  margin: 0;
  font-size: var(--text-xs);
  font-style: italic;
  color: var(--chat-tinta-suave);
}

.chat-medio-estado[data-medio-estado="error"] {
  color: var(--fc-danger);
  font-style: normal;
}

/* La miniatura es un botón: se abre en grande con clic, Enter o Espacio. */
.chat-medio-ampliar {
  display: block;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  cursor: zoom-in;
}

.chat-medio-imagen {
  display: block;
  max-width: min(260px, 100%);
  max-height: 260px;
  border-radius: 6px;
  object-fit: cover;
}

.chat-medio-audio {
  width: min(280px, 100%);
}

.chat-medio-video {
  max-width: min(320px, 100%);
  max-height: 320px;
  border-radius: 6px;
}

.chat-medio-grande {
  display: block;
  max-width: 100%;
  max-height: 70vh;
  margin: 0 auto;
  object-fit: contain;
}

/* El cuadro para responder, debajo del chat (lib/respuesta.js). */
.buzon-pie {
  flex: none;
  padding: var(--space-2) var(--space-4) var(--space-3);
  border-top: 1px solid var(--hairline);
  background: var(--surface);
}

.respuesta {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.respuesta p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.respuesta-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.respuesta-fila {
  display: flex;
  align-items: flex-end;
  gap: var(--space-2);
}

.respuesta-texto {
  flex: 1;
  min-width: 0;
  resize: vertical;
}

.respuesta .respuesta-error {
  color: var(--fc-danger);
}

/* El archivo elegido para mandar (4.12.0): miniatura, nombre y tamaño, texto opcional. */
.respuesta-archivo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding: var(--space-2);
  border-radius: 8px;
  background: var(--chat-fondo);
  color: var(--chat-tinta);
}

.respuesta-miniatura {
  display: block;
  width: 56px;
  height: 56px;
  border-radius: 6px;
  object-fit: cover;
}

.respuesta-archivo-nombre {
  margin: 0;
  font-size: var(--text-xs);
  overflow-wrap: anywhere;
}

.respuesta-leyenda {
  flex: 1 1 12rem;
  min-width: 0;
}

.respuesta-archivo-acciones {
  display: flex;
  gap: var(--space-2);
}

/* ── Menú del mensaje (4.13.0) ───────────────────────────────────────────
   El botón aparece al pasar el mouse o con el foco (siempre en pantallas
   táctiles); la cita, los fijados, la selección y la ubicación del cliente. */
.chat-menu {
  position: absolute;
  top: 2px;
  right: 2px;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: inherit;
  color: var(--chat-tinta-suave);
  cursor: pointer;
  opacity: 0;
}

.chat-burbuja:hover .chat-menu,
.chat-menu:focus-visible,
.chat-menu[aria-expanded="true"] {
  opacity: 1;
}

.chat-menu:focus-visible {
  outline: 2px solid var(--chat-acento);
  outline-offset: 1px;
}

@media (hover: none) {
  .chat-menu {
    opacity: 1;
  }
}

.icono-chevron {
  display: block;
  width: 7px;
  height: 7px;
  margin-top: -3px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

.icono-fijado {
  display: inline-block;
  width: 9px;
  height: 12px;
  margin-right: 3px;
  vertical-align: -1px;
  background: currentColor;
  clip-path: polygon(20% 0, 80% 0, 70% 40%, 100% 65%, 55% 65%, 50% 100%, 45% 65%, 0 65%, 30% 40%);
}

.chat-hora .icono-estrella {
  width: 10px;
  height: 10px;
  margin-right: 3px;
}

.chat-cita {
  display: flex;
  flex-direction: column;
  margin: 2px 0 4px;
  padding: 4px 8px;
  border-left: 4px solid var(--chat-acento);
  border-radius: 6px;
  background: var(--chat-cita);
  font-size: var(--text-sm);
}

.chat-cita-quien {
  font-weight: 600;
  color: var(--chat-acento);
}

.chat-cita-texto {
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  color: var(--chat-tinta-suave);
  overflow-wrap: anywhere;
}

.respuesta-cita {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: 8px;
  background: var(--chat-fondo);
  color: var(--chat-tinta);
}

.respuesta-cita .chat-cita {
  flex: 1;
  min-width: 0;
  margin: 0;
}

.chat-fijados {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: var(--space-2);
}

.chat-fijado {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  padding: 4px 8px;
  border: 1px solid var(--hairline);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font-size: var(--text-sm);
  text-align: left;
  cursor: pointer;
}

.chat-fijado-texto {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.chat-resaltado {
  outline: 3px solid var(--chat-acento);
  outline-offset: 2px;
}

/* «Destacados»: sólo los mensajes con estrella. */
.chat-lista[data-solo-destacados] > li:not([data-destacado]) {
  display: none;
}

/* «Seleccionar»: la casilla de cada burbuja, sólo en modo selección. */
.chat-marcar {
  display: none;
}

.chat-lista[data-seleccionando] .chat-marcar {
  display: inline-block;
  width: 20px;
  height: 20px;
  margin: 0 6px 0 0;
  vertical-align: middle;
}

.chat-seleccion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.chat-seleccion-cuenta {
  font-size: var(--text-sm);
  font-weight: 600;
}

.chat-oculto {
  opacity: 0.7;
  outline: 1px dashed var(--chat-tinta-suave);
}

.chat-oculto-aviso {
  display: block;
  font-size: var(--text-xs);
  font-style: italic;
  color: var(--chat-tinta-suave);
}

.chat-ubicacion {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 4px 0;
  padding-right: 4.5rem;
  font-size: var(--text-sm);
}

.chat-ubicacion-enlace {
  font-weight: 600;
  color: var(--chat-enlace);
}

.chat-ubicacion-dato {
  color: var(--chat-tinta-suave);
  overflow-wrap: anywhere;
}

.chat-ubicacion-borrada {
  font-style: italic;
  color: var(--chat-tinta-suave);
}

/* El diálogo «Reenviar mensaje a» y «Nuevo mensaje». */
.reenvio,
.nuevo-mensaje {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.reenvio-control {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
}

.reenvio-lista {
  max-height: 45vh;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.reenvio-fila {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 2px var(--space-2);
  padding: 6px 4px;
  border-bottom: 1px solid var(--hairline-soft);
}

.reenvio-fila-no .reenvio-nombre {
  color: var(--ink-muted);
}

.reenvio-nombre {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.reenvio-dato,
.reenvio-estado,
.reenvio-cuenta {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.reenvio-motivo {
  grid-column: 2;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.reenvio-elegir {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: none;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
}

.reenvio-elegir[aria-pressed="true"] {
  border-color: var(--chat-acento);
  background: var(--chat-cita);
}

.nuevo-destino {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  border: 0;
}

.nuevo-previa {
  margin: 0;
}

.nuevo-previa .chat-burbuja {
  max-width: 100%;
}
/* ─────────────────────────────────────────────────────────────────────────
   BUZÓN — Conversaciones y Derivaciones como WhatsApp Web (lib/buzon.js)
   ─────────────────────────────────────────────────────────────────────────
   La lista a la izquierda y lo elegido a la derecha, cada uno con su propio
   desplazamiento. La vista ocupa el alto disponible: la página no se
   desplaza aparte. Por debajo de 800px se ve una sola columna. */
.view.active.vista-buzon {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

.vista-buzon > h1,
.vista-buzon > p {
  flex: none;
}

.buzon {
  flex: 1;
  min-height: 420px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.buzon-cuerpo {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.buzon-lista {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--hairline);
}

.buzon-herramientas {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border-bottom: 1px solid var(--hairline);
}

.buzon-herramientas-fila {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.buzon-buscar {
  width: 100%;
  min-height: 36px;
  padding: 0 12px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  background: var(--surface);
  font: inherit;
  font-size: var(--text-sm);
  color: var(--ink);
}

.buzon-items {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.buzon-items > .state-box,
.buzon-items > .state-inline {
  margin: var(--space-3);
}

.buzon-opciones {
  list-style: none;
  margin: 0;
  padding: 0;
}

.buzon-fila {
  display: grid;
  gap: 2px;
  padding: 10px var(--space-3) 10px 13px;
  border-bottom: 1px solid var(--hairline-soft);
  border-left: 3px solid transparent;
  cursor: pointer;
}

.buzon-fila:hover {
  background: rgb(var(--color-app) / 0.6);
}

/* Elegida: tinte de marca Y barra de 3px, como el ítem activo del menú. */
.buzon-fila[aria-selected="true"] {
  background: var(--primary-soft);
  border-left-color: var(--primary);
}

.buzon-fila:focus-visible {
  outline: 2px solid rgb(var(--color-brand));
  outline-offset: -2px;
}

.buzon-fila-arriba {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  min-width: 0;
}

.buzon-quien {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-base);
}

.buzon-hora {
  flex: none;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.buzon-fila-dato {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.buzon-previa {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.buzon-insignias {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
}

.buzon-insignias:empty {
  display: none;
}

.buzon-panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.buzon-panel > .state-box,
.buzon-panel > .state-inline {
  margin: var(--space-4);
}

.buzon-cabecera {
  flex: none;
  max-height: 45%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--hairline);
}

.buzon-titulo {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.buzon-cabecera p {
  margin: 0;
}

.buzon-acciones {
  justify-content: flex-start;
  max-width: none;
}

.buzon-historial summary {
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.buzon-chat {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  background: var(--chat-fondo);
}

.buzon-chat .chat-lista {
  min-height: 100%;
  margin: 0;
  border-radius: 0;
}

.buzon-vacio {
  margin: auto;
  padding: var(--space-6);
  text-align: center;
  color: var(--ink-muted);
}

.buzon-volver {
  display: none;
}

/* En vivo (lib/buzon.js): el estado, a la derecha. */
.buzon-cabeza {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.buzon-vivo {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.buzon-vivo[hidden] {
  display: none;
}

.buzon-vivo-punto {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--fc-ok);
}

.buzon-vivo[data-vivo="error"] .buzon-vivo-punto {
  background: var(--fc-warning);
}

/* «Nuevos mensajes ↓»: flota sobre el final del chat. */
.buzon-nuevos {
  align-self: center;
  position: relative;
  z-index: 1;
  min-height: 28px;
  margin: calc(-28px - var(--space-3)) 0 var(--space-3);
  padding: 0 12px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: 500;
  box-shadow: var(--shadow-sm);
  cursor: pointer;
}

.buzon-nuevos[hidden] {
  display: none;
}

/* Una fila que llegó en vivo: entra con el tinte de marca y se apaga. */
.buzon-fila-nueva {
  animation: buzon-fila-nueva 2.4s ease-out;
}

@keyframes buzon-fila-nueva {
  from {
    background: var(--primary-soft);
  }
}

/* ── Bandeja (4.10.0): chips, marcas, no leída y menú de la fila ── */
.buzon-filtros {
  display: flex;
  gap: var(--space-1);
  overflow-x: auto;
  scrollbar-width: thin;
  padding-bottom: 2px;
}

.buzon-filtro {
  flex: none;
  min-height: 32px;
  padding: 0 12px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
}

.buzon-filtro[aria-pressed="true"] {
  background: var(--primary-soft);
  border-color: var(--primary);
  font-weight: 600;
}

.buzon-filtro:focus-visible,
.buzon-menu:focus-visible {
  outline: 2px solid rgb(var(--color-brand));
  outline-offset: 1px;
}

.buzon-etiqueta {
  width: auto;
  min-height: 32px;
  font-size: var(--text-xs);
}

.buzon-etiqueta[hidden] {
  display: none;
}

.buzon-fila-fin {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.buzon-marca {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.buzon-estrella {
  color: var(--primary);
}

.buzon-no-leida {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--primary);
}

.buzon-fila-no-leida .buzon-quien,
.buzon-fila-no-leida .buzon-previa {
  font-weight: 700;
  color: var(--ink);
}

.buzon-menu {
  min-width: 28px;
  min-height: 28px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink-muted);
  font: inherit;
  font-size: var(--text-base);
  line-height: 1;
  cursor: pointer;
}

.buzon-menu:hover {
  background: var(--surface-sunken);
}

.buzon-menu-lista {
  display: grid;
  gap: var(--space-2);
}

@media (max-width: 800px) {
  .buzon-cuerpo {
    grid-template-columns: minmax(0, 1fr);
  }

  .buzon-lista {
    border-right: 0;
  }

  .buzon[data-abierto] .buzon-lista,
  .buzon:not([data-abierto]) .buzon-panel {
    display: none;
  }

  .buzon-volver {
    display: inline-flex;
    align-self: flex-start;
    margin: var(--space-2) var(--space-3) 0;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   BANDEJA A PANTALLA COMPLETA (rediseño 2026-10-01)
   Como WhatsApp Web: la bandeja usa todo el alto y el ancho útiles, la lista
   es de filas con avatar y jerarquía clara, la cabecera del chat es UNA fila
   (avatar, quién, acciones) y los avisos van plegados en «Detalles». El chat
   se queda con la altura. Contrastes: blanco sobre cada tono de avatar
   ≥ 4.5:1; foco visible en buscador, filas y chips.
   ═══════════════════════════════════════════════════════════════════════ */
.main:has(> .view.active.vista-buzon) {
  padding: 12px;
}

.view.active.vista-buzon {
  max-width: none;
}

.buzon {
  min-height: 360px;
  margin-top: 0;
  gap: 6px;
}

.buzon-cuerpo {
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
}

@media (min-width: 801px) {
  .buzon-cuerpo {
    grid-template-columns: clamp(300px, 30%, 420px) minmax(0, 1fr);
  }
}

/* ── Lista ── */
.buzon-herramientas {
  gap: 10px;
  padding: 12px;
}

.buzon-buscar {
  min-height: 40px;
  padding: 0 16px;
  border-color: transparent;
  border-radius: 999px;
  background: var(--surface-sunken);
  transition: background-color 150ms ease, box-shadow 150ms ease;
}

.buzon-buscar:focus {
  outline: none;
  border-color: var(--primary);
  background: var(--surface);
  box-shadow: var(--focus-ring);
}

.buzon-fila {
  grid-template-columns: 44px minmax(0, 1fr);
  align-items: center;
  column-gap: 12px;
  padding: 10px 14px;
  border-left: 0;
  transition: background-color 150ms ease;
}

.buzon-fila-cuerpo {
  display: grid;
  gap: 1px;
  min-width: 0;
}

/* Elegida: tinte y barra interior de 3px (sin mover el contenido). */
.buzon-fila[aria-selected="true"] {
  box-shadow: inset 3px 0 0 var(--primary);
}

.buzon-quien {
  font-weight: 600;
  color: var(--ink);
}

.buzon-hora {
  font-family: var(--font-body);
}

.buzon-fila-no-leida .buzon-hora {
  color: var(--primary-strong);
  font-weight: 600;
}

.buzon-no-leida {
  width: 9px;
  height: 9px;
}

/* ── Avatar: iniciales en un círculo, seis tonos sobrios ── */
.buzon-avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgb(var(--color-border-soft));
  color: var(--ink-secondary);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.02em;
  user-select: none;
}

/* Los seis tonos de avatar se quitaron (opción A): el color es para los estados. */

/* ── Cabecera del chat: una fila ── */
/* Tope de 40%: «Derivaciones» todavía arma su cabecera con los avisos sueltos. */
.buzon-cabecera {
  max-height: 40%;
  gap: 6px;
  padding: 10px 16px;
  background: var(--surface);
}

.buzon-encabezado {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
}

.buzon-encabezado .buzon-avatar {
  width: 40px;
  height: 40px;
  font-size: 14px;
}

.buzon-encabezado-texto {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.buzon-encabezado .lead-sub {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-xs);
}

/* Nombre, número, «Mostrar número» e insignias en UN renglón; el nombre se
   recorta antes que cualquier otra cosa. */
.buzon-encabezado .buzon-titulo {
  flex-wrap: nowrap;
  min-width: 0;
}

.buzon-encabezado .buzon-titulo > * {
  flex: none;
}

.buzon-encabezado .buzon-titulo > :first-child {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* El bloque del contacto (nombre, …4091, «Mostrar número») también en un
   renglón; el nombre es lo que se recorta. */
.buzon-encabezado .chat-contacto {
  flex-wrap: nowrap;
  align-items: center;
  min-width: 0;
}

.buzon-encabezado .chat-contacto > strong {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.buzon-encabezado .chat-contacto > * {
  flex: none;
}

.buzon-encabezado .chat-contacto > strong {
  flex: 0 1 auto;
}

.buzon-encabezado .chat-contacto .btn {
  min-height: 26px;
  padding: 0 10px;
}

/* ── Chat y cuadro de respuesta ── */
.buzon-chat .chat-lista {
  padding: 16px clamp(16px, 6%, 72px) 24px;
}

.buzon-chat .chat-burbuja {
  max-width: min(65%, 680px);
}

.buzon-pie {
  padding: 8px 16px 10px;
  background: var(--surface-sunken);
}

.buzon-pie .respuesta-texto {
  field-sizing: content;
  min-height: 44px;
  max-height: 30vh;
  padding: 10px 14px;
  border-radius: 20px;
  resize: none;
}

/* Sin el control: aviso y botón en UN renglón, no un botón a todo el ancho. */
.buzon-pie .respuesta:has(> .respuesta-aviso) {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
}

.buzon-pie .respuesta:has(> .respuesta-aviso) > .respuesta-aviso {
  flex: 1;
  min-width: 12rem;
}

/* «En vivo» no ocupa un renglón: mientras todo va bien queda sólo para el
   lector de pantalla; si se cae la conexión, flota arriba al centro. */
.buzon {
  position: relative;
}

.buzon-cabeza {
  position: absolute;
  top: 8px;
  left: 50%;
  z-index: 3;
  transform: translateX(-50%);
  pointer-events: none;
}

.buzon-vivo[data-vivo="ok"] {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.buzon-vivo[data-vivo="error"] {
  margin: 0;
  padding: 4px 12px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow-md);
}

.topbar {
  min-height: 52px;
}

/* ── Seleccionar varias ── */
.buzon-buscar-fila {
  display: flex;
  align-items: center;
  gap: 8px;
}

.buzon-buscar-fila .buzon-buscar {
  flex: 1;
  min-width: 0;
}

.btn.buzon-seleccionar[aria-pressed="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--sobre-relleno);
}

.buzon-marcar {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: rgb(var(--color-brand));
  cursor: pointer;
}

.buzon:not([data-marcando]) .buzon-marcar {
  display: none;
}

.buzon[data-marcando] .buzon-fila {
  grid-template-columns: 18px 44px minmax(0, 1fr);
}

.buzon-seleccion {
  flex: none;
  display: grid;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--hairline);
  background: var(--primary-soft);
}

.buzon-seleccion[hidden] {
  display: none;
}

.buzon-seleccion-cuenta {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--primary-strong);
}

.buzon-seleccion-acciones {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Botones-chip: las seis acciones caben en dos renglones. */
.buzon-seleccion-acciones .btn {
  min-height: 28px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: var(--text-xs);
}

/* ── Herramientas compactas sobre la lista ── */
.buzon-filtros {
  scrollbar-width: none;
  mask-image: linear-gradient(90deg, rgb(var(--color-negro)) 88%, transparent);
}

.buzon-filtros::-webkit-scrollbar {
  display: none;
}

.buzon-herramientas-fila {
  flex-wrap: nowrap;
}

.buzon-herramientas-fila [data-cuenta] {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Segunda línea de la fila: marcas y datos, en un renglón. */
.buzon-fila-dato {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.buzon-fila-dato .buzon-marca {
  margin-right: 6px;
  font-weight: 600;
  color: var(--primary-strong);
}

@media (prefers-reduced-motion: reduce) {
  .buzon-fila,
  .buzon-buscar,
  .buzon-detalles > summary::before {
    transition: none;
  }
}

.buzon-volver {
  align-items: center;
}

/* ═══════════════════════════════════════════════════════════════════════
   INSIGNIA DEL CANAL EN EL AVATAR (lib/buzon.js, lib/icons.js)
   Redonda, abajo a la derecha, como el estado en un avatar de chat, con un
   filo del color de la superficie para despegarse de las iniciales. Es un
   ícono: blanco sobre el color del canal da 3:1 o más (WhatsApp #128C7E
   4.1:1, Instagram #C13584 5.1:1, voz #334155 10:1). El nombre del canal
   va en texto al lado (cabecera) o para el lector de pantalla (fila).
   ═══════════════════════════════════════════════════════════════════════ */
.buzon-avatar {
  position: relative;
}

.buzon-canal {
  position: absolute;
  right: -3px;
  bottom: -3px;
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--canal-whatsapp);
  color: var(--sobre-relleno);
  box-shadow: 0 0 0 2px var(--surface);
}

.buzon-canal[data-canal="instagram"] {
  background: var(--canal-instagram);
}

.buzon-canal[data-canal="voice"] {
  background: var(--canal-voz);
}

.buzon-canal svg {
  display: block;
  width: 11px;
  height: 11px;
}

.buzon-encabezado .buzon-canal {
  width: 16px;
  height: 16px;
}

.buzon-encabezado .buzon-canal svg {
  width: 10px;
  height: 10px;
}

/* ═══════════════════════════════════════════════════════════════════════
   ÍCONOS DIBUJADOS EN CSS
   Los caracteres «⋮», «★» y «✕» cambian de forma, tamaño y grosor con la
   fuente de cada sistema (y algunos salen como emoji). Estos se dibujan con
   `currentColor`: siguen el color y el tema del control que los lleva.
   ═══════════════════════════════════════════════════════════════════════ */
.icono-puntos {
  display: block;
  width: 3.5px;
  height: 3.5px;
  margin: auto;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 -5.5px 0 currentColor, 0 5.5px 0 currentColor;
}

.icono-estrella {
  display: inline-block;
  width: 12px;
  height: 12px;
  vertical-align: -1px;
  background: currentColor;
  clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}

/* ═══════════════════════════════════════════════════════════════════════
   SIN ESTILOS EN LÍNEA
   Lo que las vistas escribían con `style="…"`. Con una CSP sin
   'unsafe-inline' esos estilos no se aplican: márgenes que no estaban,
   formularios plegables que arrancaban abiertos, colores de nodo que no
   salían. Cada uno pasa a una clase.
   ═══════════════════════════════════════════════════════════════════════ */

/* Una fila de campos editables con su «Quitar» (inspector de nodos). */
.fila-de-campos {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: var(--space-1);
}

.fila-de-campos > .input,
.fila-de-campos > .select {
  flex: 1 1 0;
  min-width: 0;
}

/* Historial de versiones del editor de flujos. */
.version-fila {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 6px 0;
  border-bottom: 1px solid var(--hairline-soft);
  font-size: var(--text-sm);
}

/* Lista corta dentro de una ayuda (huecos, bloqueos, faltantes). */
.lista-de-ayuda {
  margin: var(--space-1) 0 0;
  padding-left: var(--space-5);
}

/* Casillas de registros fuente (Ciclo de vida). */
.lista-de-casillas {
  margin: var(--space-1) 0 0;
  padding: 0;
  list-style: none;
}

.lista-de-casillas > li {
  margin: 2px 0;
}

.casilla {
  width: 24px;
  height: 24px;
}

.select.select-angosto {
  width: auto;
  max-width: 320px;
}

.toolbar > .etiqueta-en-linea,
.toolbar > .titulo-en-barra {
  margin: 0;
}

/* Texto, insignias y acción de una línea de traza (Voz). */
.trace-cuerpo {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px var(--space-2);
  min-width: 0;
}

.detalle-plegable {
  margin-top: var(--space-3);
}

/* Consentimiento de un cliente (Clientes): un bloque con borde, no texto
   suelto pegado a la tabla. */
.consent-bloque {
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
}

/* ═══════════════════════════════════════════════════════════════════════
   CABECERA DEL CHAT EN UNA FILA (2026-10-02, a pedido del dueño: «no tengo
   margen de ver nada de la conversación»)
   Como WhatsApp: flecha atrás (teléfono), avatar, quién, una línea de estado
   que abre «Detalles» y «⋮» con todas las acciones (lib/buzon.js,
   `encabezadoDeChat`). Las listas son popovers nativos: anclados al botón en
   escritorio y hoja desde abajo en el teléfono. En el teléfono, con un chat
   abierto, el chat es la pantalla entera.
   ═══════════════════════════════════════════════════════════════════════ */

/* La barra de «Seleccionar» se esconde con `hidden`: su `display` no le gana. */
.chat-seleccion[hidden] {
  display: none;
}

.buzon-cabecera {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 4px;
  max-height: none;
  overflow: visible;
  padding: 8px 12px 8px 16px;
}

.buzon-cabecera > :not(.buzon-volver, .buzon-encabezado) {
  grid-column: 1 / -1;
}

.buzon-encabezado {
  grid-column: 2;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
}

.buzon-encabezado-texto {
  gap: 0;
}

.buzon-encabezado .buzon-titulo {
  font-size: var(--text-md);
  line-height: 1.3;
}

.buzon-encabezado .chat-contacto {
  display: flex;
  gap: 8px;
}

.buzon-encabezado .chat-contacto .mono {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* La línea de estado: insignias y un dato, en un renglón que se recorta. */
.buzon-estado {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  max-width: 100%;
  min-height: 24px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-muted);
  font: inherit;
  font-size: var(--text-xs);
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
}

button.buzon-estado:hover {
  color: var(--ink);
}

.buzon-estado > * {
  flex: none;
}

.buzon-estado .badge {
  padding: 0 8px;
  line-height: 20px;
}

.buzon-estado .chip {
  padding: 0 8px;
  line-height: 20px;
  font-size: var(--text-xs);
}

.buzon-estado-dato {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.buzon-estado .icono-chevron {
  width: 6px;
  height: 6px;
  margin: -3px 2px 0;
}

.buzon-mas,
.buzon-volver {
  border-color: transparent;
}

.buzon-volver {
  align-self: center;
  margin: 0;
}

.icono-atras {
  display: block;
  width: 10px;
  height: 10px;
  margin-left: 4px;
  border-left: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

/* Muchos fijados no se comen el chat: se desplazan dentro de su franja. */
.chat-fijados {
  max-height: 76px;
  overflow-y: auto;
}

/* ── Las listas flotantes: «⋮» y «Detalles» ── */
.buzon-flotante {
  min-width: 240px;
  max-width: min(360px, calc(100vw - 24px));
  max-height: min(70vh, 520px);
  margin: 0;
  padding: 6px;
  overflow-y: auto;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
}

.buzon-flotante:popover-open {
  display: grid;
  gap: 2px;
}

.buzon-flotante-menu .btn {
  display: block;
  width: 100%;
  min-height: 40px;
  padding: 8px 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink);
  font-weight: 500;
  text-align: left;
}

.buzon-flotante-menu .btn:hover:not(:disabled) {
  background: var(--surface-sunken);
}

.buzon-flotante-menu .btn[aria-pressed="true"] {
  color: var(--primary-strong);
  font-weight: 600;
}

.buzon-flotante-menu .btn[aria-pressed="true"]::after {
  content: " · activo";
  font-weight: 500;
  color: var(--ink-muted);
}

.buzon-flotante-menu .buzon-accion-peligro {
  margin-top: 4px;
  box-shadow: inset 0 1px 0 var(--hairline);
  border-radius: 0 0 8px 8px;
  color: var(--fc-danger);
}

.buzon-flotante-detalles {
  padding: 12px 16px;
  gap: 8px;
  font-size: var(--text-sm);
}

.buzon-flotante-detalles p {
  margin: 0;
}

.buzon-flotante-titulo {
  font-weight: 600;
  color: var(--ink);
}

@supports (anchor-name: --a) {
  .buzon-mas {
    anchor-name: --buzon-mas;
  }

  .buzon-estado {
    anchor-name: --buzon-estado;
  }

  .buzon-flotante-menu {
    position-anchor: --buzon-mas;
    inset: auto;
    top: anchor(bottom);
    right: anchor(right);
    margin-top: 6px;
  }

  .buzon-flotante-detalles {
    position-anchor: --buzon-estado;
    inset: auto;
    top: anchor(bottom);
    left: anchor(left);
    margin-top: 6px;
  }
}

/* ── Lista: herramientas que caben ── */
.buzon-herramientas-fila {
  flex-wrap: wrap;
}

.buzon-herramientas-fila .buzon-etiqueta {
  flex: 1 1 0;
  min-width: 0;
}

/* La cuenta, debajo y entera: al lado de los botones quedaba recortada a nada. */
.buzon-herramientas-fila [data-cuenta] {
  order: 1;
  flex-basis: 100%;
}

.buzon-herramientas-fila [data-cuenta]:empty {
  display: none;
}

@media (min-width: 801px) {
  .buzon-cuerpo {
    grid-template-columns: clamp(340px, 30%, 420px) minmax(0, 1fr);
  }
}

.buzon-herramientas-fila .btn {
  flex: none;
  white-space: nowrap;
}

/* Sin el control: aviso y botón en un renglón, también a 375px. */
.buzon-pie .respuesta:has(> .respuesta-aviso) > .respuesta-aviso {
  min-width: 0;
}

.buzon-pie .respuesta:has(> .respuesta-aviso) > .btn {
  flex: none;
  white-space: nowrap;
}

/* Pills con la letra del texto, no la de código. */
.badge {
  font-family: var(--font-body);
  font-weight: 600;
  border-radius: var(--radius-pill);
}

@media (max-width: 800px) {
  /* Con un chat abierto, el chat es la pantalla: sin barra del panel ni marco. */
  .main:has(> .view.active.vista-buzon) {
    padding: 0;
  }

  .contenido:has(.view.active .buzon[data-abierto]) > .topbar {
    display: none;
  }

  .buzon-cuerpo {
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .buzon-cabecera {
    padding: 6px 8px 6px 4px;
  }

  .buzon-encabezado {
    gap: 10px;
  }

  .buzon-encabezado .buzon-avatar {
    width: 36px;
    height: 36px;
    font-size: 13px;
  }

  .buzon-chat .chat-lista {
    padding: 12px 10px 16px;
  }

  .buzon-chat .chat-burbuja {
    max-width: 85%;
  }

  .buzon-pie {
    padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
  }

  /* «Actualizar» sobra: la lista se actualiza sola cada 5 s. */
  #conv-actualizar {
    display: none;
  }

  /* Las listas, como hoja que sube desde abajo: a la mano del pulgar. */
  .buzon-flotante {
    inset: auto 0 0 0;
    width: 100%;
    max-width: none;
    max-height: 80vh;
    margin: 0;
    padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
    border-radius: 18px 18px 0 0;
  }

  .buzon-flotante::backdrop {
    background: var(--fondo-overlay);
  }

  .buzon-flotante-menu .btn {
    min-height: 48px;
    font-size: var(--text-md);
  }
}

/* En pantallas de dedo el menú del mensaje se abre con un toque largo,
   como en WhatsApp: el botón tapaba el texto de la burbuja. */
@media (hover: none) and (pointer: coarse) {
  .chat-menu {
    display: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   LEADS (2026-10-03)
   Los filtros en una franja (plegados en el teléfono), filas alineadas, y
   el detalle AL LADO de la lista en escritorio ancho (no al final de la
   página, donde había que ir a buscarlo); en pantallas menores entra como
   panel desde la derecha, a pantalla completa en el teléfono.
   ═══════════════════════════════════════════════════════════════════════ */
.leads-barra {
  padding: 10px 16px;
}

.leads-filtros > summary {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
  list-style: none;
}

.leads-filtros > summary::-webkit-details-marker {
  display: none;
}

.leads-filtros > summary::before {
  content: "";
  width: 6px;
  height: 6px;
  margin: 0 10px 2px 2px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-control) var(--ease);
}

.leads-filtros[open] > summary::before {
  transform: rotate(45deg);
}

.leads-filtros-campos {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin: 8px 0 6px;
}

.leads-filtros-campos .field-group {
  flex: 1 1 150px;
  max-width: none;
  margin: 0;
}

.leads-filtros-botones {
  display: flex;
  gap: 8px;
}

.leads-filtros-botones .btn {
  white-space: nowrap;
}

/* La insignia arriba del título y las acciones a la derecha, en todo ancho. */
#view-leads .lead-row {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px 16px;
  padding: 14px 16px;
  transition: border-color var(--dur-control) var(--ease);
}

#view-leads .lead-ident {
  grid-column: 1;
  flex-direction: row;
  flex-wrap: wrap;
}

#view-leads .lead-meta {
  grid-column: 1;
}

#view-leads .lead-actions {
  grid-column: 2;
  grid-row: 1 / span 2;
}

#view-leads .lead-row:hover {
  border-color: rgb(var(--color-ink-faint));
}

#view-leads .lead-row .lead-interest {
  font-size: var(--text-md);
  font-weight: 600;
}

#view-leads .lead-next {
  font-weight: 500;
}

/* Las etiquetas de los datos, con la letra del texto: en mayúsculas y
   monoespaciada parecían una planilla técnica. */
.lead-dato-label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  text-transform: none;
  letter-spacing: normal;
}

.chip {
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-weight: 500;
}

#lead-detalle .lead-datos {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 860px) {
  #view-leads .lead-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }

  #view-leads .lead-actions {
    grid-column: 1;
    grid-row: auto;
  }
}

/* En el teléfono, la lista sin la tarjeta de afuera: le sobraban márgenes. */
@media (max-width: 800px) {
  #view-leads > .card:not(.leads-barra, #lead-detalle) {
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
  }
}

@media (min-width: 1100px) {
  #view-leads.active:has(> #lead-detalle:not([hidden])) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(380px, 42%);
    align-items: start;
    column-gap: 16px;
  }

  /* `:where`: sin peso, para que las columnas de abajo le ganen. */
  :where(#view-leads.active:has(> #lead-detalle:not([hidden]))) > * {
    grid-column: 1 / -1;
  }

  #view-leads.active > .card:not(.leads-barra, #lead-detalle) {
    grid-column: 1;
  }

  #view-leads.active > #lead-detalle {
    grid-column: 2;
    grid-row: 3;
    position: sticky;
    top: 0;
    max-height: calc(100vh - 100px);
    overflow-y: auto;
  }

  /* Con el detalle al lado, la fila se apila: la columna es angosta. */
}

@media (max-width: 1099.98px) {
  #lead-detalle:not([hidden]) {
    position: fixed;
    inset: 0 0 0 auto;
    z-index: 960;
    width: min(560px, 100%);
    margin: 0;
    overflow-y: auto;
    border-radius: 0;
    box-shadow: var(--shadow-drawer);
  }
}

#lead-detalle:focus {
  outline: none;
}

/* ═══════════════════════════════════════════════════════════════════════
   ETIQUETAS CON LA LETRA DEL TEXTO (2026-10-03)
   La letra monoespaciada en mayúsculas se lee como una planilla técnica, y
   el dueño quiere un producto que "entre por los ojos" (ElevenLabs, Kommo).
   La mono queda sólo para cifras y códigos (`.mono`, horas, nodos de flujo).
   ═══════════════════════════════════════════════════════════════════════ */
.brand-tagline,
.nav-group,
.stat-label,
.table th,
.stat-strip dt,
.page-meta {
  font-family: var(--font-body);
}

.brand-tagline {
  text-transform: none;
  letter-spacing: normal;
}

/* Grupos del menú y encabezados de tabla: mayúscula chica y espaciada. */
.nav-group,
.table th {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
}

/* Un encabezado de FILA (el correo, el nombre) es un dato, no un rótulo de columna. */
.table tbody th {
  background: transparent;
  color: var(--ink);
  font-size: var(--text-sm);
  font-weight: 500;
  text-transform: none;
  letter-spacing: normal;
}

.stat-label,
.stat-strip dt {
  font-size: var(--text-sm);
  font-weight: 500;
  text-transform: none;
  letter-spacing: normal;
}

/* ═══════════════════════════════════════════════════════════════════════
   BARRA LATERAL ACHICADA (2026-10-03, a pedido del dueño)
   En escritorio, Conversaciones y Derivaciones abren con la barra en sólo
   íconos (64px) para que el chat tenga el ancho; el botón de menú la abre y
   la cierra. El nombre de cada sección sale al pasar el mouse (`title`) y
   sigue siendo el nombre accesible del botón. En el teléfono no cambia nada.
   ═══════════════════════════════════════════════════════════════════════ */
@media (min-width: 768px) {
  .menu-btn {
    display: inline-grid;
  }


  .menu-angosto .sidebar {
    width: 64px;
  }

  .menu-angosto .sidebar-head {
    justify-content: center;
    padding: 18px 8px 14px;
  }

  .menu-angosto .brand,
  .menu-angosto .sidebar-pie {
    display: none;
  }

  .menu-angosto .nav {
    padding: 4px 8px 12px;
  }

  /* El rótulo del grupo pasa a ser una raya entre grupos. */
  .menu-angosto .nav-group {
    height: 1px;
    margin: 8px 6px;
    padding: 0;
    overflow: hidden;
    background: rgb(var(--color-blanco) / 0.1);
    color: transparent;
  }

  /* El texto queda (es el nombre accesible) pero no ocupa lugar. */
  .menu-angosto .nav-btn {
    justify-content: center;
    padding: 10px 0;
    font-size: 0;
  }

  .menu-angosto .nav-icon {
    width: 18px;
    height: 18px;
  }

  .menu-angosto .nav-cuenta,
  .menu-angosto .nav-nuevas {
    position: absolute;
    top: 2px;
    right: 2px;
    min-width: 18px;
    padding: 0 4px;
    line-height: 18px;
  }

  .menu-angosto .nav-nuevas {
    top: auto;
    bottom: 2px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar {
    transition: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   CONTEXTO DE LA DERIVACIÓN (2026-10-03, lib/contextoDerivacion.js)
   El «i» junto al nombre (y en la fila de «Derivaciones») abre la burbuja
   con lo que escribió el modelo. Es un `.buzon-flotante`: anclada al «i» en
   escritorio y hoja desde abajo en el teléfono (el bloque de la cabecera).
   Sólo fichas existentes; sin colores ni tamaños propios.
   ═══════════════════════════════════════════════════════════════════════ */
.ctx-derivacion {
  display: inline-flex;
  align-items: center;
  margin-left: 2px;
  vertical-align: middle;
}

/* Sin marco, como «⋮»: es un ícono de la cabecera, no un botón más. */
.ctx-derivacion-info {
  border-color: transparent;
}

/* En la fila, el chip y la «i» en UN renglón: el chip se recorta. 32px: la
   fila entera ya es el blanco grande. */
.buzon-fila .ctx-derivacion-info {
  width: 32px;
  height: 32px;
  min-width: 32px;
  min-height: 32px;
}

.buzon-fila [data-derivada] {
  display: inline-block;
  min-width: 0;
  max-width: calc(100% - 36px);
  overflow: hidden;
  text-overflow: ellipsis;
}

.icono-info {
  display: inline-grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border: 1.5px solid currentColor;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  line-height: 1;
}

.icono-info::before {
  content: "i";
}

.buzon-flotante-contexto {
  padding: 12px 16px;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

.buzon-flotante-contexto:popover-open {
  gap: 8px;
}

.buzon-flotante-contexto p {
  margin: 0;
}

.ctx-derivacion-cuerpo {
  display: grid;
  gap: 8px;
}

.ctx-derivacion-rotulo {
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  color: var(--ink-muted);
}

.ctx-derivacion-lista {
  margin: 0;
  padding-left: 18px;
}

.ctx-derivacion-datos {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.ctx-derivacion-pie {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.ctx-derivacion-pie:empty {
  display: none;
}

.ctx-derivacion-acciones {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* En escritorio se cierra con Escape o un clic afuera; en el teléfono, con el botón. */
@media (min-width: 801px) {
  .ctx-derivacion-cerrar {
    display: none;
  }
}

/* `anchor-scope`: cada fila tiene su «i»; sin él, todas se anclarían al último. */
@supports (anchor-name: --a) and (anchor-scope: --a) {
  @media (min-width: 801px) {
    .ctx-derivacion {
      anchor-scope: --contexto;
    }

    .ctx-derivacion-info {
      anchor-name: --contexto;
    }

    .buzon-flotante-contexto {
      position-anchor: --contexto;
      inset: auto;
      top: anchor(bottom);
      left: anchor(left);
      margin-top: 6px;
      position-try-fallbacks: flip-block, flip-inline;
    }
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   OBJETIVOS TÁCTILES
   En teléfono, y en cualquier pantalla de dedo, todo lo que se pulsa mide
   al menos 44px (los íconos, 44×44). Los campos van a 16px: con menos,
   Safari en iPhone acerca la página al enfocarlos. Va al final de la hoja
   para ganarle a los altos compactos de cada componente.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 767.98px), (pointer: coarse) {
  .btn,
  .nav-btn,
  .palette-btn,
  .toolbar-check,
  .sidebar-salir,
  .modo-pill,
  .buzon-filtro,
  .buzon-encabezado .chat-contacto .btn,
  .buzon-seleccion-acciones .btn,
  .input,
  .select {
    min-height: 44px;
  }

  .icon-btn,
  .sidebar-cerrar,
  .buzon-menu,
  .fc-toast-close {
    min-width: 44px;
    min-height: 44px;
  }

  .input,
  .select,
  .textarea,
  .buzon-buscar {
    font-size: 16px;
  }
}

/* ── Avisos al equipo (lib/avisos.js) ─────────────────────────────────
   Arriba al centro y sin vencer: una cita nueva no puede pasar de largo.
   Cada aviso es un `.fc-toast` (mismo fondo y cruz que los de abajo). */
.avisos-pila {
  position: fixed;
  top: 12px;
  left: 50%;
  z-index: 1100;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: min(460px, calc(100vw - 32px));
  transform: translateX(-50%);
  pointer-events: none;
}

.avisos-pila:empty {
  display: none;
}

.avisos-pila .fc-toast {
  pointer-events: auto;
  border-left: 4px solid var(--primary);
}

.aviso-enlace {
  flex: 1;
  min-width: 0;
  color: inherit;
  font-weight: 600;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.aviso-enlace:hover {
  text-decoration: underline;
}

.avisos-pila :focus-visible {
  outline-color: currentColor;
}

.avisos-btn .nav-icon {
  width: 16px;
  height: 16px;
}

.avisos-activar {
  white-space: nowrap;
}

.avisos-estado {
  margin: 0;
  padding: 4px 12px 8px;
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

.avisos-menu .buzon-flotante-titulo {
  margin: 0;
  padding: 8px 12px 0;
}

@supports (anchor-name: --a) {
  .avisos-btn {
    anchor-name: --avisos;
  }

  .buzon-flotante.avisos-menu {
    position-anchor: --avisos;
  }
}
