/* ==========================================================
   VALION Control Center
   Sistema de diseño según README-STYLE.md — variables, tipografía,
   espaciado y componentes reutilizables. No modificar sin revisar ese
   documento primero (los únicos 2 valores "de marca" son --brand-primary
   y --brand-accent, y ya coinciden con los de valion.com.co).
   ========================================================== */

:root {
  color-scheme: light;

  --brand-primary:       #1F2937;
  --brand-primary-hover: #1B2532;
  --brand-on-primary:    #ffffff;
  --brand-accent:        #FF9900;
  --brand-accent-hover:  #E68600;
  --brand-gradient:      linear-gradient(90deg, #A9ECD9, #A7D3F5, #C8D9F7);

  /* Alto de la barra superior. Hay cosas ancladas a el (el sub-menu
     lateral de Documentacion, el inset del panel del asistente en
     mobile), asi que vive aca y no repetido como 56px suelto. */
  --topbar-h: 56px;

  /* La tira fina de arriba del todo (Preferencias) y la suma de las dos.
     Lo que se ancla al BORDE DE LA VENTANA usa --cabecera-h; lo que se
     ancla al topbar en si -- el menu desplegable, que es absolute dentro
     de el -- sigue usando --topbar-h. Confundirlos deja el desplegable
     flotando 34 px por debajo de donde toca. */
  --barra-fina-h: 34px;
  --cabecera-h: calc(var(--barra-fina-h) + var(--topbar-h));

  --radius-sm:   6px;
  --radius-md:   10px;
  --radius-lg:   16px;
  --radius-pill: 999px;

  --surface-1:      #ffffff;
  --page:           #F8FAFC;
  --text-primary:   #232F3E;
  --text-secondary: #667085;
  --text-muted:     #7B8794;
  --gridline:       #E8EDF2;
  --baseline:       #D6DDE6;
  --border:         #E8EDF2;

  --nav-surface: rgba(255,255,255,.82);
  --nav-border:  rgba(226,232,240,.6);

  --series-1:        #2a78d6;
  --success:         #006300;
  --status-good:     #0ca30c;
  --status-warning:  #fab219;
  --status-serious:  #ec835a;
  --status-critical: #d03b3b;
  --delta-bad:       #d03b3b;

  --section-a-bg: color-mix(in srgb, #16A34A 7%, var(--surface-1));
  --section-b-bg: color-mix(in srgb, #1F2937 6%, var(--surface-1));
  --section-c-bg: color-mix(in srgb, #2F6FED 7%, var(--surface-1));

  --ai-accent: #7C3AED;
  --ai-bg:     color-mix(in srgb, #7C3AED 6%, var(--surface-1));
}

/* EL TEMA OSCURO CUELGA DE UN ATRIBUTO, NO DE LA MEDIA QUERY.

   Antes era @media (prefers-color-scheme: dark) a secas, que no deja
   elegir: si el sistema esta en oscuro, la aplicacion esta en oscuro y no
   hay nada que hacer. Ahora el usuario puede fijar Claro u Oscuro, o
   dejarlo en Dispositivo.

   El truco para no duplicar los tokens es que "Dispositivo" NO se queda
   sin resolver: un script en el <head> de index.html y login.html lee la
   preferencia guardada, la resuelve contra matchMedia y escribe el
   atributo ya concreto antes del primer pintado. Asi aqui solo hace falta
   un bloque, el de [data-tema="oscuro"], en vez de repetir la lista
   entera para la media query y otra vez para el atributo.

   Va en el <head> y no en tema.js a proposito: cualquier cosa que corra
   despues de la hoja de estilos produce un parpadeo blanco al entrar en
   oscuro. */
:root[data-tema="oscuro"] {
    color-scheme: dark;
    --brand-primary:       #1F2937;
    --brand-primary-hover: #2A3849;
    --brand-on-primary:    #ffffff;

    --surface-1:      #1a1a19;
    --page:           #0d0d0d;
    --text-primary:   #ffffff;
    --text-secondary: #c3c2b7;
    --text-muted:     #898781;
    --gridline:       #2c2c2a;
    --baseline:       #383835;
    --border:         rgba(255,255,255,0.10);

    --nav-surface: rgba(26,26,25,.82);
    --nav-border:  rgba(255,255,255,.10);

    --series-1:        #3987e5;
    --status-critical: #d03b3b;
    --delta-bad:       #e66767;
}

/* === Base === */

* {
  box-sizing: border-box;
}

html {
  overflow-x: hidden;
  overflow-y: auto;
  /* SIN "scrollbar-gutter: stable". Reservaba siempre los ~15px de la
     barra de scroll, y en las vistas cortas -que no scrollean- esa franja
     quedaba vacia a la derecha: la topbar terminaba antes del borde de la
     ventana. No se puede tapar desde la topbar, porque el gutter tambien
     encoge el bloque contenedor inicial y 100vw ya viene recortado.
     A cambio, al pasar de una vista corta a una larga el contenido se
     corre 15px cuando aparece la barra de scroll. */
}

body {
  margin: 0;
  font-family: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--page);
  color: var(--text-primary);
  font-size: 14px;
}

[hidden] {
  display: none !important;
}

h1, h2, h3, p {
  margin: 0;
}

/* === Shell: topbar === */

/* ---------------------------------------------- barra fina superior
   Una tira por encima del topbar, a todo el ancho, con lo que no es
   navegacion: hoy solo Preferencias. Es la misma pieza que ya lleva
   VALION INSIGHTS, para que las dos herramientas se manejen igual.

   El hueco de la izquierda esta vacio a proposito: ahi va el selector de
   idioma cuando el Control Center se traduzca. */
.barra-fina {
  position: sticky;
  top: 0;
  /* Por encima del topbar (10): si no, el panel de Preferencias sale por
     debajo de la barra de navegacion. */
  z-index: 11;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  height: var(--barra-fina-h);
  padding: 0 16px;
  background: var(--nav-surface);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--nav-border);
  font-size: 12.5px;
}

.barra-fina__boton {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  font: inherit;
  color: var(--text-secondary);
  cursor: pointer;
  transition: color .15s ease, background .15s ease, border-color .15s ease;
}
.barra-fina__boton:hover {
  color: var(--text-primary);
  background: color-mix(in srgb, var(--text-primary) 6%, transparent);
}
.barra-fina__boton[aria-expanded="true"] {
  color: var(--text-primary);
  border-color: var(--border);
  background: var(--surface-1);
}
.barra-fina__flecha {
  width: 11px;
  height: 11px;
  transition: transform .15s ease;
}
.barra-fina__boton[aria-expanded="true"] .barra-fina__flecha { transform: rotate(180deg); }

/* El panel. Se ancla a la DERECHA del boton -- el bug que hubo en el
   portal de soporte fue justo este: boton a un lado y desplegable al
   otro. */
.barra-fina__menu {
  position: absolute;
  top: calc(var(--barra-fina-h) - 2px);
  right: 16px;
  min-width: 190px;
  padding: 10px 0 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .14);
}
.barra-fina__menu[hidden] { display: none; }

.barra-fina__titulo {
  display: block;
  padding: 0 14px 7px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Cada opcion es un <label> con su radio dentro: el radio es de verdad,
   asi que el teclado y los lectores de pantalla lo entienden sin que
   haya que fingir nada con roles. */
.barra-fina__opcion {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 14px;
  cursor: pointer;
  color: var(--text-secondary);
  transition: background .12s ease, color .12s ease;
}
.barra-fina__opcion:hover {
  background: color-mix(in srgb, var(--text-primary) 6%, transparent);
  color: var(--text-primary);
}
.barra-fina__opcion input { accent-color: var(--brand-accent); margin: 0; }
.barra-fina__opcion:has(input:checked) {
  color: var(--text-primary);
  font-weight: 600;
  background: color-mix(in srgb, var(--text-primary) 8%, transparent);
}
.barra-fina__opcion:focus-within {
  outline: 2px solid var(--brand-accent);
  outline-offset: -2px;
}

@media (max-width: 480px) {
  .barra-fina { padding: 0 10px; }
  .barra-fina__menu { right: 10px; }
}

.topbar {
  position: sticky;
  top: var(--barra-fina-h);
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 24px;
  height: var(--topbar-h);
  background: var(--nav-surface);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--nav-border);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  text-decoration: none;
  color: inherit;
}
.brand-logo {
  height: 22px;
  width: auto;
  display: block;
}
.brand-logo--dark {
  display: none;
}
:root[data-tema="oscuro"] .brand-logo--light { display: none; }
:root[data-tema="oscuro"] .brand-logo--dark { display: block; }
.brand-suffix {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-muted);
  padding-left: 10px;
  border-left: 1px solid var(--border);
}
@media (max-width: 480px) {
  .brand-suffix { display: none; }
}

.user-info {
  font-size: 13px;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 10px;
}

/* === Pantalla de bienvenida (#/) ===
   Deliberadamente vacia: logo centrado y saludo, nada mas. Los enlaces a
   las otras plataformas de VALION que vivian aca son ahora el grupo
   "Ayuda" del menu superior. */

.home-welcome {
  /* Centrado vertical real: descuenta el topbar y el padding de .dash-col
     para que el bloque quede en la mitad de la pantalla, no de un
     contenedor de alto indefinido. */
  min-height: calc(100vh - var(--cabecera-h) - 48px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  text-align: center;
  /* 50px arriba del centro exacto. Va con transform y no restandole alto
     al contenedor para que el centrado siga siendo el del viewport: si
     manana cambia el alto del topbar, esto se acomoda solo. */
  transform: translateY(-50px);
}
.home-welcome__logo {
  width: min(340px, 62vw);
  height: auto;
}
.home-welcome__title {
  font-size: 28px;
  font-weight: 800;
  color: var(--text-primary);
  letter-spacing: -.01em;
}

@media (max-width: 480px) {
  .home-welcome { min-height: calc(100vh - var(--cabecera-h) - 32px); }
  .home-welcome__title { font-size: 22px; }
}

/* === Dropdown de usuario (topbar) === */

.user-menu {
  position: relative;
}
.user-menu__trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-primary);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.user-menu__trigger:hover {
  background: var(--gridline);
  border-color: var(--border);
}
.user-menu__chevron {
  width: 14px;
  height: 14px;
  color: var(--text-muted);
}
.user-menu__icon {
  width: 18px;
  height: 18px;
  color: var(--text-muted);
  flex: none;
}
.user-menu__panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 220px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px rgba(15, 23, 42, .18);
  padding: 6px;
  z-index: 20;
}
.user-menu__email {
  padding: 8px 10px 6px;
  font-size: 12px;
  color: var(--text-muted);
  border-bottom: 1px solid var(--gridline);
  margin-bottom: 4px;
  word-break: break-all;
}
.user-menu__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  color: var(--text-primary);
  font: inherit;
  font-size: 13px;
  text-decoration: none;
  cursor: pointer;
}
.user-menu__item:hover {
  background: var(--gridline);
}
.user-menu__item--danger {
  color: var(--status-critical);
  margin-top: 2px;
}
.user-menu__item--danger:hover {
  background: color-mix(in srgb, var(--status-critical) 12%, transparent);
}

/* Wrapper de icono. Sobrevive al sidebar: lo usan los items del menu
   superior y la hamburguesa. El sistema de diseno pide que ningun SVG
   vaya suelto (README-STYLE.md, seccion de accesibilidad). */
.sidebar-link__icon {
  flex: none;
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: inherit;
}
.sidebar-link__icon svg { width: 100%; height: 100%; }

/* === Navegacion: menu superior ===
   Reemplazo del sidebar lateral fijo (que se comia 260px de ancho en
   todas las pantallas). Cada grupo es un desplegable; el patron es el
   mismo del menu de usuario: wrapper relativo + panel absoluto + el
   atributo nativo [hidden]. */

.topnav {
  display: flex;
  align-items: center;
  /* Centrada en el espacio que queda entre el logo y el menu de usuario.
     No se centra respecto del viewport (con position:absolute) a
     proposito: eso la haria pisar el logo o el nombre del usuario en
     cuanto uno de los dos creciera. */
  justify-content: center;
  gap: 2px;
  flex: 1;
  min-width: 0;
  /* NADA de overflow aca. Tuvo "overflow-x: auto" para que la barra no
     hiciera wrap, y eso rompio los desplegables por completo: cuando un
     eje deja de ser "visible", el otro pasa a "auto" por especificacion,
     asi que .topnav se volvia un contenedor con scroll y RECORTABA los
     paneles, que cuelgan por debajo. Los menus se abrian y no se veian.
     Que la nav quepa se resuelve con el breakpoint de la hamburguesa, no
     recortando. */
}

.topnav-link,
.topnav-trigger {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
  padding: 7px 10px;
  border: none;
  background: transparent;
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.topnav-link:hover,
.topnav-trigger:hover { background: var(--gridline); color: var(--text-primary); }
.topnav-link.active,
.topnav-trigger.active {
  background: color-mix(in srgb, var(--brand-primary) 8%, var(--surface-1));
  color: var(--text-primary);
}

.topnav-group { position: relative; flex: none; }
.topnav-chevron { width: 14px; height: 14px; flex: none; }

.topnav-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 240px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 32px rgba(15, 23, 42, .18);
  padding: 6px;
  /* El topbar es z-index 10 y no tiene overflow:hidden, asi que el panel
     escapa bien; 20 lo deja por encima del contenido de la vista. */
  z-index: 20;
}

.topnav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  text-decoration: none;
  white-space: nowrap;
}
.topnav-item:hover { background: var(--gridline); }

/* Encabezado de subseccion dentro de un desplegable. Mismo lenguaje que
   las etiquetas de grupo que tenia el sidebar: chico, mayusculas, tenue.
   El primero no lleva separador arriba porque queda pegado al borde del
   panel; los siguientes si, para despegarlos de la subseccion anterior. */
.topnav-subgroup {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted);
  padding: 10px 10px 4px;
  margin-top: 4px;
  border-top: 1px solid var(--gridline);
}
.topnav-subgroup:first-child {
  margin-top: 0;
  border-top: none;
  padding-top: 4px;
}
.topnav-item.active { background: color-mix(in srgb, var(--brand-primary) 8%, var(--surface-1)); }

.topnav-burger {
  display: none;
  flex: none;
  border: none;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  padding: 8px;
  border-radius: var(--radius-md);
}
.topnav-burger:hover { background: var(--gridline); color: var(--text-primary); }

.dash-col {
  /* Sin sidebar que compensar: el contenido usa todo el ancho. El
     max-width evita que en un monitor muy ancho los parrafos queden en
     lineas kilometricas; las vistas anchas de verdad (Pricing) llegan
     igual a su tope. */
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
  /* Abajo 96 y no 24: el boton flotante de VALION IA (.chat-fab-wrap) es
     fixed en la esquina inferior derecha y ocupa unos 80px. Sin este
     espacio se monta sobre lo ultimo de la pagina -- y desde que TODA
     lista termina en el paginador, lo que tapa es justo el selector de
     "Por pagina", que vive en esa misma esquina. */
  padding: 24px 24px 96px;
  box-sizing: border-box;
}

/* === Pagina de login (login.html) -- standalone, sin topbar/sidebar === */

.auth-body {
  min-height: 100vh;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--page);
  padding: 24px;
  box-sizing: border-box;
}
.auth-shell {
  width: 100%;
  max-width: 380px;
}
.auth-card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 32px 28px;
  box-shadow: 0 20px 60px rgba(15, 23, 42, .12);
}
.auth-brand {
  display: flex;
  justify-content: center;
  margin-bottom: 24px;
}
.auth-brand .brand-logo {
  height: 32px;
}
/* El selector empleado / cliente de la pantalla de login. Vive solo
   dentro de #view-login: en recuperar contraseña estorba, porque ahi ya
   se sabe quien es. */
.auth-quien {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: 22px;
  background: var(--page);
  border: 1px solid var(--border);
  border-radius: 999px;
}
.auth-quien__op {
  flex: 1;
  padding: 8px 12px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}
.auth-quien__op--activa {
  background: var(--surface-1);
  color: var(--text-primary);
  box-shadow: 0 1px 3px rgba(15, 23, 42, .10);
  cursor: default;
}

.auth-card h1 {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
  text-align: center;
  margin-bottom: 4px;
}
.auth-card p.muted {
  text-align: center;
  margin-bottom: 20px;
}
.auth-submit {
  width: 100%;
  justify-content: center;
  margin-top: 4px;
}
.auth-link {
  display: block;
  width: 100%;
  text-align: center;
  margin-top: 16px;
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: 13px;
  cursor: pointer;
  text-decoration: underline;
}
.auth-link:hover {
  color: var(--text-primary);
}

/* La nav se esconde detras de la hamburguesa y, al abrirse, baja como un
   panel de ancho completo. Es el MISMO markup y el mismo JS que en
   escritorio -- lo unico que cambia es que los desplegables de grupo
   pasan a ser estaticos y empujan hacia abajo en vez de flotar.
   
   El corte va en 1200 y no en los 760 habituales de navegacion, y es un
   breakpoint propio de este componente con una razon medida: un Admin ve
   "Inicio + 6 grupos" (~700px de nav) mas el logo con su sufijo (~215px)
   y el nombre de usuario (~195px), y eso no entra por debajo de ~1200px.
   Por debajo, hamburguesa. La alternativa era recortar la nav con scroll
   horizontal, que es exactamente lo que rompio los desplegables.
   
   El burger y el panel comparten el MISMO @media a proposito: si se
   separaran, entre los dos numeros habria un boton que no hace nada.
   
   Y el panel se oculta con display, NO con el atributo [hidden]: hidden
   es global y con !important, asi que si alguien cierra el menu en el
   telefono y despues agranda la ventana, la navegacion desapareceria en
   escritorio sin forma de recuperarla desde CSS. */
@media (max-width: 1200px) {
  .topnav-burger { display: flex; }

  .topnav {
    display: none;
    position: absolute;
    top: var(--topbar-h);
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 2px;
    max-height: calc(100vh - var(--cabecera-h));
    overflow-y: auto;
    padding: 8px;
    background: var(--surface-1);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 12px 32px rgba(15, 23, 42, .18);
  }
  .topnav.topnav--open { display: flex; }

  .topnav-panel {
    position: static;
    min-width: 0;
    border: none;
    box-shadow: none;
    padding: 0 0 4px 26px;
  }
}

@media (max-width: 480px) {
  .dash-col {
    padding: 16px;
  }
  .topbar {
    padding: 0 16px;
  }
}

/* === Card === */

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px;
  margin-bottom: 16px;
}
.card h2 {
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted);
  margin: 0 0 16px;
  font-weight: 600;
}

/* Titulo de la card de "sesion activa" (chat en curso / llamada en
   curso) -- a diferencia de .card h2 (eyebrow, para titulos de seccion
   estaticos), esta variante comunica estado en vivo junto al dot de
   color y los controles de la sesion, por eso se le da mas peso. */
.card h2.card-title--session {
  text-transform: none;
  letter-spacing: normal;
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  margin: 0;
}

@media (max-width: 480px) {
  .card {
    padding: 14px;
  }
}

/* === Botones === */

.btn {
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  padding: 10px 16px;
  cursor: pointer;
  transition: transform .2s ease, background .2s ease;
}
.btn--sm { padding: 6px 10px; font-size: 12px; }
.btn--primary { background: var(--brand-primary); color: var(--brand-on-primary); }
.btn--primary:hover { background: var(--brand-primary-hover); transform: translateY(-1px); }
.btn--primary:disabled { opacity: .6; cursor: default; }
.btn--ghost { background: var(--gridline); border-color: var(--border); color: var(--text-secondary); }
.btn--ghost:hover { background: color-mix(in srgb, var(--text-secondary) 12%, var(--gridline)); }
.btn--ghost-danger { background: var(--gridline); color: var(--status-critical); }
.btn--ghost-danger:hover { background: color-mix(in srgb, var(--status-critical) 12%, transparent); border-color: var(--status-critical); }

.icon-btn {
  flex: none;
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}
.icon-btn:hover { background: var(--gridline); color: var(--text-primary); }
.icon-btn:disabled { opacity: .5; cursor: default; }
.icon-btn--danger:hover { background: color-mix(in srgb, var(--status-critical) 12%, transparent); color: var(--status-critical); }
/* Variante chica: para cuando el boton acompana una linea de texto y no
   tiene que competir con ella (el copiar del codigo de proyecto, el
   quitar de una fila de Pricing). */
.icon-btn--xs { width: 20px; height: 20px; }
.icon-btn--xs svg { width: 13px; height: 13px; }

/* Segunda linea de una tarjeta: el codigo con su boton de copiar y lo que
   lo acompane (estado, fecha). La usan Proyectos, Propuestas y el
   portafolio de Pricing -- los tres muestran el mismo codigo. */
.code-line,
.project-code-line {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}
.code-text,
.project-code { font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .btn--primary:hover { transform: none; }
}

/* === Badges, dots y severidad === */

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600;
  padding: 3px 8px 3px 6px;
  border-radius: 999px;
  white-space: nowrap;
  background: var(--gridline);
  color: var(--text-secondary);
}
.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; display: inline-block; }
.dot.critica  { background: var(--status-critical); }
.dot.alta     { background: var(--status-serious); }
.dot.media    { background: var(--status-warning); }
.dot.good     { background: var(--status-good); }
.dot.neutral  { background: var(--text-muted); }
.dot.tipo     { background: var(--series-1); }

/* === Formularios === */

.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.field label { font-size: 12px; color: var(--text-muted); }
.field input, .field select, .field textarea {
  font-family: inherit;
  font-size: 14px;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
}
.field textarea { resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { outline: 2px solid var(--text-primary); outline-offset: 1px; }
.form-error { color: var(--delta-bad); font-size: 13px; min-height: 18px; }

/* === Modal === */

.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, .5);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 40px 16px;
  overflow-y: auto;
  z-index: 100;
}
.modal {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 20px 60px rgba(15, 23, 42, .3);
  width: 100%;
  max-width: 560px;
  padding: 20px;
}

/* === Skeleton loading === */

.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--gridline) !important;
  pointer-events: none;
}
.skeleton::after {
  content: "";
  position: absolute; inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--baseline) 55%, transparent), transparent);
  animation: skeleton-shimmer 1.6s ease-in-out infinite;
}
@keyframes skeleton-shimmer { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { .skeleton::after { animation: none; } }

.skeleton--text { display: block; height: .85em; min-height: 10px; border-radius: 4px; width: 100%; }
.skeleton--pill { border-radius: var(--radius-pill); }
.skeleton--circle { border-radius: 50%; }

/* === Listas de items === */

.item { display: flex; gap: 12px; padding: 12px 0; border-top: 1px solid var(--gridline); align-items: center; }
.item:first-child { border-top: none; }
.item .body { flex: 1; min-width: 0; }
.item .title { font-size: 14px; margin-bottom: 2px; }
.item .sub { font-size: 12px; color: var(--text-muted); }
.item .amount { flex: none; font-size: 14px; font-weight: 600; text-align: right; min-width: 90px; }

/* === Chat de demos === */

.chat-message {
  max-width: 75%;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  font-size: 14px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
}
.chat-message--user {
  align-self: flex-end;
  background: var(--brand-primary);
  color: var(--brand-on-primary);
  border-bottom-right-radius: 4px;
}
.chat-message--assistant {
  align-self: flex-start;
  background: var(--gridline);
  color: var(--text-primary);
  border-bottom-left-radius: 4px;
}
.chat-message--pending { opacity: .6; }
.chat-message__list { margin: 4px 0; padding-left: 18px; }
.chat-message__list li { margin: 2px 0; }

/* === Demos: chips de plantilla, contador de caracteres, copiar mensaje === */

.chip-row { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--gridline);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.chip:hover { background: color-mix(in srgb, var(--brand-primary) 8%, var(--gridline)); color: var(--text-primary); border-color: var(--baseline); }

.preference-group { margin-bottom: 8px; }
.preference-group__label { font-size: 11px; color: var(--text-muted); margin: 0 0 4px; }
.chip.chip--active { background: var(--brand-primary); color: var(--brand-on-primary); border-color: var(--brand-primary); }
.chip.chip--active:hover { background: var(--brand-primary-hover); }

.char-counter { font-size: 11px; color: var(--text-muted); text-align: right; font-variant-numeric: tabular-nums; }
.count-warn  { color: var(--status-warning); }
.count-limit { color: var(--delta-bad); font-weight: 600; }

/* Copiar mensaje -- reusa .icon-btn (ya existente) y solo agrega el
   posicionamiento absoluto + revelado en hover. */
.chat-message { position: relative; }
.chat-message--assistant { padding-right: 34px; }
.chat-message__copy {
  position: absolute; top: 4px; right: 4px;
  width: 22px; height: 22px;
  opacity: 0;
  transition: opacity .15s ease, background-color .15s ease, color .15s ease;
}
.chat-message__copy:hover { background: var(--surface-1); color: var(--text-primary); }
.chat-message--assistant:hover .chat-message__copy,
.chat-message__copy:focus-visible { opacity: 1; }
@media (hover: none) { .chat-message__copy { opacity: 1; } } /* touch: sin hover, siempre visible */

/* "Escribiendo..." animado -- unico @keyframes en loop de esta seccion,
   con su contraparte de prefers-reduced-motion. */
.typing-dots { display: inline-flex; gap: 4px; align-items: center; }
.typing-dots span {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-muted);
  animation: typing-bounce 1.2s ease-in-out infinite;
}
.typing-dots span:nth-child(2) { animation-delay: .2s; }
.typing-dots span:nth-child(3) { animation-delay: .4s; }
@keyframes typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: .5; }
  30% { transform: translateY(-4px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .typing-dots span { animation: none; opacity: .7; }
}

/* === Demo de voz: dot de estado y nivel de microfono === */

.voice-dot {
  width: 12px; height: 12px; border-radius: 50%; flex: none;
  background: var(--text-muted);
  box-shadow: 0 0 0 4px transparent;
  transition: background-color .25s ease, box-shadow .25s ease;
}
.voice-dot--connecting { background: var(--text-muted); }
.voice-dot--speaking   { background: var(--status-good); box-shadow: 0 0 0 4px color-mix(in srgb, var(--status-good) 25%, transparent); }
.voice-dot--listening  { background: var(--brand-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand-accent) 25%, transparent); }
.voice-dot--error      { background: var(--status-critical); box-shadow: 0 0 0 4px color-mix(in srgb, var(--status-critical) 25%, transparent); }

.mic-level { display: flex; align-items: flex-end; gap: 2px; height: 16px; flex: none; }
.mic-level span {
  width: 3px; height: 4px; border-radius: 2px;
  background: var(--baseline);
  transition: background-color .1s ease;
}
.mic-level span:nth-child(2) { height: 7px; }
.mic-level span:nth-child(3) { height: 10px; }
.mic-level span:nth-child(4) { height: 7px; }
.mic-level span:nth-child(5) { height: 4px; }
.mic-level span.active { background: var(--brand-accent); }

.voice-system-note {
  text-align: center;
  font-size: 11px;
  color: var(--text-muted);
  margin: 2px 0;
  letter-spacing: .02em;
}

/* === Utilidades === */

.muted { color: var(--text-muted); }

pre {
  background: var(--page);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 1rem;
  overflow-x: auto;
  white-space: pre-wrap;
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 12px;
  color: var(--text-secondary);
}

.tabular-nums {
  font-variant-numeric: tabular-nums;
}

/* === Documentacion interna (Admin y Manager) -- mismo patron visual que el
   centro de ayuda estatico de referencia (ayuda-valion/), que
   ya usa los mismos tokens de marca: landing con grilla de tarjetas,
   layout con sub-sidebar de arbol (grupos + estado activo) + articulo
   de contenido, buscador simple sin backend.

   Desde el 2026-07-31 documenta DOS plataformas (Control Center e
   Insights) con arboles de navegacion independientes. Comparten todas
   estas clases a proposito -- la unica diferencia visual entre una y
   otra es el contenido, no el estilo. Lo nuevo: .doc-hub-* (pantalla de
   eleccion de plataforma) y .doc-platform-switch (conmutador). === */

.doc-hero { text-align: center; padding: 32px 24px 40px; max-width: 640px; margin: 0 auto; }
.doc-hero h1 { font-size: 26px; font-weight: 800; margin: 0 0 10px; text-wrap: balance; }
.doc-hero p { font-size: 14.5px; color: var(--text-secondary); line-height: 1.6; margin: 0; }
.doc-hero__back { display: inline-block; text-decoration: none; color: var(--text-muted); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 14px; }
.doc-hero__back:hover { color: var(--text-secondary); }

/* Conmutador entre las 2 plataformas documentadas (Control Center /
   Insights). Solo en el hero de la landing -- dentro de un articulo
   estorbaba a la navegacion de la seccion, asi que ahi no se pinta. */
.doc-platform-switch {
  display: flex;
  gap: 3px;
  padding: 3px;
  background: var(--gridline);
  border-radius: var(--radius-pill);
}
.doc-hero .doc-platform-switch { width: fit-content; margin: 0 auto 18px; }
.doc-platform-switch__item {
  flex: 1;
  text-align: center;
  white-space: nowrap;
  text-decoration: none;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  padding: 6px 14px;
  border-radius: var(--radius-pill);
}
.doc-platform-switch__item:hover { color: var(--text-primary); }
.doc-platform-switch__item.active { background: var(--surface-1); color: var(--text-primary); font-weight: 700; box-shadow: 0 1px 2px rgba(15, 23, 42, .08); }

.doc-search { position: relative; width: 100%; max-width: 360px; margin: 20px auto 0; }
.doc-search input {
  width: 100%;
  font-family: inherit;
  font-size: 13px;
  padding: 9px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
}
.doc-search input:focus { outline: 2px solid var(--brand-primary); outline-offset: 1px; }
.doc-search__results {
  position: absolute;
  top: calc(100% + 6px);
  left: 0; right: 0;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(15, 23, 42, .12);
  overflow: hidden;
  z-index: 5;
  text-align: left;
}
.doc-search__results:empty { display: none; }
.doc-search__result { display: block; padding: 10px 14px; text-decoration: none; }
.doc-search__result:hover { background: var(--gridline); }
.doc-search__result .title { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.doc-search__result .group { font-size: 11px; color: var(--text-muted); }
.doc-search__empty { padding: 10px 14px; font-size: 12.5px; color: var(--text-muted); }

.doc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; max-width: 900px; margin: 0 auto; }
.doc-card { display: block; text-decoration: none; color: inherit; background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 20px; }
.doc-card:hover { border-color: var(--brand-primary); }
.doc-card__group { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); margin-bottom: 6px; }
.doc-card h2 { font-size: 15px; margin: 0 0 6px; }
.doc-card p { font-size: 13px; color: var(--text-secondary); line-height: 1.5; margin: 0; }

/* Landing de plataforma: la grilla ahora va agrupada (Modulos,
   Referencia, Backend, ...) en vez de una sola bolsa de tarjetas. */
.doc-landing-group { max-width: 900px; margin: 0 auto 28px; }
.doc-landing-group__label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); margin: 0 0 10px 2px; }

/* Hub (#/documentacion): eleccion de plataforma. Tarjetas mas grandes
   que las de seccion, para que se lea como una bifurcacion y no como
   dos articulos mas. */
.doc-hub-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; max-width: 760px; margin: 0 auto; }
.doc-hub-card {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 24px;
}
.doc-hub-card:hover { border-color: var(--brand-primary); }
.doc-hub-card__icon { display: inline-flex; width: 38px; height: 38px; align-items: center; justify-content: center; border-radius: var(--radius-md); background: var(--gridline); color: var(--brand-accent-hover); margin-bottom: 14px; }
.doc-hub-card__icon svg { width: 20px; height: 20px; }
.doc-hub-card__eyebrow { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); margin-bottom: 5px; }
.doc-hub-card h2 { font-size: 17px; margin: 0 0 8px; }
.doc-hub-card p { font-size: 13px; color: var(--text-secondary); line-height: 1.55; margin: 0 0 14px; }
.doc-hub-card__meta { font-size: 12px; font-weight: 700; color: var(--brand-accent-hover); }

/* justify-content:center porque .doc-article esta capado en 760px: sin el,
   al desaparecer el sidebar de 260px el articulo quedaba pegado a la
   izquierda con un hueco enorme a la derecha. */
.doc-layout { display: flex; align-items: flex-start; gap: 24px; justify-content: center; }

.doc-sidebar {
  flex: none;
  width: 220px;
  position: sticky;
  top: var(--cabecera-h); /* barra fina + topbar */
  align-self: flex-start;
  max-height: calc(100vh - var(--cabecera-h));
  overflow-y: auto;
  padding-bottom: 24px;
}
.doc-sidebar__back { display: block; text-decoration: none; color: var(--text-muted); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 12px; }
.doc-sidebar__back:hover { color: var(--text-secondary); }
.doc-sidebar__group-label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); padding: 0 10px; margin: 14px 0 4px; }
.doc-sidebar__group-label:first-of-type { margin-top: 0; }
.doc-tree-link {
  display: block;
  font-size: 13.5px;
  color: var(--text-secondary);
  text-decoration: none;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  border-left: 2px solid transparent;
}
.doc-tree-link:hover { color: var(--text-primary); background: var(--gridline); }
.doc-tree-link.active { color: var(--text-primary); font-weight: 700; background: var(--gridline); border-left-color: var(--brand-accent); }

.doc-article { flex: 1; min-width: 0; max-width: 760px; }
.doc-article__eyebrow { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--brand-accent-hover); margin-bottom: 8px; }
.doc-article h1 { font-size: 24px; font-weight: 800; margin: 0 0 8px; text-wrap: balance; }
.doc-article > p.lead { font-size: 14px; color: var(--text-secondary); line-height: 1.6; margin: 0 0 28px; }
.doc-article h2 { font-size: 16.5px; font-weight: 700; margin: 32px 0 10px; }
.doc-article h2:first-of-type { margin-top: 0; }
.doc-article h3 { font-size: 14px; font-weight: 700; margin: 18px 0 6px; }
.doc-article p { font-size: 13.5px; line-height: 1.7; color: var(--text-secondary); margin: 0 0 14px; }
.doc-article p strong { color: var(--text-primary); }
.doc-article ul, .doc-article ol { font-size: 13.5px; line-height: 1.7; color: var(--text-secondary); padding-left: 20px; margin: 0 0 14px; }
.doc-article li { margin-bottom: 4px; }
.doc-article li strong { color: var(--text-primary); }
.doc-article a { color: var(--brand-accent-hover); text-decoration: underline; text-underline-offset: 2px; }
.doc-article code { font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: 12.5px; background: var(--gridline); padding: 1px 5px; border-radius: 4px; }
/* Bloques de codigo (JSON del contrato, formulas de Python, diagramas
   ASCII). Scrollean solos en horizontal para no ensanchar el articulo. */
.doc-article pre {
  overflow-x: auto;
  background: var(--gridline);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin: 0 0 20px;
}
.doc-article pre code { display: block; background: none; padding: 0; font-size: 12px; line-height: 1.65; color: var(--text-primary); white-space: pre; }

.doc-note { display: flex; gap: 10px; background: var(--gridline); border-radius: var(--radius-md); padding: 14px 16px; margin: 0 0 20px; font-size: 13px; color: var(--text-secondary); line-height: 1.6; }
.doc-note strong { color: var(--text-primary); }
.doc-note--warning { background: color-mix(in srgb, var(--status-warning) 12%, var(--surface-1)); }

.doc-table-wrap { overflow-x: auto; margin: 0 0 20px; border: 1px solid var(--border); border-radius: var(--radius-md); }
.doc-table-wrap table { width: 100%; border-collapse: collapse; font-size: 13px; }
.doc-table-wrap th, .doc-table-wrap td { text-align: left; padding: 9px 12px; border-bottom: 1px solid var(--border); vertical-align: top; }
.doc-table-wrap th { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-muted); background: var(--gridline); white-space: nowrap; }
.doc-table-wrap td { color: var(--text-secondary); line-height: 1.5; }
.doc-table-wrap td code { font-family: ui-monospace, "Cascadia Code", Consolas, monospace; font-size: 12px; background: var(--gridline); padding: 1px 5px; border-radius: 4px; }
.doc-table-wrap tr:last-child td { border-bottom: none; }

@media (max-width: 760px) {
  .doc-layout { flex-direction: column; }
  .doc-sidebar { position: static; width: 100%; max-height: none; padding: 0 0 16px; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
}

/* === Asistente de IA (panel flotante) ===
   Implementa el patron de README-STYLE.md 7.9 "Panel flotante (chat /
   asistente / cualquier overlay persistente)": panel anclado abajo a la
   derecha, SIN scrim (no bloquea el resto de la pantalla), que alterna
   con su propio FAB en el mismo lugar. z-index 30, deliberadamente por
   debajo de .modal-overlay (100) -- si un formulario modal y el panel
   quedan abiertos a la vez, gana el formulario.

   El violeta --ai-accent es el color reservado por el sistema de diseno
   para contenido generado por un modelo; no se usa en ningun otro lado
   de la app. */

/* FAB del asistente -- implementa diseño-widget-chatid.md (el mismo boton
   que usa el chat del dashboard de Insights), con los valores literales
   de ese documento mapeados a los tokens de este proyecto. El mapeo es
   1:1: --ai-accent #7C3AED, --page #F8FAFC, --surface-1, --border,
   --text-primary, --radius-pill y --radius-lg ya valen exactamente lo
   que pide el documento. Usar la variable y no el hex es ademas lo unico
   que hace que el borde "recortado" del badge siga funcionando en modo
   oscuro, donde --page pasa a #0d0d0d. */

/* Wrapper fijo: agrupa la nube de invitacion + el circulo. El
   position:fixed vive ACA, no en el boton, para que los dos se muevan
   juntos y un unico listener cubra el click en cualquiera de los dos. */
.chat-fab-wrap {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 8;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  cursor: pointer;
}
.chat-fab-wrap[hidden] { display: none; }

/* "Nube" de invitacion (callout arriba del boton). */
.chat-fab-hint {
  max-width: 190px;
  max-height: 100px;
  padding: 10px 14px;
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  border: 1px solid var(--border);
  box-shadow: 0 8px 24px rgba(15, 23, 42, .12);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--text-primary);
  transition: opacity .3s ease, transform .3s ease,
              max-height .3s ease, padding .3s ease, border-width .3s ease;
}

/* Oculta: colapsa alto y padding ademas de opacity, para no dejar un
   hueco vacio arriba del boton cuando se retira. */
.chat-fab-hint--gone {
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-width: 0;
  overflow: hidden;
}

.chat-fab {
  position: relative; /* ancla del badge absoluto */
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ai-accent);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(15, 23, 42, .18);
}
.chat-fab svg { width: 22px; height: 22px; }
/* El hover se dispara desde el WRAPPER, no desde el boton: asi pasar el
   mouse por la nube tambien ilumina el circulo, que es una sola pieza. */
.chat-fab-wrap:hover .chat-fab { background: color-mix(in srgb, var(--ai-accent) 85%, black); }

/* Letrero "VALION IA": pill superpuesto en la esquina superior derecha
   del circulo, DESBORDANDO su borde. El borde de 2px va del color de
   fondo de la pagina (no del boton, ni transparente) para que se lea
   recortado encima, como una notificacion. */
.chat-fab__ai-badge {
  position: absolute;
  top: -10px;
  right: -10px;
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  background: var(--ai-accent);
  color: #fff;
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: .03em;
  white-space: nowrap;
  border: 2px solid var(--page);
  animation: chat-fab-badge-pulse 1.8s ease-in-out infinite;
}

/* Una sola animacion hace las dos cosas sobre el propio badge (no sobre
   un pseudo-elemento): escala 8% y, a la vez, un anillo de box-shadow
   que crece de 0 a 5px mientras baja de 45% de opacidad a 0. El
   navegador interpola los dos estados y sale el "ping" de notificacion. */
@keyframes chat-fab-badge-pulse {
  0%, 100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(124, 58, 237, .45);
  }
  50% {
    transform: scale(1.08);
    box-shadow: 0 0 0 5px rgba(124, 58, 237, 0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat-fab-hint { transition: none; }
  .chat-fab__ai-badge { animation: none; }
}

@media (max-width: 760px) {
  .chat-fab-wrap { right: 16px; bottom: 16px; }
}

.floating-panel {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 380px;
  height: min(640px, calc(100vh - 100px));
  z-index: 30;
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 64px rgba(15, 23, 42, .28);
  overflow: hidden;
}
.floating-panel[hidden] { display: none; }

.assistant-head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 12px 12px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--ai-bg);
}
.assistant-head__title { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; }
.assistant-head__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ai-accent); flex: none; }
.assistant-head__actions { display: flex; gap: 2px; }
.assistant-icon-btn {
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border: none; background: none; cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
}
.assistant-icon-btn:hover { background: var(--gridline); color: var(--text-primary); }
.assistant-icon-btn svg { width: 16px; height: 16px; }

.assistant-log {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain; /* que el scroll no se contagie a la pagina de atras */
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px;
}
/* Las burbujas reusan .chat-message del chat de demos a proposito --
   misma app, misma forma de mensaje. Solo cambia el ancho maximo: el
   panel es mucho mas angosto que la vista de demos. */
.assistant-log .chat-message { max-width: 88%; font-size: 13.5px; }

.assistant-welcome { color: var(--text-secondary); font-size: 13.5px; line-height: 1.6; }
.assistant-welcome p { margin: 0 0 12px; }
.assistant-suggestions { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.assistant-chip {
  font-family: inherit;
  font-size: 12.5px;
  text-align: left;
  padding: 7px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-secondary);
  cursor: pointer;
}
.assistant-chip:hover { border-color: var(--ai-accent); color: var(--text-primary); }

.assistant-error { flex: none; padding: 0 14px; font-size: 12.5px; color: var(--status-critical); }
.assistant-error:empty { display: none; }

.assistant-form { flex: none; padding: 10px 14px 0; border-top: 1px solid var(--border); }
.assistant-form textarea {
  width: 100%;
  resize: none;
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.45;
  padding: 9px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
}
.assistant-form textarea:focus { outline: 2px solid var(--ai-accent); outline-offset: 1px; }
.assistant-form__foot { display: flex; align-items: center; justify-content: space-between; margin-top: 8px; }
.assistant-counter { font-size: 11px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.assistant-counter.is-over { color: var(--status-critical); font-weight: 700; }

.assistant-disclaimer {
  flex: none;
  margin: 0;
  padding: 8px 14px 12px;
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--text-muted);
  text-align: center;
}

@media (max-width: 760px) {
  /* Casi pantalla completa. El inset de arriba lo calcula el JS midiendo
     la altura real de la topbar, que se envuelve en pantallas angostas. */
  .floating-panel {
    top: var(--floating-panel-top, 108px);
    right: 12px;
    bottom: max(12px, env(safe-area-inset-bottom));
    left: 12px;
    width: auto;
    height: auto;
  }
  /* El FAB tiene su propio corte a 760px junto al resto de sus reglas
     (.chat-fab-wrap), asi queda todo el widget en un solo lugar. */
}

/* ------------------------------------------------------------------ */
/* Pricing -- hoja de rentabilidad por propuesta                       */
/*                                                                     */
/* Es la unica grilla numerica editable de la app. No reusa            */
/* .doc-table-wrap porque esa esta pensada para tablas de LECTURA en   */
/* la documentacion (texto a la izquierda, vertical-align:top).        */
/*                                                                     */
/* Las dos reglas que la hacen usable con 12-36 columnas: encabezado   */
/* pegado arriba y primera columna congelada a la izquierda. Sin la    */
/* segunda, al desplazarse a "dic-27" ya no se sabe de que fila es el  */
/* numero que se esta mirando.                                         */
/* ------------------------------------------------------------------ */

.pricing-meta {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin: 16px 0;
}
.pricing-meta .field {
  margin-bottom: 0;
  min-width: 118px;
}

/* Linea vertical que separa los parametros de la hoja (que SI se guardan)
   de la calculadora (que es un borrador y no se guarda). */
.pricing-meta-sep {
  width: 1px;
  align-self: stretch;
  background: var(--border);
  margin: 0 4px;
}

.pricing-calc-field { min-width: 240px; flex: 1; }
.pricing-calc-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.pricing-calc-row input { flex: 1; min-width: 110px; }
.pricing-calc-out {
  flex: none;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--text-primary);
  white-space: nowrap;
}
/* Mientras la expresion esta a medio escribir el parser falla, y eso es
   normal: el aviso va en gris y discreto, no en rojo parpadeando. */
.pricing-calc-out.is-error {
  font-weight: 400;
  font-size: 12px;
  color: var(--text-muted);
}

.pricing-wrap {
  overflow: auto;
  max-height: 60vh;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

/* Compacta a proposito: la hoja tiene hasta 36 columnas de mes y el
   objetivo es que entren ~5 meses mas los dos totales sin scroll
   horizontal en una pantalla normal. Cada punto de font-size y cada pixel
   de padding se multiplica por columna. */
.pricing-table {
  width: max-content;
  min-width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 12.5px;
}

.pricing-table th,
.pricing-table td {
  padding: 3px 6px;
  border-bottom: 1px solid var(--gridline);
  white-space: nowrap;
  background: var(--surface-1);
}

.pricing-table thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--text-muted);
  background: var(--gridline);
}

/* La primera columna queda fija; en el encabezado tiene que ganarle en
   z-index a las demas celdas sticky o se superponen al desplazar. */
.pricing-sticky-col {
  position: sticky;
  left: 0;
  z-index: 1;
  min-width: 186px;
  border-right: 1px solid var(--border);
}
.pricing-table thead .pricing-sticky-col {
  z-index: 3;
}

.pricing-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.pricing-computed {
  color: var(--text-secondary);
  font-weight: 600;
}

.pricing-table input,
.pricing-table select {
  border: 1px solid transparent;
  background: transparent;
  border-radius: var(--radius-sm);
  padding: 2px 4px;
  font: inherit;
  color: inherit;
  width: 100%;
}
.pricing-table .pricing-num input {
  text-align: right;
  font-variant-numeric: tabular-nums;
  min-width: 58px;
}

/* Celda editable de un mes: el input mas la moneda pegada a la derecha.
   El flex-basis explicito es lo que fija el ancho de la columna: un
   <input> sin base declarada aporta su ancho por defecto (~20 caracteres)
   al calculo de max-content de la tabla, y cada mes quedaria al doble de
   lo necesario. */
.pricing-cell {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 3px;
}
.pricing-cell input { flex: 1 1 58px; }
.pricing-table input:hover,
.pricing-table select:hover {
  border-color: var(--border);
}
.pricing-table input:focus,
.pricing-table select:focus {
  outline: none;
  border-color: var(--brand-accent);
  background: var(--surface-1);
}

.pricing-line-head {
  display: flex;
  gap: 4px;
  align-items: center;
}
.pricing-line-head input { flex: 1; }
.pricing-line-head select { width: auto; flex: none; }

.pricing-total td {
  font-weight: 700;
  background: var(--page);
}
.pricing-total .pricing-sticky-col {
  background: var(--page);
}
/* Franja blanca entre el bloque de ingresos y el de costos. Va sin borde:
   la idea es un respiro, no otra linea mas en una tabla que ya tiene
   muchas. */
.pricing-table .pricing-gap td {
  height: 9px;
  padding: 0;
  background: var(--surface-1);
  border-bottom: none;
}

.pricing-total.is-revenue td { background: var(--section-a-bg); }
.pricing-total.is-cost    td { background: color-mix(in srgb, #d03b3b 7%, var(--surface-1)); }
.pricing-total.is-balance td { background: var(--section-c-bg); }

/* Fila del portafolio de Pricing, en 3 columnas: quien es el proyecto,
   el balance y el margen. El minmax(0,...) de la primera es lo que deja
   que una descripcion larga se recorte en vez de empujar las otras dos
   fuera de la tarjeta. */
.pricing-portfolio-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 16px;
  align-items: center;
}

.pricing-balance {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 190px;
}
.pricing-balance-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  /* Fondo muy tenue solo para distinguir las tres lineas de un vistazo.
     El numero va en el color de texto normal, no en verde ni rojo: sobre
     blanco esos colores se leen mal y aca lo que importa es la cifra. */
  background: var(--surface-1);
}
.pricing-balance-row.is-revenue { background: var(--section-a-bg); }
.pricing-balance-row.is-cost    { background: color-mix(in srgb, #d03b3b 7%, var(--surface-1)); }
.pricing-balance-row.is-net     { background: var(--section-c-bg); }
.pricing-balance-label {
  font-size: 11px;
  color: var(--text-secondary);
}
.pricing-balance-value {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-primary);
  white-space: nowrap;
}

@media (max-width: 760px) {
  .pricing-portfolio-row {
    grid-template-columns: 1fr;
    gap: 8px;
  }
  .pricing-balance { min-width: 0; }
}

/* Bitacora de cambios: discreta y cerrada por defecto. Va al pie de todo,
   despues del resultado de operacion. */
.pricing-audit { margin-top: 24px; }
.pricing-audit-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 12px;
  cursor: pointer;
}
.pricing-audit-toggle:hover { color: var(--text-primary); }
.pricing-audit-chevron { font-size: 10px; }
.pricing-audit-more { text-decoration: underline; }
.pricing-audit-body { margin-top: 8px; }
/* Texto plano de verdad: monoespaciado, con los saltos de linea que trae
   el contenido y scroll propio si la bitacora es larga. No es editable --
   la API ni siquiera expone como modificarla. */
.pricing-audit-log {
  margin: 0;
  padding: 12px 14px;
  max-height: 320px;
  overflow: auto;
  background: var(--page);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-secondary);
  white-space: pre-wrap;
  word-break: break-word;
}

.pricing-result {
  margin-top: 20px;
  max-width: 580px;
}
.pricing-table--result {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.pricing-table--result td { white-space: normal; }

/* Casilla "=" de la fila: mismo valor todos los meses. Va pegada al
   selector de moneda porque las dos definen "como se cargan los numeros
   de esta linea", no que numero es. */
.pricing-repeat {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex: none;
  cursor: pointer;
  color: var(--text-muted);
  font-weight: 700;
  user-select: none;
}
.pricing-repeat input { width: auto; flex: none; margin: 0; cursor: pointer; }


.pricing-cur {
  font-size: 8.5px;
  font-weight: 700;
  color: var(--text-muted);
  letter-spacing: .02em;
  flex: none;
}

.pricing-note {
  color: var(--text-muted);
  font-size: 11px;
}
.pricing-table--result thead th {
  position: static;
}

/* Informe por destinatario de una campaña (modal). El modal normal esta
   capado en 560px: sirve para un formulario, no para una tabla de cuatro
   columnas con fechas. */
/* 80% de la pantalla. Los 900 px fijos se quedaban cortos con el informe
   por contacto: cinco columnas con nowrap y correos largos desbordaban el
   modal y aparecia scroll horizontal. En pantallas chicas se toma todo el
   ancho, que es lo unico que tiene sentido ahi. */
.modal--wide { max-width: 80vw; }
@media (max-width: 900px) {
  .modal--wide { max-width: 100%; }
}

.report-wrap {
  max-height: 55vh;
  overflow: auto;
  border: 1px solid var(--gridline);
  border-radius: var(--radius-md);
}

.report-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}
.report-table th,
.report-table td {
  padding: 8px 12px;
  text-align: left;
  border-bottom: 1px solid var(--gridline);
  background: var(--surface-1);
  white-space: nowrap;
}
/* La del contacto es la unica que puede crecer sin limite -- nombre largo
   mas correo largo -- y es la que empujaba la tabla fuera del modal. Se le
   deja partir; las de fechas y estados siguen en una linea, que es donde
   el nowrap si ayuda a leer. */
.report-table td:first-child { white-space: normal; }
.report-table td:first-child > div { overflow-wrap: anywhere; }
/* Encabezado pegado: la lista puede tener cientos de filas y al
   desplazarse hay que seguir sabiendo que columna es cual. */
.report-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--text-muted);
  background: var(--gridline);
}
.report-table td:first-child { white-space: normal; min-width: 220px; }
.report-table tr:last-child td { border-bottom: none; }

/* === Paginador de tablas ===
   Barra al pie de toda lista de datos (README-STYLE.md §7.6). La pinta
   js/pagination.js; ninguna vista escribe este marcado a mano.

   Tres bloques: cuantas filas se ven, la navegacion, y el tamano de
   pagina. El del medio va centrado respecto de la BARRA y no del espacio
   sobrante, por eso los laterales son flex:1 -- si no, la navegacion se
   corre segun cuanto ocupe el texto de la izquierda, que cambia con el
   numero de filas. */

.pager {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
  padding: 12px 4px 2px;
  border-top: 1px solid var(--gridline);
  font-size: 13px;
  color: var(--text-secondary);
  flex-wrap: wrap;
}

.pager__count {
  flex: 1;
  min-width: 140px;
  margin: 0;
}

.pager__count strong,
.pager__page strong {
  color: var(--text-primary);
  font-weight: 600;
}

.pager__nav {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

.pager__page {
  white-space: nowrap;
}

.pager__btn {
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-secondary);
  border-radius: var(--radius-sm);
  padding: 5px 12px;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
}

.pager__btn:hover:not(:disabled) {
  background: var(--gridline);
  color: var(--text-primary);
}

/* Deshabilitado y NO oculto: que se vea que existe un "anterior" y que
   ahora mismo no lleva a ningun lado ubica mejor que un boton que
   aparece y desaparece segun la pagina. */
.pager__btn:disabled {
  opacity: 0.45;
  cursor: default;
}

.pager__size {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  min-width: 140px;
}

.pager__size label {
  white-space: nowrap;
}

.pager__size select {
  width: auto;
  min-width: 68px;
  padding: 5px 8px;
  font-size: 12px;
}

/* En pantallas angostas los tres bloques se apilan y se centran; con
   flex:1 en los laterales quedarian estirados y desalineados entre si. */
@media (max-width: 640px) {
  .pager {
    justify-content: center;
    text-align: center;
  }
  .pager__count,
  .pager__size {
    flex: none;
    justify-content: center;
  }
}

/* === Recursos (Marketing) ============================================== */

.rec-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.rec-count {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: var(--page);
  border: 1px solid var(--border);
}

.rec-note {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin: 8px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-secondary);
  max-width: 78ch;
}
.rec-note .dot { margin-top: 5px; }

.rec-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px;
  margin-top: 16px;
}

.rec-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-1);
}

/* LOS DOS FONDOS DE MINIATURA SON FIJOS Y NO SIGUEN EL TEMA, que es la
   unica excepcion deliberada a la regla de "todo color por variable".
   La miniatura no es cromo de la interfaz: ensena el archivo en el fondo
   para el que fue hecho. Un logotipo azul marino sobre la superficie
   oscura del tema desaparece, y quien lo mira concluiria que el archivo
   esta roto. */
.rec-thumb {
  height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 14px;
  border-bottom: 1px solid var(--border);
}
.rec-thumb img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.rec-thumb--claro  { background: #FFFFFF; }
.rec-thumb--oscuro { background: #252F3E; }

/* La portada de un documento. Mas alta que el resto de miniaturas: una
   pagina necesita alto para leerse como pagina, y ademas es la primera
   fila de la vista -- es lo que hace que Recursos se vea como un
   estante y no como una lista. Se recorta por arriba a proposito: ahi
   estan la cabecera de marca y el titular. */
.rec-thumb--pagina {
  height: 168px;
  padding: 0;
  background: #FFFFFF;
  align-items: flex-start;
  overflow: hidden;
}
.rec-thumb--pagina img {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: cover;
  object-position: top center;
  display: block;
}

.rec-thumb--doc {
  background: var(--page);
  color: var(--text-muted);
}
.rec-thumb--doc span {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .12em;
  padding: 7px 12px;
  border: 1px dashed var(--baseline);
  border-radius: var(--radius-sm);
}

.rec-body {
  padding: 11px 12px 0;
  flex: 1;
}

.rec-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.35;
}

.rec-detail {
  font-size: 12px;
  line-height: 1.45;
  margin-top: 3px;
}

.rec-meta {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 6px;
}

.rec-acciones {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px;
  margin: 10px 12px 12px;
}
.rec-acciones .btn { justify-content: center; }

@media (max-width: 560px) {
  /* Una sola columna, y la miniatura mas baja: en el telefono lo que
     interesa es llegar al boton, no admirar el logotipo. */
  .rec-grid { grid-template-columns: 1fr; }
  .rec-thumb { height: 78px; }
}

/* === Visor de recursos (Marketing) ===================================== */

/* No reusa .modal a proposito: aquel esta pensado para un formulario --
   560px de ancho maximo y el overlay con scroll -- y aqui hace falta lo
   contrario, una ventana grande y fija con el documento dentro. */
.visor-overlay {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, .62);
  display: flex; align-items: center; justify-content: center;
  z-index: 110;
}
.visor {
  width: 90vw; height: 90vh;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 70px rgba(15, 23, 42, .4);
  display: flex; flex-direction: column;
  overflow: hidden;
}

.visor__cab {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  flex: none;
}
.visor__t {
  font-size: 14px; font-weight: 600; color: var(--text-primary);
  line-height: 1.3;
}
.visor__meta {
  font-size: 12px; color: var(--text-muted);
  font-variant-numeric: tabular-nums; margin-top: 2px;
}
.visor__cab > div:first-child { flex: 1; min-width: 0; }

.visor__cuerpo {
  flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
/* El PDF va sin relleno: su propio visor ya trae margenes. */
.visor__cuerpo--pdf { padding: 0; }
.visor__cuerpo iframe { width: 100%; height: 100%; border: 0; display: block; }
.visor__cuerpo img { max-width: 100%; max-height: 100%; object-fit: contain; }

/* Mismo criterio que las miniaturas: el fondo lo decide el archivo, no el
   tema. Un logotipo blanco sobre superficie clara no se ve. */
.visor__cuerpo--claro  { background: #FFFFFF; }
.visor__cuerpo--oscuro { background: #252F3E; }

.visor__nada { text-align: center; max-width: 420px; }
.visor__nada strong { display: block; color: var(--text-primary); font-size: 15px; }
.visor__nada span { display: block; color: var(--text-secondary); font-size: 13px;
  line-height: 1.5; margin-top: 8px; }

@media (max-width: 700px) {
  .visor { width: 100vw; height: 100vh; border-radius: 0; border: 0; }
}

/* ---------------------------------------------------------------- pasos
   Armar una campaña son cuatro cosas distintas -- a quién le escribo, qué
   imágenes van, qué dice el correo, y revisarlo antes de mandarlo -- y
   hasta ahora las cuatro se veían como una sola lista de campos pegados.
   Una persona de marketing sin perfil técnico abría la campaña y no tenía
   forma de saber por dónde empezar ni si le faltaba algo (pasó en la
   primera sesión de uso, 20-08-2026).

   Cada paso es un bloque cerrado con su número, su icono, su título y una
   frase que dice en cristiano para qué sirve. El número se pone verde con
   un chequeo cuando el paso está resuelto, así que el estado de la
   campaña se lee de un vistazo sin leer una sola etiqueta. */

.paso {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  margin-bottom: 16px;
  overflow: hidden;
}

.paso__cab {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  background: var(--gridline);
  border-bottom: 1px solid var(--border);
}

/* El numero. Cuando el paso esta resuelto se reemplaza por un chequeo
   verde -- el mismo verde de --status-good que el resto de la app usa
   para "esto ya esta". */
.paso__num {
  flex: none;
  width: 26px; height: 26px;
  border-radius: var(--radius-pill);
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  background: var(--surface-1);
  border: 1px solid var(--baseline);
  color: var(--text-secondary);
}
.paso--ok .paso__num {
  background: var(--status-good);
  border-color: var(--status-good);
  color: #fff;
}
.paso--ok .paso__num span { display: none; }
.paso--ok .paso__num::after {
  content: '';
  width: 9px; height: 5px;
  border-left: 2px solid #fff; border-bottom: 2px solid #fff;
  transform: rotate(-45deg) translate(1px, -1px);
}

.paso__icono { flex: none; width: 20px; height: 20px; color: var(--text-secondary); margin-top: 2px; }
.paso__texto { flex: 1; min-width: 0; }
.paso__tit {
  margin: 0; font-size: 14px; font-weight: 700; line-height: 1.3;
  color: var(--text-primary); text-transform: none; letter-spacing: 0;
}
.paso__sub { margin: 3px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--text-secondary); }
.paso__sub strong { color: var(--text-primary); font-weight: 600; }

/* El estado del paso, a la derecha: "38 contactos", "sin generar". Es lo
   que responde "que me falta" sin abrir nada. */
.paso__estado {
  flex: none; align-self: center;
  font-size: 11.5px; font-weight: 600;
  padding: 3px 9px; border-radius: var(--radius-pill);
  background: var(--surface-1); border: 1px solid var(--border);
  color: var(--text-muted); white-space: nowrap;
}
.paso__estado--ok { color: var(--status-good); border-color: color-mix(in srgb, var(--status-good) 35%, transparent); }

.paso__cuerpo { padding: 16px; }
.paso__cuerpo > .field:last-child { margin-bottom: 0; }

/* El paso de la IA lleva el violeta que el sistema ya reserva para todo
   lo que es inteligencia artificial (el asistente usa el mismo). */
.paso--ia .paso__cab {
  background: var(--ai-bg);
  border-bottom-color: color-mix(in srgb, var(--ai-accent) 22%, transparent);
}
.paso--ia .paso__icono { color: var(--ai-accent); }
.paso--ia:not(.paso--ok) .paso__num { border-color: color-mix(in srgb, var(--ai-accent) 45%, transparent); color: var(--ai-accent); }

/* Opcional: el unico paso que se puede saltar sin consecuencias. */
.paso__opcional {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); background: var(--gridline);
  border-radius: var(--radius-sm); padding: 2px 6px; margin-left: 6px;
  vertical-align: 2px;
}

/* La fila de controles de cada paso: en pantalla angosta se apila sola en
   vez de encogerse hasta que no se pueda escribir. */
.paso__fila { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.paso__fila > input { flex: 1 1 200px; min-width: 0; }

@media (max-width: 640px) {
  .paso__cab { flex-wrap: wrap; }
  .paso__estado { align-self: flex-start; order: 3; margin-left: 38px; }
  .paso__fila > .btn { width: 100%; }
}

/* Un boton que se ve como un enlace: se usa dentro de los textos de ayuda
   ("Descarga la plantilla"). Es <button> y no <a> porque no navega a
   ningun lado -- dispara una descarga -- y un <a href="#"> ahi seria
   mentirle al lector y al lector de pantalla. */
.enlace-boton {
  background: none; border: 0; padding: 0;
  font: inherit; color: var(--brand-accent); font-weight: 600;
  text-decoration: underline; cursor: pointer;
}
.enlace-boton:hover { color: var(--text-primary); }

/* -------------------------------------------------------- campo de archivo
   El <input type="file"> nativo pinta un boton gris del sistema operativo
   con un "Ningun archivo seleccionado" al lado, y no hay CSS que lo
   arregle: no se puede dar estilo al boton interno. Al lado de los campos
   del resto de la app parecia de otra epoca, y en el paso de las imagenes
   ademas exprimia al campo de "que es" hasta cortarle el placeholder.

   La solucion de siempre: el input se esconde (visible para el teclado y
   el lector de pantalla, pero fuera de la vista) y el <label> se disfraza
   de zona de carga. El label ya dispara el selector al hacer clic sin una
   linea de JavaScript -- lo unico que aporta el JS es el nombre del
   archivo elegido y el arrastrar y soltar. */

.archivo { display: block; }

/* Escondido pero NO display:none: asi sigue recibiendo foco con el
   tabulador y el lector de pantalla lo anuncia. */
.archivo__input {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.archivo__caja {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 16px;
  border: 1.5px dashed var(--baseline);
  border-radius: var(--radius-md);
  background: var(--surface-1);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.archivo__caja:hover,
.archivo.is-encima .archivo__caja,
.archivo__input:focus-visible + .archivo__caja {
  border-color: var(--brand-accent);
  background: color-mix(in srgb, var(--brand-accent) 6%, var(--surface-1));
}
.archivo__input:focus-visible + .archivo__caja { outline: 2px solid var(--text-primary); outline-offset: 1px; }

.archivo__icono { flex: none; width: 20px; height: 20px; color: var(--text-muted); }
.archivo__caja:hover .archivo__icono,
.archivo.is-encima .archivo__icono { color: var(--brand-accent); }

.archivo__texto { font-size: 13px; line-height: 1.4; color: var(--text-secondary); }
.archivo__texto strong { color: var(--text-primary); font-weight: 600; }

.archivo__nombre { margin: 7px 0 0; font-size: 12px; color: var(--text-muted); }
/* Verde y en negrita cuando ya hay archivo: es la confirmacion de que el
   clic hizo algo, que en el control nativo se perdia entre gris y gris. */
.archivo__nombre.tiene { color: var(--status-good); font-weight: 600; }

/* Ayuda debajo de la etiqueta de un campo, antes del control. El .field de
   la casa no tenia sitio para esto y cada pantalla lo resolvia con un <p>
   suelto y estilos en linea. */
.field__ayuda { margin: -2px 0 2px; font-size: 12px; line-height: 1.5; color: var(--text-muted); }
.field__ayuda strong { color: var(--text-secondary); font-weight: 600; }

/* ------------------------------------------------- pedirle cambios a la IA
   Era un <input> de una linea metido en la misma fila que su boton: el
   placeholder no cabia entero, y para pedir un cambio de tres frases habia
   que escribirlas a ciegas en una ranura de 40 px.

   Ahora es un compositor con la misma forma que el del asistente -- misma
   tipografia, mismo radio, mismo foco en violeta --, que es el lenguaje que
   la app ya usa para todo lo que habla con un modelo. */

.pedido textarea {
  width: 100%;
  resize: vertical;
  min-height: 70px;
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.5;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface-1);
  color: var(--text-primary);
}
.pedido textarea::placeholder { color: var(--text-muted); }
.pedido textarea:focus { outline: 2px solid var(--ai-accent); outline-offset: 1px; }

.pedido__pie {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-top: 10px; flex-wrap: wrap;
}
.pedido__ayuda { font-size: 12px; line-height: 1.45; color: var(--text-muted); flex: 1 1 220px; }

/* Ejemplos de un clic. El problema de una caja de texto vacia no es como
   se ve, es que no se sabe que escribir en ella -- y menos si uno no ha
   trabajado nunca con un modelo. Tres ejemplos que se rellenan solos
   resuelven eso mejor que cualquier instruccion. */
.pedido__ejemplos { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 8px; }
.pedido__ej {
  font-family: inherit; font-size: 12px; text-align: left;
  padding: 5px 11px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface-1);
  color: var(--text-secondary); cursor: pointer;
}
.pedido__ej:hover { border-color: var(--ai-accent); color: var(--text-primary); }

/* ------------------------------------------------- campanas ya enviadas
   La fila cerrada de una campana enviada mostraba el nombre, una etiqueta
   y el numero de contactos, y nada mas: para saber como le fue habia que
   abrirla. Ahora se parte en tres columnas -- quien y cuando / como le fue
   / a cuantos -- y el dato que de verdad se busca queda a la vista. */

.enviada {
  display: grid;
  /* La primera se lleva mas que la del medio: la del medio tiene ancho
     natural (el bloque de cifras no crece) y la primera carga el nombre
     con su etiqueta de estado, que al apretarse se parte en dos lineas.
     Se ajusto al sumar el boton de informe a la tercera columna. */
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1.1fr) auto;
  gap: 18px;
  align-items: center;
}

.enviada__quien { min-width: 0; }
.enviada__nombre {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  font-size: 15px; font-weight: 700; color: var(--text-primary);
}
.enviada__fecha { margin: 5px 0 0; font-size: 12px; color: var(--text-muted); }

/* La columna del medio. La efectividad va grande porque es la respuesta a
   "como le fue", y debajo van los cuatro numeros de los que sale, para
   que nunca sea una cifra que aparece de la nada. */
.enviada__medio { display: flex; align-items: center; gap: 14px; min-width: 0; }

.efectividad { flex: none; text-align: center; }
.efectividad__n {
  font-size: 27px; font-weight: 800; line-height: 1;
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.efectividad__t {
  display: block; margin-top: 3px;
  font-size: 10px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-muted);
}
.efectividad--alta .efectividad__n { color: var(--status-good); }
/* El naranja de --status-serious da 2,7:1 sobre blanco y el minimo para
   un numero grande es 3:1, asi que en claro se oscurece. En oscuro el
   token ya contrasta de sobra y se deja como esta. */
.efectividad--media .efectividad__n { color: color-mix(in srgb, var(--status-serious) 78%, #000); }
:root[data-tema="oscuro"] .efectividad--media .efectividad__n { color: var(--status-serious); }
.efectividad--baja .efectividad__n { color: var(--status-critical); }

/* Los cuatro numeros en dos por dos: entra en el ancho de una fila sin
   empujar la tercera columna fuera de la tarjeta. */
.enviada__cifras {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 14px; min-width: 0;
  font-size: 12px; color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.enviada__cifras b { color: var(--text-primary); font-weight: 700; }

.enviada__cuantos { display: flex; align-items: center; gap: 10px; flex: none; }
.enviada__contactos { text-align: right; }
.enviada__contactos strong {
  display: block; font-size: 17px; font-weight: 800; color: var(--text-primary);
  line-height: 1; font-variant-numeric: tabular-nums;
}
.enviada__contactos span { font-size: 11px; color: var(--text-muted); }

@media (max-width: 780px) {
  .enviada { grid-template-columns: 1fr auto; gap: 12px; }
  .enviada__medio { grid-column: 1 / -1; }
}

/* --------------------------------------------- detalle de una enviada
   Era una pila de parrafos sueltos ("Asunto: ...", "Enviada el ...", una
   linea con tres cifras separadas por puntos). Se lee mal y no hay forma
   de encontrar un dato de un vistazo. Ahora: recuadros para los numeros y
   una ficha de dos columnas para lo demas. */

.resumen {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
  gap: 10px;
  margin: 0 0 16px;
}
.metrica {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  background: var(--surface-1);
}
.metrica__n {
  font-size: 21px; font-weight: 800; line-height: 1.1;
  color: var(--text-primary); letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.metrica__t {
  display: block; margin-top: 5px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-muted);
}
.metrica__pie { display: block; margin-top: 2px; font-size: 11.5px; color: var(--text-secondary); }
.metrica--buena .metrica__n { color: var(--status-good); }
.metrica--mala .metrica__n { color: var(--status-critical); }
.metrica--destacada { background: var(--gridline); border-color: var(--baseline); }

.datos-campana {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 7px 16px; margin: 0 0 16px; font-size: 13px;
}
.datos-campana dt { color: var(--text-muted); white-space: nowrap; }
.datos-campana dd { margin: 0; color: var(--text-primary); min-width: 0; overflow-wrap: anywhere; }

.bloque-titulo {
  margin: 0 0 10px; font-size: 11px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
}

@media (max-width: 560px) {
  .datos-campana { grid-template-columns: 1fr; gap: 2px; }
  .datos-campana dt { margin-top: 8px; }
}

/* Cabecera de un bloque del detalle: el titulo a la izquierda y sus
   acciones a la derecha (el "Actualizar metricas" de las enviadas). */
.bloque-cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin: 0 0 10px;
}
.bloque-cab__acciones { display: flex; align-items: center; gap: 10px; }

/* La celda del medio de una fila de tres columnas, para la accion
   principal ("Lanzar campana"). Centrada en su columna, no en la fila. */
.fila-accion { display: flex; justify-content: center; }
@media (max-width: 780px) {
  .fila-accion { grid-column: 1 / -1; justify-content: flex-start; }
  .fila-accion .btn { width: 100%; }
}

/* Una campana aprobada trae su <p class="form-error"> vacio para que
   sendCampaign pueda escribir ahi si algo falla, pero el min-height de
   18px dejaba un hueco visible bajo el boton. Vacio no ocupa. */
.enviada + .form-error:empty { display: none; }

/* La fila de una campana aprobada le da mas aire al nombre: el del medio
   solo lleva un boton y no necesita 1,5fr, y con el nombre apretado el
   badge de estado se caia a una segunda linea. */
.enviada--aprobada { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto; }

/* --------------------------------------------------- lanzar una campana
   El boton queda CENTRADO EN LA FILA, no en su columna: por eso las dos
   columnas de los lados son 1fr iguales y la del medio es auto. Con la
   izquierda mas ancha que la derecha (que era lo que habia) el boton se
   veia corrido hacia la derecha aunque estuviera centrado en su celda. */
.enviada--aprobada { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
.enviada--aprobada .enviada__cuantos { justify-content: flex-end; }

/* Naranja de marca con tinta oscura encima: 6,86:1. Blanco sobre este
   naranja da 2,14:1 y no pasaria -- es la misma regla que sigue el
   generador de correos. */
.btn--lanzar {
  background: var(--brand-accent);
  color: #1F2937;
  border-color: var(--brand-accent);
  font-weight: 800;
  font-size: 14px;
  letter-spacing: -0.01em;
  /* Un 10% mas chico que el original (176,7 x 45 px) sin tocar la letra:
     el ancho lo pone el texto, que no cambia, asi que el recorte sale
     todo del relleno. Medido en el navegador, no calculado a ojo. */
  padding: 10px 19px;
  white-space: nowrap;
  animation: latido-lanzar 2.6s ease-out infinite;
}
.btn--lanzar:hover {
  background: var(--brand-accent-hover);
  border-color: var(--brand-accent-hover);
  transform: translateY(-1px);
}

/* El guino: un halo que sale del boton y se desvanece. Va en box-shadow y
   no en un pseudo-elemento con escala, para no mover el layout ni obligar
   al navegador a recalcularlo en cada cuadro. */
@keyframes latido-lanzar {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand-accent) 55%, transparent); }
  70%  { box-shadow: 0 0 0 14px color-mix(in srgb, var(--brand-accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand-accent) 0%, transparent); }
}

/* Quien pidio menos animacion no recibe el latido. El boton sigue siendo
   naranja y grande: lo llamativo no depende del movimiento. */
@media (prefers-reduced-motion: reduce) {
  .btn--lanzar { animation: none; }
}

/* ------------------------------------------------------- informe con IA
   El boton vive bajo las cifras de la fila cerrada. Discreto a proposito:
   compite con la efectividad, que es el dato que se busca primero. */
.btn-informe {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 8px; padding: 5px 11px;
  font: inherit; font-size: 11.5px; font-weight: 700;
  color: var(--ai-accent);
  background: var(--ai-bg);
  border: 1px solid color-mix(in srgb, var(--ai-accent) 28%, transparent);
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.btn-informe:hover { border-color: var(--ai-accent); }
.btn-informe svg { width: 14px; height: 14px; flex: none; }

/* Las tres tarjetas. En una sola columna y no en tres: se leen de arriba
   abajo por orden de importancia, que es como las ordena el modelo, y un
   texto de dos frases en una columna de un tercio queda ilegible. */
.insights { display: grid; gap: 10px; }
.insight {
  border: 1px solid var(--border);
  border-left: 4px solid var(--baseline);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  background: var(--surface-1);
}
.insight__nivel {
  display: inline-block; margin-bottom: 5px;
  font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
}
.insight__titulo {
  margin: 0 0 4px; font-size: 14px; font-weight: 700; line-height: 1.3;
  color: var(--text-primary); text-transform: none; letter-spacing: 0;
}
.insight__texto { margin: 0; font-size: 13px; line-height: 1.55; color: var(--text-secondary); }

/* El color va en el filete y en la etiqueta, no en el fondo entero: tres
   tarjetas de color pleno una encima de otra cansan y ninguna resalta. */
.insight--critico { border-left-color: var(--status-critical); }
.insight--critico .insight__nivel { color: var(--status-critical); }
.insight--atencion { border-left-color: var(--status-warning); }
.insight--atencion .insight__nivel { color: color-mix(in srgb, var(--status-warning) 72%, #000); }
.insight--bueno { border-left-color: var(--status-good); }
.insight--bueno .insight__nivel { color: var(--status-good); }

:root[data-tema="oscuro"] .insight--atencion .insight__nivel { color: var(--status-warning); }

.informe-analisis p { margin: 0 0 10px; font-size: 13.5px; line-height: 1.65; color: var(--text-secondary); }
.informe-analisis p:last-child { margin-bottom: 0; }

/* ------------------------------------------- separador de grupo de la lista
   El rotulo "Enviadas" era un texto gris de 12 px que se perdia entre dos
   tarjetas. Ahora es una division de verdad: linea de corte, titulo con
   peso y el numero de campanas al lado. Se tiene que ver desde lejos que
   ahi cambia la naturaleza de lo que sigue. */
.grupo-sep {
  display: flex; align-items: center; gap: 10px;
  margin: 32px 0 14px; padding-top: 20px;
  border-top: 1px solid var(--baseline);
}
.grupo-sep__t {
  margin: 0; font-size: 15px; font-weight: 800; letter-spacing: -0.01em;
  color: var(--text-primary); text-transform: none;
}
.grupo-sep__n {
  font-size: 11.5px; font-weight: 700;
  color: var(--text-muted); background: var(--gridline);
  border-radius: var(--radius-pill); padding: 2px 9px;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------- filtros de la lista
   Buscar por nombre, desde y hasta, en una sola linea. El de nombre se
   lleva el espacio sobrante porque es el que mas texto recibe; los de
   fecha tienen ancho propio, que es lo que ocupa un selector de fecha del
   navegador y no crece con nada. */
.filtros {
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap;
  margin-top: 16px;
}
.filtros .field { margin-bottom: 0; }
.filtros__nombre { flex: 1 1 260px; min-width: 0; }
.filtros input[type="date"] { min-width: 160px; }
.filtros__limpiar { margin-bottom: 1px; }

@media (max-width: 620px) {
  .filtros { gap: 10px; }
  .filtros .field { flex: 1 1 100%; }
  .filtros input[type="date"] { width: 100%; }
}

/* La tercera columna de una campana enviada: el contador y, debajo, el
   acceso al informe por contacto. Antes ese boton solo existia dentro del
   detalle, asi que habia que desplegar la campana para llegar a el. */
.enviada__pila { display: flex; flex-direction: column; align-items: flex-end; gap: 7px; }
/* Un 10% mas chico que el .btn--sm de la casa, letra incluida, para que
   pese lo mismo que el "Informe con IA" que tiene al lado: los dos son
   accesos secundarios y ninguno debe ganarle al numero de contactos.
   Los valores salen de medir en el navegador, no de estimar. */
.enviada__informe {
  white-space: nowrap;
  font-size: 10.8px;
  padding: 5px 9px;
}

/* ------------------------------------------- resumen del dashboard de horas
   Dos tarjetas en linea entre los filtros y la lista. Se apilan en
   pantalla angosta: dos columnas de barras con nombres largos a menos de
   860 px dejan de leerse. */
.resumen-horas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
  /* El mismo margen que trae una .card suelta. A las tarjetas de adentro
     se les quita el suyo para que el hueco entre columnas lo gobierne el
     gap, y sin este margen el bloque quedaba pegado a la lista de abajo. */
  margin-bottom: 16px;
}
.resumen-horas:empty { display: none; margin-bottom: 0; }
.resumen-horas .card { margin-bottom: 0; }

/* Lista de barras horizontales. La forma sale de que el dato es una
   magnitud por categoria con nombres largos: en barras verticales las
   etiquetas se rotan y dejan de leerse. */
.barras { display: flex; flex-direction: column; gap: 12px; }

.barra__cab {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 5px;
}
.barra__nombre {
  font-size: 13px; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* El valor SIEMPRE escrito al lado de la barra: asi el color nunca es lo
   unico que informa, y quien no distinga tonos lee el numero igual. */
.barra__valor { font-size: 12px; font-weight: 700; color: var(--text-secondary); flex: none; }

.barra__pista {
  height: 8px; border-radius: 4px;
  background: var(--gridline);
  overflow: hidden;
}
.barra__marca {
  height: 100%; border-radius: 4px;
  background: var(--series-1);
  transition: width .35s ease;
}
/* Por encima del 100% de utilizacion la barra llega al tope y cambia de
   tono: el numero de al lado sigue mostrando el valor real. */
.barra--alerta .barra__marca { background: var(--status-serious); }
.barra--alerta .barra__valor { color: var(--status-serious); }

.barra:hover .barra__nombre { color: var(--text-primary); }


/* ---------------------------------------------- salud de SES
   Una tira compacta arriba de Campanas. La barra de cada tasa NO es un
   adorno: es la escala. Va de cero al umbral en el que AWS suspende, con
   una marca en el umbral en el que abre revision, asi que "llena" quiere
   decir exactamente eso y el numero llega con su contexto. */
.ses-salud { padding: 14px 18px; margin-bottom: 16px; }

.ses-salud__cabecera {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 12px;
}
.ses-estado {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text-primary);
}
.ses-estado__punto {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--status-good);
  /* El halo hace que se vea de reojo sin tener que leer. */
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-good) 22%, transparent);
}
.ses-estado--medio .ses-estado__punto {
  background: var(--status-warning);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-warning) 22%, transparent);
}
.ses-estado--mal .ses-estado__punto {
  background: var(--status-critical);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-critical) 22%, transparent);
}
.ses-salud__detalle { font-size: 12.5px; color: var(--text-secondary); }
.ses-salud__cuota {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-muted);
}

.ses-salud__metricas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px 28px;
  margin-top: 12px;
}
@media (max-width: 560px) {
  .ses-salud__cuota { margin-left: 0; }
}

.ses-metrica {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 2px 10px;
}
.ses-metrica__nombre {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.ses-metrica__valor {
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--status-good);
}
.ses-metrica__valor--medio { color: var(--status-warning); }
.ses-metrica__valor--mal { color: var(--status-critical); }
.ses-metrica__valor--vacio { font-size: 13px; font-weight: 600; color: var(--text-muted); }

.ses-barra {
  grid-column: 1 / -1;
  position: relative;
  height: 7px;
  margin-top: 5px;
  border-radius: 999px;
  background: var(--gridline);
  overflow: hidden;
}
.ses-barra__relleno {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: 999px;
  background: var(--status-good);
  /* Un minimo visible: con 0,00 % la barra vacia parece rota, y lo que
     hay que entender es "hay medida y esta abajo del todo". */
  min-width: 3px;
  transition: width .3s ease;
}
.ses-barra__relleno--medio { background: var(--status-warning); }
.ses-barra__relleno--mal { background: var(--status-critical); }
.ses-barra__umbral {
  position: absolute;
  top: -1px;
  bottom: -1px;
  width: 2px;
  background: var(--text-muted);
  opacity: .55;
}
.ses-metrica__nota {
  grid-column: 1 / -1;
  margin: 6px 0 0;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-muted);
}
.ses-metrica__fecha { white-space: nowrap; }
/* Un dato de hace una semana con la barra en verde se lee como "estamos
   bien ahora", y no es lo que dice. */
.ses-metrica__fecha--vieja { color: var(--status-warning); font-weight: 600; white-space: normal; }

/* ---------------------------------------------- generador de piezas
   El taller es dos columnas: los controles a la izquierda y el lienzo a
   la derecha, pegajoso, para que la pieza siga a la vista mientras se
   escribe. Por debajo de 1000 px se apila: con el lienzo al lado no
   quedan ni 300 px para el formulario. */
.pieza-taller {
  display: grid;
  grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
  gap: 28px;
  align-items: start;
}
@media (max-width: 1000px) {
  .pieza-taller { grid-template-columns: 1fr; }
}
.pieza-grupo { margin-bottom: 22px; }
.pieza-grupo__titulo {
  display: block;
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.pieza-opciones { display: flex; flex-wrap: wrap; gap: 6px; }
.pieza-opcion {
  padding: 7px 13px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-1);
  font: inherit;
  font-size: 12.5px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease;
}
.pieza-opcion:hover { color: var(--text-primary); border-color: var(--text-muted); }
.pieza-opcion.is-activa {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: var(--brand-on-primary);
  font-weight: 600;
}
.pieza-ayuda {
  margin: 8px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}
.pieza-contador { float: right; font-weight: 400; color: var(--text-muted); }

/* ---------------------------------------------- el panel de IA
   Era un textarea del navegador con un boton al lado: tres renglones de
   alto para escribir un encargo y ningun sitio donde poner la foto. Ahora
   es un panel propio -- el unico bloque de la columna que se separa del
   resto -- con la caja grande y el boton debajo, a todo el ancho, que es
   donde cae la vista despues de escribir. */
.pieza-ia {
  margin-bottom: 22px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 14px;
  /* El mismo gesto que hace la propia pieza: un degradado muy suave en
     vez de un plano. Aqui no compite con nada porque el contenido va
     dentro de cajas con fondo propio. */
  background:
    radial-gradient(120% 90% at 100% 0%,
      color-mix(in srgb, var(--brand-primary) 7%, transparent) 0%,
      transparent 60%),
    var(--surface-1);
}
.pieza-ia__cabecera {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: 12px;
}
.pieza-ia__chispa {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--brand-primary) 12%, transparent);
  color: var(--brand-primary);
}
.pieza-ia__chispa svg { width: 17px; height: 17px; }
.pieza-ia__titulo {
  display: block;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text-primary);
}
.pieza-ia__sub {
  display: block;
  margin-top: 1px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
}
.pieza-ia__caja {
  display: block;
  width: 100%;
  min-height: 128px;
  padding: 12px 13px;
  border: 1px solid var(--border);
  border-radius: 11px;
  background: var(--page);
  font: inherit;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text-primary);
  resize: vertical;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.pieza-ia__caja::placeholder { color: var(--text-muted); }
.pieza-ia__caja:focus {
  outline: none;
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-primary) 16%, transparent);
}

/* La zona de la fotografia. Es un <label> con el input escondido dentro:
   asi el area de clic es toda la caja y no hay que replicar el foco con
   JavaScript -- el teclado la alcanza igual. */
.pieza-ia__foto {
  display: flex;
  gap: 9px;
  align-items: center;
  margin-top: 10px;
  padding: 11px 13px;
  border: 1px dashed var(--border);
  border-radius: 11px;
  font-size: 12.5px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.pieza-ia__foto:hover {
  border-color: var(--brand-primary);
  color: var(--text-primary);
  background: color-mix(in srgb, var(--brand-primary) 5%, transparent);
}
.pieza-ia__foto svg { flex: none; width: 17px; height: 17px; }
.pieza-ia__foto:focus-within {
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-primary) 16%, transparent);
}
.pieza-ia__boton {
  display: block;
  width: 100%;
  margin-top: 12px;
}
.pieza-ia .enlace-boton { margin-top: 8px; }
.pieza-ia .pieza-ayuda { margin-top: 10px; }

/* El lienzo se muestra escalado por CSS; el canvas por dentro siempre
   mide lo que va a medir el archivo exportado. */
.pieza-lienzo { position: sticky; top: calc(var(--cabecera-h) + 20px); }
.pieza-marco {
  padding: 18px;
  background: var(--page);
  border: 1px solid var(--border);
  border-radius: 14px;
  text-align: center;
}
.pieza-marco canvas {
  max-width: 100%;
  max-height: 62vh;
  height: auto;
  border-radius: 6px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .10);
}
.pieza-acciones {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 14px;
}
.pieza-medida { font-size: 12px; color: var(--text-muted); }

.pieza-auditoria { margin-top: 18px; }
.pieza-checks { list-style: none; margin: 0; padding: 0; }
.pieza-check {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  padding: 5px 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.pieza-check__marca {
  flex: none;
  width: 17px;
  height: 17px;
  margin-top: 1px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--status-good) 16%, transparent);
  color: var(--status-good);
  font-size: 11px;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
}
.pieza-check--mal .pieza-check__marca {
  background: color-mix(in srgb, var(--status-critical) 16%, transparent);
  color: var(--status-critical);
}
.pieza-avisos {
  margin: 10px 0 0;
  padding: 10px 14px;
  border-left: 2px solid var(--status-warning);
  list-style: none;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-secondary);
}
.pieza-avisos li + li { margin-top: 5px; }


/* ------------------------------------------------------------------ */
/* ORGANIGRAMA                                                        */
/*                                                                    */
/* Cajas y lineas, no una lista con sangria. Un organigrama se lee de  */
/* un vistazo por su FORMA: quien esta al lado de quien y cuantos      */
/* cuelgan de cada uno. Con sangrias hay que ir contando espacios para */
/* saber de quien depende cada persona, que es justo lo que un         */
/* organigrama existe para no tener que hacer.                         */
/*                                                                    */
/* Las lineas son bordes de ::before y ::after, no un SVG ni medidas   */
/* calculadas en JavaScript: asi aguantan cualquier nombre por largo   */
/* que sea y cualquier numero de niveles, sin nada que recalcular al   */
/* cambiar el tamano de la ventana.                                    */
/*                                                                    */
/* El contenedor se desplaza en horizontal a proposito. Un organigrama */
/* ancho es ancho; apretarlo para que quepa dejaria las cajas          */
/* ilegibles, que es peor que arrastrar.                               */
.org { overflow-x: auto; padding: 4px 2px 12px; }
.org ul {
  position: relative;
  display: flex;
  justify-content: center;
  list-style: none;
  margin: 0;
  padding: 22px 0 0;
}
.org > ul { padding-top: 0; }
.org li { position: relative; padding: 22px 6px 0; text-align: center; }

/* La linea que hermana a los hijos: cada uno pinta su mitad, y las dos
   mitades juntas forman el travesano. */
.org li::before,
.org li::after {
  content: '';
  position: absolute;
  top: 0;
  right: 50%;
  width: 50%;
  height: 22px;
  border-top: 2px solid var(--border);
}
.org li::after { right: auto; left: 50%; border-left: 2px solid var(--border); }

/* Hijo unico: no hay a quien hermanar, solo baja la linea. */
.org li:only-child::before,
.org li:only-child::after { display: none; }
.org li:only-child { padding-top: 22px; }

/* Los extremos cierran el travesano en vez de seguirlo hacia afuera. */
.org li:first-child::before,
.org li:last-child::after { border-top: 0; }
.org li:last-child::before { border-right: 2px solid var(--border); border-radius: 0 6px 0 0; }
.org li:first-child::after { border-radius: 6px 0 0 0; }

/* La bajada desde el padre hasta la fila de hijos. */
.org ul ul::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: 0;
  height: 22px;
  border-left: 2px solid var(--border);
}

.org__caja {
  display: inline-block;
  min-width: 148px;
  max-width: 210px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--page);
  text-align: center;
}
/* La cabeza del arbol no es una persona: se distingue sin necesidad de
   leerla, que es lo que hace que un organigrama se entienda de lejos. */
.org__caja--organo { border-style: dashed; background: transparent; }
.org__nombre { font-size: 13.5px; font-weight: 650; line-height: 1.3; }
.org__cargo { font-size: 11.5px; color: var(--text-muted); margin-top: 3px; line-height: 1.35; }
.org__equipo { font-size: 11px; color: var(--text-muted); margin-top: 5px; }
.org__falta { font-size: 11.5px; color: var(--status-warning); margin-top: 3px; }
