:root {
  --ul-turquoise: #0eefda;
  --ul-navy: #1a0072;
  --ul-navy-deep: #100046;
  /* Tamano de letra del chat (FR-096): default UNICO del CSS; el body lo sobreescribe con el valor
     efectivo de la cascada usuario->cliente->global (context processor). Los consumidores usan
     var(--ul-chat-font-size) SIN fallback propio (un solo default que mantener). */
  --ul-chat-font-size: 17px;
  /* Texto legible sobre las superficies navy. Por defecto blanco; el branding por cliente (FR-092)
     lo recalcula segun el brillo de su color (oscuro si el cliente eligio un navy claro) para que el
     texto no desaparezca. Hay dos: `--ul-on-navy` para las superficies que usan --ul-navy (el color
     del cliente) y `--ul-on-navy-deep` para las que usan el tono profundo --ul-navy-deep (page-shell,
     hero). Guardia de contraste: ver accounts/branding._texto_sobre_color. */
  --ul-on-navy: #fff;
  --ul-on-navy-deep: #fff;
  --ul-white: #ffffff;
  --ul-turquoise-dark: #24b8b3;
  --ul-sky: #00a4d1;
  /* Sky ACCESIBLE para texto pequeno sobre superficies claras (eyebrows): mismo tono (H 193,
     S 100%), oscurecido hasta cumplir WCAG AA 4.5:1 en las tres superficies claras del sistema
     (blanco 5.35:1, bg-soft 4.95:1, bg-tint 4.90:1; el sky claro da 2.9:1 y FALLA). El sky claro
     queda para fondos oscuros y acentos no textuales. Gemelo de `skyDark` en tokens.json. */
  --ul-sky-dark: #007494;
  --ul-yellow: #f4a945;
  --ul-slate: #313a4d;
  --ul-bg-soft: #f4f6fb;
  --ul-bg-tint: #e9f8f8;
  --ul-border: #e3e7ef;
  --ul-border-strong: #c9d1dc;
  --ul-muted: #6b7385;
  --color-error: #e05555;
  --font-display: "Oswald", "Arial Narrow", sans-serif;
  --font-body: "Roboto", "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-pill: 999px;
  --shadow-sm: 0 1px 2px rgba(16, 0, 70, 0.06), 0 1px 1px rgba(16, 0, 70, 0.04);
  --shadow-md: 0 4px 12px rgba(16, 0, 70, 0.08), 0 2px 4px rgba(16, 0, 70, 0.04);
  --shadow-lg: 0 16px 40px rgba(16, 0, 70, 0.14), 0 4px 12px rgba(16, 0, 70, 0.08);
  --gradient-navy-radial: radial-gradient(120% 80% at 20% 0%, #2b14a0 0%, #1a0072 45%, #100046 100%);
  --gradient-turquoise: linear-gradient(135deg, #0eefda 0%, #24b8b3 100%);
  /* Velos (scrim) que oscurecen el fondo de marca para legibilidad. Como variables para que el
     branding por cliente (FR-092 Fase 3) los re-tina con su color; el default es el navy corporativo. */
  --ul-scrim-page: linear-gradient(rgba(16, 0, 70, 0.3), rgba(16, 0, 70, 0.52));
  --ul-scrim-auth: linear-gradient(rgba(16, 0, 70, 0.24), rgba(16, 0, 70, 0.5));
}

* {
  box-sizing: border-box;
}

html {
  min-height: 100%;
}

body {
  margin: 0;
  /* Columna flex global: el encabezado toma su alto natural y el .page-shell llena el resto
     SIEMPRE, sin restar un alto de header "a ojo". Asi el login, el chat y las pantallas
     autenticadas comparten el mismo mecanismo elastico y no reaparece la franja gris del body. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: #ece9f1;
  color: var(--ul-slate);
  font-family: var(--font-body);
}

a {
  color: var(--ul-turquoise-dark);
  font-weight: 600;
}

.app-header {
  align-items: center;
  background: var(--ul-white);
  border-bottom: 1px solid var(--ul-border);
  display: flex;
  flex: 0 0 auto;
  gap: 20px;
  min-height: 82px;
  /* Padding vertical ajustado (8px) para que el logo (.brand-logo, abajo) pueda crecer y casi
     tocar los bordes superior/inferior SIN que el encabezado gane altura: la altura del header es
     max(logo, header-content) + 2*8 + 1px de borde. El logo es el elemento mas alto y la fila de
     menu/cuenta queda centrada, asi conserva su respiro. Fuente unica: aqui, no en base.html. */
  padding: 8px 30px;
  position: relative;
  z-index: 5;
}

.brand {
  align-items: center;
  display: flex;
  flex: 0 0 auto;
  text-decoration: none;
}

.brand-logo {
  display: block;
  /* Logo mas grande con margen minimo a los bordes del header, manteniendo su altura (ver el
     comentario de padding en .app-header). En movil se reduce en el @media de abajo. */
  height: 72px;
  width: auto;
}

.brand-divider {
  background: var(--ul-border);
  flex: 0 0 auto;
  height: 44px;
  width: 1px;
}

.brand-title {
  display: grid;
  gap: 3px;
  min-width: 250px;
  /* El titulo de la app pega su TEXTO al extremo DERECHO del encabezado (decision del responsable
     2026-07-02): la caja ya va a la derecha (align-items de .header-title-row), pero con el
     min-width el texto quedaba flotando con hueco a su derecha. */
  text-align: right;
}

.brand-title strong {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 25px;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1.05;
  text-transform: uppercase;
}

.main-nav {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  margin-left: auto;
}

.main-nav a {
  border-bottom: 2.5px solid transparent;
  color: var(--ul-muted);
  font-size: 16px;
  font-weight: 600;
  padding: 6px 2px;
  text-decoration: none;
}

.main-nav a:hover {
  border-bottom-color: var(--ul-turquoise);
  color: var(--ul-navy);
}

.page-shell {
  margin: 0 auto;
  max-width: 1120px;
  padding: 28px;
}

body:not(.auth-page) .page-shell {
  background-color: var(--ul-navy-deep);
  background-image:
    var(--ul-scrim-page),
    var(--ul-configured-background, var(--gradient-navy-radial));
  background-position: center;
  background-size: cover;
  isolation: isolate;
  margin: 0;
  max-width: none;
  /* Llena el alto restante por flex (no por un offset de header fijo): crece para tapar todo el
     hueco bajo el encabezado y, con contenido alto, crece mas (la pagina hace scroll). */
  flex: 1 0 auto;
  min-height: 0;
  overflow: hidden;
  padding: 18px 28px 22px;
  position: relative;
}

body:not(.auth-page) .page-shell::before {
  background-image:
    linear-gradient(30deg, rgba(14, 239, 218, 0.055) 12%, transparent 12.5%, transparent 87%, rgba(14, 239, 218, 0.055) 87.5%, rgba(14, 239, 218, 0.055)),
    linear-gradient(150deg, rgba(14, 239, 218, 0.055) 12%, transparent 12.5%, transparent 87%, rgba(14, 239, 218, 0.055) 87.5%, rgba(14, 239, 218, 0.055)),
    radial-gradient(circle at 18% 28%, rgba(14, 239, 218, 0.75) 0 3px, rgba(14, 239, 218, 0.16) 4px 14px, transparent 15px),
    radial-gradient(circle at 52% 16%, rgba(14, 239, 218, 0.65) 0 3px, rgba(14, 239, 218, 0.13) 4px 13px, transparent 14px),
    radial-gradient(circle at 84% 35%, rgba(14, 239, 218, 0.7) 0 3px, rgba(14, 239, 218, 0.14) 4px 13px, transparent 14px),
    linear-gradient(145deg, transparent 35%, rgba(14, 239, 218, 0.13) 35.2%, transparent 35.5%),
    linear-gradient(22deg, transparent 58%, rgba(14, 239, 218, 0.12) 58.2%, transparent 58.5%);
  background-position: 0 0, 52px 30px, 0 0, 0 0, 0 0, 0 0, 0 0;
  background-size: 104px 60px, 104px 60px, auto, auto, auto, auto, auto;
  content: "";
  inset: 0;
  opacity: 0.8;
  position: absolute;
  z-index: -1;
}

body:not(.auth-page) .page-shell > h1,
body:not(.auth-page) .page-shell > h2,
body:not(.auth-page) .page-shell > form,
body:not(.auth-page) .page-shell > table,
body:not(.auth-page) .page-shell > .messages {
  margin-left: auto;
  margin-right: auto;
  max-width: 1080px;
  position: relative;
  z-index: 1;
}

body:not(.auth-page) .page-shell > h1 {
  color: var(--ul-on-navy-deep);
  font-size: 30px;
  margin-bottom: 16px;
  text-align: center;
  text-transform: uppercase;
}

body:not(.auth-page) .page-shell > h2 {
  color: var(--ul-turquoise);
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 0;
  margin-top: 28px;
  text-transform: uppercase;
}

body:not(.auth-page) .page-shell > form {
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 26px 30px;
}

body:not(.auth-page) .page-shell > table {
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

h1 {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1.08;
  margin: 0 0 18px;
}

h2 {
  color: var(--ul-navy);
  font-size: 22px;
  margin: 28px 0 14px;
}

form {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  margin-bottom: 22px;
  padding: 20px;
}

form p {
  display: grid;
  gap: 7px;
  margin: 0 0 14px;
}

label,
.field-label {
  color: var(--ul-navy);
  display: block;
  font-weight: 700;
}

input,
select,
textarea {
  background: var(--ul-white);
  border: 1.5px solid var(--ul-border-strong);
  border-radius: var(--radius-sm);
  color: var(--ul-slate);
  font: inherit;
  min-height: 40px;
  padding: 9px 11px;
  width: min(100%, 720px);
}

/* Los checkboxes/radios NO son campos de texto: el ancho/alto/relleno de arriba los rompe
   (en flex toman el 100% del ancho). Se devuelven a su tamano nativo. */
input[type="checkbox"],
input[type="radio"] {
  accent-color: var(--ul-turquoise);
  background: none;
  border: 0;
  flex: 0 0 auto;
  min-height: 0;
  padding: 0;
  width: auto;
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--ul-turquoise);
  box-shadow: 0 0 0 3px rgba(14, 239, 218, 0.15);
  outline: none;
}

textarea {
  min-height: 140px;
}

/* Textarea compacto (opt-in): respeta su atributo `rows` en lugar del alto base de 140px —pensado
   para un campo largo—. Para descripciones/comentarios cortos donde 140px desperdicia alto vertical
   y obliga a hacer scroll. Reutilizable: cualquier <textarea rows="2|3"> que deba ser bajo lo adopta.
   Hermano de los modificadores .is-dense / .compact (densidad definida en la clase central, no inline). */
textarea.textarea-compact {
  min-height: 0;
}

button,
input[type="submit"] {
  background: var(--ul-navy);
  border: 0;
  border-radius: var(--radius-md);
  color: var(--ul-turquoise);
  cursor: pointer;
  font-weight: 700;
  min-height: 42px;
  padding: 9px 18px;
}

table {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-collapse: collapse;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  width: 100%;
}

th,
td {
  border-bottom: 1px solid var(--ul-border);
  padding: 11px 13px;
  text-align: left;
  vertical-align: top;
}

th {
  background: var(--ul-bg-tint);
  color: var(--ul-navy);
  font-size: 14px;
}

.messages {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-left: 4px solid var(--ul-turquoise);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  margin-bottom: 18px;
  padding: 11px 14px;
  transition: opacity 400ms ease;
}

/* Auto-descarte de los mensajes flash: solo se anima la opacidad (no transform) para no pisar
   el translateX(-50%) que centra el cuadro fijo. El JS retira el nodo al terminar. */
.messages.is-dismissing {
  opacity: 0;
  pointer-events: none;
}

.messages p {
  margin: 0;
}

body:not(.auth-page) .page-shell > .messages {
  left: 50%;
  margin: 0;
  max-width: min(760px, calc(100vw - 48px));
  padding: 9px 14px;
  position: fixed;
  top: 116px;
  transform: translateX(-50%);
  width: 100%;
  z-index: 30;
}

.auth-page {
  display: flex;
  flex-direction: column;
}

.auth-page .page-shell {
  display: flex;
  flex-direction: column;
  flex: 1;
  margin: 0;
  max-width: none;
  padding: 0;
}

.auth-page .messages {
  left: 50%;
  margin: 0;
  max-width: min(460px, calc(100vw - 32px));
  position: fixed;
  top: 104px;
  transform: translateX(-50%);
  width: 100%;
  z-index: 20;
}

.auth-scene {
  align-items: center;
  background-color: var(--ul-navy-deep);
  background-image:
    var(--ul-scrim-auth),
    var(--ul-configured-background, var(--gradient-navy-radial));
  background-position: center;
  background-size: cover;
  display: flex;
  /* flex:1 0 auto -> el recuadro LLENA el alto del .page-shell (sin franja gris del body al
     fondo) pero nunca se encoge por debajo de su contenido: las pantallas con tarjeta alta
     (lista de entrevistas) crecen y hacen scroll en vez de recortarse. Sustituye al viejo
     min-height: calc(100vh - 124px), cuyo offset fijo no cuadraba con la altura real del header. */
  flex: 1 0 auto;
  justify-content: center;
  min-height: calc(100vh - 124px);
  overflow: hidden;
  padding: 42px 18px;
  position: relative;
}

.auth-scene::before {
  background-image:
    linear-gradient(30deg, rgba(14, 239, 218, 0.06) 12%, transparent 12.5%, transparent 87%, rgba(14, 239, 218, 0.06) 87.5%, rgba(14, 239, 218, 0.06)),
    linear-gradient(150deg, rgba(14, 239, 218, 0.06) 12%, transparent 12.5%, transparent 87%, rgba(14, 239, 218, 0.06) 87.5%, rgba(14, 239, 218, 0.06)),
    linear-gradient(30deg, rgba(14, 239, 218, 0.06) 12%, transparent 12.5%, transparent 87%, rgba(14, 239, 218, 0.06) 87.5%, rgba(14, 239, 218, 0.06)),
    linear-gradient(150deg, rgba(14, 239, 218, 0.06) 12%, transparent 12.5%, transparent 87%, rgba(14, 239, 218, 0.06) 87.5%, rgba(14, 239, 218, 0.06));
  background-position: 0 0, 0 0, 52px 30px, 52px 30px;
  background-size: 104px 60px;
  content: "";
  inset: 0;
  opacity: 0.7;
  position: absolute;
}

.auth-scene::after {
  background: radial-gradient(60% 60% at 50% 48%, rgba(16, 0, 70, 0) 0%, rgba(16, 0, 70, 0.5) 100%);
  content: "";
  inset: 0;
  position: absolute;
}

.neural-bg {
  inset: 0;
  position: absolute;
  z-index: 1;
}

.neural-bg::before,
.neural-bg::after {
  background:
    radial-gradient(circle at 12% 22%, rgba(14, 239, 218, 0.9) 0 3px, rgba(14, 239, 218, 0.18) 4px 15px, transparent 16px),
    radial-gradient(circle at 28% 16%, rgba(14, 239, 218, 0.85) 0 3px, rgba(14, 239, 218, 0.16) 4px 13px, transparent 14px),
    radial-gradient(circle at 40% 30%, rgba(14, 239, 218, 0.75) 0 3px, rgba(14, 239, 218, 0.14) 4px 12px, transparent 13px),
    radial-gradient(circle at 55% 20%, rgba(14, 239, 218, 0.85) 0 3px, rgba(14, 239, 218, 0.15) 4px 13px, transparent 14px),
    radial-gradient(circle at 68% 38%, rgba(14, 239, 218, 0.7) 0 3px, rgba(14, 239, 218, 0.13) 4px 12px, transparent 13px),
    radial-gradient(circle at 84% 24%, rgba(14, 239, 218, 0.8) 0 3px, rgba(14, 239, 218, 0.15) 4px 12px, transparent 13px),
    linear-gradient(22deg, transparent 11%, rgba(14, 239, 218, 0.15) 11.2%, transparent 11.5%),
    linear-gradient(145deg, transparent 34%, rgba(14, 239, 218, 0.13) 34.2%, transparent 34.5%),
    linear-gradient(164deg, transparent 52%, rgba(14, 239, 218, 0.12) 52.2%, transparent 52.5%);
  content: "";
  inset: 0;
  opacity: 0.75;
  position: absolute;
}

.neural-bg::after {
  filter: blur(0.5px);
  opacity: 0.45;
  transform: scaleX(-1) translateY(80px);
}

/* Fondo FIEL (FR-092): cuando hay una IMAGEN de fondo real —la PROPIA del cliente O la GLOBAL de
   CONFIGURACION (dominio base / System Manager)— (senal `fondo_fiel` -> `body.has-faithful-bg`), la
   imagen se ve TAL CUAL. Se QUITA el motivo geometrico corporativo (page-shell / auth-scene /
   neural-bg) y los velos: el scrim de page y de login (variables a `none`) y la vineta de la escena,
   para no alterar la imagen con la marca de UL. El caso de solo-color (gradiente re-tenido, sin imagen)
   NO activa esta clase: conserva su velo. Las superficies de contenido (paneles `.ul-*`, tarjeta de
   login `.auth-card`) son OPACAS, asi que su texto no depende del fondo; a los titulos sueltos sobre el
   page-shell se les da una sombra de texto para conservar legibilidad SIN velar la imagen. Mecanismo
   GENERICO, en un solo lugar. */
body.has-faithful-bg .page-shell::before,
body.has-faithful-bg .auth-scene::before,
body.has-faithful-bg .auth-scene::after,
body.has-faithful-bg .neural-bg {
  display: none;
}

body.has-faithful-bg {
  --ul-scrim-page: none;
  --ul-scrim-auth: none;
}

body.has-faithful-bg:not(.auth-page) .page-shell > h1,
body.has-faithful-bg:not(.auth-page) .page-shell > h2 {
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6);
}

.auth-card {
  background: var(--ul-white);
  border: 0;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  margin: 0;
  max-width: calc(100vw - 32px);
  padding: 38px 40px 34px;
  position: relative;
  text-align: center;
  width: 460px;
  z-index: 3;
}

.auth-card .eyebrow {
  color: var(--ul-sky-dark);
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  margin: 0 0 14px;
  text-transform: uppercase;
}

.auth-card h1 {
  color: var(--ul-navy);
  font-size: 28px;
  margin: 0 0 8px;
  text-transform: uppercase;
}

.auth-copy {
  color: var(--ul-muted);
  font-size: 14px;
  line-height: 1.5;
  margin: 0 0 26px;
}

.auth-card .field-label {
  color: var(--ul-slate);
  font-size: 12px;
  margin-bottom: 7px;
  text-align: left;
}

.input-shell {
  align-items: center;
  background: var(--ul-bg-soft);
  border: 1.5px solid var(--ul-turquoise);
  border-radius: var(--radius-sm);
  box-shadow: 0 0 0 3px rgba(14, 239, 218, 0.12);
  display: flex;
  gap: 10px;
  margin-bottom: 18px;
  min-height: 50px;
  padding: 0 16px;
}

.input-shell svg {
  fill: none;
  flex: 0 0 auto;
  height: 18px;
  stroke: var(--ul-muted);
  stroke-width: 1.8;
  width: 18px;
}

.input-shell input {
  background: transparent;
  border: 0;
  box-sizing: border-box;
  box-shadow: none;
  min-height: 48px;
  padding: 0;
  width: 100%;
}

.input-shell input:focus {
  box-shadow: none;
}

.primary-action {
  align-items: center;
  background: var(--ul-navy);
  border: 0;
  border-radius: var(--radius-md);
  color: var(--ul-turquoise);
  display: inline-flex;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  gap: 10px;
  justify-content: center;
  letter-spacing: 0.04em;
  min-height: 50px;
  padding: 0 28px;
  text-transform: uppercase;
  width: auto;
}

.primary-action svg {
  fill: none;
  height: 18px;
  stroke: currentColor;
  stroke-width: 2.2;
  width: 18px;
}

.secondary-action {
  align-items: center;
  background: var(--ul-white);
  border: 1.5px solid var(--ul-border-strong);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  display: inline-flex;
  flex: 0 0 auto;
  font-weight: 700;
  gap: 10px;
  justify-content: center;
  min-height: 48px;
  padding: 0 28px;
  text-decoration: none;
  width: auto;
}

.auth-actions {
  display: flex;
  gap: 12px;
}

.auth-actions .primary-action {
  flex: 1.4;
}

.auth-actions .secondary-action {
  flex: 1;
}

.auth-card > .primary-action {
  width: 100%;
}

@media (max-width: 760px) {
  .app-header {
    align-items: flex-start;
    gap: 12px;
    padding: 14px 18px;
  }

  .brand-logo {
    height: 42px;
  }

  .brand-divider {
    display: none;
  }

  .brand-title {
    /* TD-S36: con el bloque de cuenta ya DENTRO del viewport (abajo), el titulo se alinea al
       extremo derecho tambien en movil (en escritorio lo hace el text-align de la clase base). */
    margin-left: auto;
    min-width: 0;
  }

  .brand-title strong {
    font-size: 21px;
  }

  /* TD-S36 (decision del responsable): en movil el bloque de cuenta no cabia (desbordaba ~26px
     el viewport de 390px). Compactacion SOLO en pantallas de administracion (el chat tiene su
     propio encabezado, ya auditado sin desbordes): queda el circulo de INICIALES (el enlace a
     Mi perfil vive en todo el grupo .user-identity) y "Cerrar sesion" queda como ICONO (el
     glifo del boton; su aria-label conserva el nombre accesible). Principio UI #3. */
  body:not(.chat-page) .user-name {
    display: none;
  }

  body:not(.chat-page) .logout-button .logout-text {
    display: none;
  }

  body:not(.chat-page) .logout-button {
    padding: 0 12px;
  }

  .main-nav {
    flex-basis: 100%;
    gap: 14px;
    margin-left: 0;
  }

  .page-shell {
    padding: 20px 14px;
  }

  .auth-card {
    padding: 30px 24px 28px;
  }
}

/* Admin header and LLM registration screen */
/* Encabezado de una sola fila: el menu (.header-nav-row) va a la izquierda y centrado
   verticalmente; el bloque de cuenta (.header-title-row) va a la derecha, con la marca arriba y
   Terminos/usuario/Salir debajo. Asi el menu queda a media altura (no pegado abajo) y, al estar
   todo en flujo flex, no se solapan aunque el menu sea largo. */
.header-content {
  align-items: center;
  display: flex;
  flex: 1;
  flex-direction: row;
  gap: 24px;
  justify-content: space-between;
  min-width: 0;
}

.header-title-row {
  align-items: flex-end;
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  gap: 4px;
  order: 2;
}

.header-account {
  align-items: center;
  display: flex;
  gap: 16px;
}

.header-nav-row {
  align-items: center;
  display: flex;
  gap: 24px;
  min-width: 0;
  order: 1;
}

.brand-title strong span {
  color: var(--ul-turquoise-dark);
  font-weight: 500;
}

.main-nav {
  gap: 26px;
  margin-left: 0;
}

.main-nav a.is-active {
  border-bottom-color: var(--ul-turquoise);
  color: var(--ul-navy);
  font-weight: 700;
}

.session-actions {
  align-items: center;
  display: flex;
  flex: 0 0 auto;
  gap: 9px;
}

/* Identidad del usuario (avatar + nombre) como un grupo: en pantallas normales fluye en linea con el
   resto de la cuenta; el chat (override mas abajo) la baja a su propio renglon. */
.user-identity {
  align-items: center;
  display: inline-flex;
  flex: 0 0 auto;
  gap: 9px;
}

/* Enlace a Terminos: la insignia compacta "TyC" es la representacion UNICA en TODAS las ventanas
   (decision del responsable 2026-07-02; principio UI #3). El nombre completo va en el
   aria-label/title del enlace. Sin padding propio: el ritmo lo da el gap del grupo de cuenta
   (un padding lateral crearia franjas clicables invisibles junto al circulo). La vista de
   entrevista solo cambia su ANCLAJE (mas abajo). */
.header-terms-short {
  align-items: center;
  background: var(--ul-bg-soft);
  border: 1.5px solid var(--ul-turquoise-dark);
  border-radius: var(--radius-pill);
  color: var(--ul-navy);
  display: inline-flex;
  font-size: 10px;
  font-weight: 700;
  height: 22px;
  justify-content: center;
  width: 22px;
}

.header-terms-link:hover .header-terms-short,
.header-terms-link:focus-visible .header-terms-short {
  background: var(--ul-turquoise-dark);
  color: #fff;
}

.user-pill {
  align-items: center;
  background: var(--gradient-turquoise);
  border-radius: var(--radius-pill);
  color: var(--ul-navy);
  display: inline-flex;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  height: 28px;
  justify-content: center;
  width: 28px;
}

.user-name {
  color: var(--ul-slate);
  font-size: 14px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* TODO el grupo identidad (circulo + nombre) es el acceso a "Mi perfil" (TD-S36): en movil el
   nombre se oculta y el enlace debe sobrevivir en el circulo de iniciales; en escritorio ademas
   agranda el objetivo de clic (antes solo el nombre era enlace). */
a.user-identity {
  cursor: pointer;
  text-decoration: none;
}

a.user-identity:hover .user-name,
a.user-identity:focus-visible .user-name {
  color: var(--ul-navy);
  text-decoration: underline;
}

/* El form de "Cerrar sesion" (POST, TEMA #2) es transparente al layout: el boton participa DIRECTO
   en el flex de .session-actions (sin caja intermedia que lo desalinee). */
.logout-form {
  display: contents;
}

.logout-button {
  align-items: center;
  background: var(--ul-navy);
  border: none;
  border-radius: var(--radius-md);
  color: var(--ul-turquoise);
  cursor: pointer;
  display: inline-flex;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  gap: 7px;
  min-height: 34px;
  padding: 0 18px;
  text-decoration: none;
}

/* Boton "Salir entrevista" (FR-084d): termina la entrevista SIN cerrar sesion. Va junto a "Cerrar
   sesion" en el encabezado; estilo de CONTORNO (distinto del navy solido) para no confundirse, y la
   MISMA altura (controles uniformes y alineados). Solo aparece en el chat en progreso. */
.interview-exit-button {
  align-items: center;
  background: var(--ul-white);
  border: 1.5px solid var(--ul-turquoise-dark);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  cursor: pointer;
  display: inline-flex;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  min-height: 34px;
  padding: 0 16px;
  white-space: nowrap;
}

.interview-exit-button:hover:not(:disabled),
.interview-exit-button:focus-visible {
  background: var(--ul-turquoise-dark);
  color: #fff;
}

.interview-exit-button:disabled {
  cursor: progress;
  opacity: 0.6;
}

body.llm-page .page-shell {
  padding: 0;
}

.llm-stage {
  margin: 0 auto;
  max-width: 1280px;
  min-height: 0;
  padding: 24px 70px 28px;
  position: relative;
  z-index: 1;
}

.llm-panel {
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  margin: 0 auto;
  max-width: 1080px;
  /* Panel de FORMULARIO: sin overflow:hidden, por el mismo contrato de .ul-modal (las listas
     flotantes del selector de registros y los combobox deben sobresalir del panel). */
}

.llm-panel h1 {
  color: var(--ul-navy);
  font-size: 22px;
  margin: 0;
  padding: 16px 30px 10px;
  text-align: center;
}

.llm-form {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  margin: 0;
  padding: 18px 30px 18px;
}

.llm-mode-tabs {
  align-items: center;
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  display: inline-flex;
  gap: 0;
  margin-bottom: 18px;
  overflow: hidden;
  padding: 4px;
}

.mode-tab {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--ul-slate);
  display: inline-flex;
  font-size: 13px;
  font-weight: 700;
  gap: 8px;
  min-height: 34px;
  padding: 0 17px;
}

.mode-tab.is-active {
  background: var(--ul-navy);
  color: var(--ul-turquoise);
}

.mode-tab:disabled {
  cursor: not-allowed;
  opacity: 0.78;
}

.llm-grid {
  align-items: start;
  display: grid;
  gap: 28px;
  grid-template-columns: minmax(0, 1fr) 340px;
}

.llm-fields {
  align-content: start;
  display: grid;
  gap: 12px 22px;
  grid-template-columns: 1fr 1fr;
}

/* Campos que ocupan las dos columnas (nombre, API key, URL, toggles). */
.ul-field--wide {
  grid-column: 1 / -1;
}

.llm-toggles {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
}

.llm-toggle {
  align-items: center;
  display: inline-flex;
  gap: 8px;
  margin: 0;
}

.llm-toggle span {
  color: var(--ul-navy);
  font-size: 14px;
  font-weight: 700;
}

.llm-toggle-help {
  color: var(--ul-muted);
  display: block;
  font-size: 11.5px;
  line-height: 1.4;
  margin-top: 6px;
}

/* La ayuda y los errores de un campo se alinean bajo el control (columna 2),
   no comprimidos bajo la etiqueta de 78px. */
.ul-field > small {
  color: var(--ul-muted);
  font-size: 11.5px;
  grid-column: 2 / -1;
  line-height: 1.4;
}

.ul-field .errorlist {
  grid-column: 2 / -1;
}

.ul-field,
.price-field {
  align-items: center;
  display: grid;
  gap: 14px;
  grid-template-columns: 78px minmax(0, 1fr);
}

.price-field {
  grid-template-columns: 78px minmax(0, 1fr);
}

.ul-field label,
.price-field label {
  color: var(--ul-navy);
  font-size: 14px;
  font-weight: 700;
}

.ul-field input,
.money-input input,
.input-with-suffix input {
  border-color: var(--ul-turquoise-dark);
  min-height: 40px;
  width: 100%;
}

.ul-field input:focus,
.money-input input:focus,
.input-with-suffix input:focus {
  border-color: var(--ul-turquoise);
}

.input-with-suffix,
.money-input {
  align-items: center;
  display: flex;
  position: relative;
}

.input-with-suffix input {
  padding-right: 72px;
}

.input-with-suffix span {
  color: var(--ul-muted);
  font-size: 12px;
  font-weight: 700;
  position: absolute;
  right: 12px;
}

.money-input span {
  color: var(--ul-turquoise-dark);
  font-weight: 900;
  left: 14px;
  position: absolute;
}

.money-input input {
  padding-left: 34px;
}

.price-panel {
  align-content: start;
  background: var(--ul-bg-tint);
  border: 1px solid rgba(14, 239, 218, 0.32);
  border-radius: var(--radius-md);
  display: grid;
  gap: 12px;
  padding: 15px 16px;
}

.price-heading {
  align-items: flex-start;
  display: flex;
  justify-content: space-between;
}

.price-heading strong {
  color: var(--ul-navy);
  display: block;
  font-size: 14px;
  font-weight: 800;
}

.price-heading span {
  color: var(--ul-muted);
  display: block;
  font-size: 12px;
  margin-top: 3px;
}

.price-heading b {
  color: var(--ul-muted);
  font-size: 11px;
}

.llm-actions {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  margin-top: 14px;
}

.llm-actions .secondary-action,
.llm-actions .primary-action {
  flex: 0 0 auto;
  min-width: 102px;
  width: auto;
}

.primary-action.compact,
.secondary-action.compact {
  min-height: 42px;
  padding-left: 24px;
  padding-right: 24px;
  width: auto;
}

.form-errors,
.errorlist {
  color: var(--color-error);
  font-size: 12px;
  font-weight: 700;
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}

.llm-list {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  margin: 36px auto 0;
  max-width: 1080px;
  overflow: hidden;
}

.llm-list h2 {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 21px;
  margin: 0;
  padding: 18px 22px 10px;
  text-transform: uppercase;
}

.llm-list table {
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* Tabla ancha (muchas columnas): scroll horizontal en vez de cortar la ultima columna. */
.llm-table-scroll {
  overflow-x: auto;
}

@media (max-width: 960px) {
  .app-header {
    min-height: 0;
  }

  .header-content {
    align-items: stretch;
    flex-direction: column;
    gap: 10px;
  }

  .header-title-row {
    align-items: flex-start;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: flex-start;
    order: 0;
  }

  .header-account,
  .session-actions {
    align-items: center;
    flex-wrap: wrap;
  }

  .session-actions {
    max-width: 100%;
  }

  .user-name {
    max-width: min(240px, calc(100vw - 150px));
  }

  .llm-stage {
    padding: 34px 16px 42px;
  }

  .llm-grid,
  .llm-fields {
    grid-template-columns: 1fr;
  }

  .ul-field,
  .price-field {
    grid-template-columns: 1fr;
    gap: 7px;
  }
}

/* Faithful SUPERCHAT UI reference layer */
.nav-item {
  position: relative;
}

.nav-menu {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  display: none;
  left: -6px;
  min-width: 190px;
  padding: 6px;
  position: absolute;
  top: calc(100% + 8px);
  z-index: 40;
}

.nav-item.is-open .nav-menu {
  display: grid;
  gap: 1px;
}

/* El hover solo abre el menu en dispositivos con puntero real (en tactil el :hover queda "pegado"
   tras el tap y chocaria con la apertura por click); en tactil se abre por click/tap (.is-open). */
@media (hover: hover) {
  .nav-item:hover .nav-menu {
    display: grid;
    gap: 1px;
  }
}

.nav-menu a,
.nav-menu span {
  align-items: center;
  border-radius: var(--radius-sm);
  color: var(--ul-slate);
  display: flex;
  font-size: 15px;
  font-weight: 400;
  gap: 9px;
  padding: 9px 14px;
  text-decoration: none;
}

.nav-menu a:first-child,
.nav-menu span:first-child {
  background: var(--ul-bg-tint);
  color: var(--ul-slate);
  font-weight: 600;
}

.nav-menu a::before,
.nav-menu span::before {
  background: var(--ul-border-strong);
  border-radius: 50%;
  content: "";
  height: 6px;
  width: 6px;
}

.nav-menu a:first-child::before,
.nav-menu span:first-child::before {
  background: var(--ul-turquoise);
}

/* Acciones de registro atenuadas: cuando la entidad aun no tiene registros, Consultar/
   Actualizar/Eliminar se muestran en gris y no clicables (solo "Crear" queda activo). */
.nav-menu .is-disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.nav-menu .nav-menu-download {
  border-top: 1px solid var(--ul-border);
  color: var(--ul-navy);
  font-weight: 600;
  margin-top: 5px;
}

.nav-menu .nav-menu-download::before {
  background: transparent;
  border-bottom: 2px solid var(--ul-turquoise-dark);
  border-left: 2px solid var(--ul-turquoise-dark);
  border-radius: 0;
  height: 8px;
  transform: rotate(-45deg);
  width: 8px;
}

/* Descargas consecutivas en un mismo menu: una sola linea separadora antes del grupo, no una por
   item (regla generica del patron, no por pantalla). */
.nav-menu .nav-menu-download + .nav-menu-download {
  border-top: 0;
  margin-top: 0;
}

/* Contenedor de pagina. Principio de UI (ver CLAUDE.md): aprovechar el ancho horizontal y
   no desperdiciar espacio a los lados. Usa casi todo el viewport (acotado en monitores muy
   anchos) con un padding lateral discreto; los paneles internos (formularios via .ul-modal,
   tablas via .ul-table-panel) se auto-limitan a su ancho comodo, asi que ensanchar esto no
   estira los formularios. */
.ul-screen {
  margin: 0 auto;
  max-width: min(1680px, 94vw);
  min-height: 0;
  padding: 8px 36px 12px;
  position: relative;
  z-index: 1;
}

.ul-modal {
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  margin: 0 auto;
  max-width: var(--modal-width, 1080px);
  /* CONTRATO: los paneles de FORMULARIO no recortan (sin overflow:hidden). Las listas flotantes
     de sus controles (.record-search-results: combobox con busqueda, autocompletado, selector de
     registros) deben poder sobresalir del panel, como el desplegable de un <select> nativo. Nada
     interno pinta hasta las esquinas (titulo y cuerpo tienen padding), asi que el redondeo no
     necesita recorte. Los paneles de TABLA (.ul-table-panel) si conservan el suyo. */
  /* position: relative para anclar el icono "X" de cierre (.panel-close) arriba a la derecha. */
  position: relative;
}

.ul-modal-title {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  margin: 0;
  padding: 16px 30px 11px;
  text-align: center;
}

/* Si la ventana tiene icono "X" de cierre arriba a la derecha, el titulo centrado reserva espacio a
   ambos lados para no quedar debajo del icono en pantallas angostas (sigue centrado). */
.ul-modal:has(> .panel-close) .ul-modal-title {
  padding-left: 48px;
  padding-right: 48px;
}

.ul-modal-body {
  border-top: 1px solid var(--ul-border-strong);
  padding: 16px 30px 18px;
}

.ul-form {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  margin: 0;
  padding: 0;
}

.ul-form-grid {
  display: grid;
  gap: 14px;
}

/* Modificador OPT-IN para formularios LARGOS: distribuye las filas en DOS columnas para reducir el
   scroll vertical (principio de UI 1) y aprovechar el ancho del modal (principio 2), sin estirar cada
   campo a todo el monitor. Mecanismo generico y reutilizable: basta anadir `ul-form-grid--2col` a un
   `.ul-form-grid` (y dar mas ancho al modal); los grids que no lo activan no cambian. En pantallas
   angostas colapsa a una sola columna (ver media query). */
.ul-form-grid--2col {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 28px;
  /* Relleno denso: cuando una fila a ancho completo (p. ej. el desplegable buscable de abajo) parte
     el flujo, la media-celda que quedaria vacia la ocupa el siguiente campo, sin filas huecas
     (principios 1 y 2). El orden de tabulacion sigue siendo el del formulario. */
  grid-auto-flow: dense;
}

/* Componente COMPARTIDO con base NEUTRA: la barra no asume nada de su anfitrion; cada tipo de
   panel agrega SOLO sus insets. Asi un anfitrion nuevo nace bien por defecto, en vez de heredar
   afinados de otro panel y tener que deshacerlos (Principio 5: la regla del anfitrion afina, no
   parcha). */
.record-selector-bar {
  align-items: center;
  border-bottom: 1px solid var(--ul-border-strong);
  display: grid;
  gap: 18px;
  grid-template-columns: 190px minmax(0, 1fr);
  margin: 0 0 18px;
  padding: 0 0 18px;
}

/* Panel de FORMULARIO (.ul-modal-body, relleno lateral de 30px): el margen negativo cancela ese
   relleno para que el borde inferior abarque todo el ancho, y el padding re-inseta la etiqueta
   alineada con el contenido; el -4px arrima la barra al encabezado del modal. */
.ul-modal-body > .record-selector-bar {
  margin: -4px -30px 18px;
  padding: 0 30px 18px;
}

.llm-panel > .record-selector-bar {
  margin: 0;
  padding: 8px 30px 14px;
}

/* Panel de TABLA (.ul-table-panel, sin relleno propio: su contenido va con inset de 22px via el
   padding del h2): mismo inset lateral que el titulo y un respiro arriba para no morder el texto
   previo (p. ej. el parrafo de ayuda). */
.ul-table-panel > .record-selector-bar {
  padding: 8px 22px 18px;
}

.record-selector-bar label {
  color: var(--ul-navy);
  font-size: 15px;
  font-weight: 800;
}

.record-selector-bar select {
  border-color: var(--ul-turquoise-dark);
  min-height: 40px;
  width: 100%;
}

/* Caja de busqueda con autocompletado (reemplaza al <select> que cargaba todos los registros).
   El contenedor es position:relative para anclar la lista de resultados flotante debajo. */
.record-search-box,
.autocomplete-field {
  position: relative;
  width: 100%;
}

/* Contrato UNICO del campo de busqueda: lo comparten el autocompletado de registros
   (.record-search-input) y el buscador del Centro de Reportes (.report-search input), para no
   duplicar borde/alto/radio/padding/ancho (Principio 5: solucion generica, no parche por caso). */
.record-search-input,
.report-search input {
  border: 1px solid var(--ul-turquoise-dark);
  border-radius: var(--radius-md);
  min-height: 40px;
  padding: 0 12px;
  width: 100%;
}

.record-search-current {
  color: var(--ul-navy);
  font-size: 13px;
  margin: 6px 0 0;
  opacity: 0.8;
}

.record-search-results {
  background: var(--ul-white);
  border: 1px solid var(--ul-border-strong);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  left: 0;
  list-style: none;
  margin: 4px 0 0;
  max-height: 280px;
  overflow-y: auto;
  padding: 4px;
  position: absolute;
  right: 0;
  top: 40px;
  z-index: 20;
}

/* Lista flotante DESANCLADA al <body> por float_fit.js (ver desanclar() alli): al abrirse sale de
   su panel y se fija al area visible, para que NINGUN ancestro con overflow pueda recortarla. Antes
   vivia dentro del panel y `.ul-table-panel` (overflow: hidden por sus esquinas redondeadas) le
   rebanaba la ultima fila a la mitad; con esto el desplegable usa todo el alto de la pantalla, como
   el de un <select> nativo. La GEOMETRIA (top/left/width/max-height) la calcula el JS con la
   posicion del control; aqui solo va el modo de posicionamiento y la neutralizacion de los anclajes
   de la regla base, que se resolvian contra un ancestro que ya no es el suyo.

   `max-height: none` suelta el tope de 280px de la regla base: flotando, quien acota el alto es el
   espacio VISIBLE, que float_fit.js mide y aplica en linea. Sin esto la lista seguiria topada en
   280px aunque sobrara media pantalla — es decir, se arreglaba el recorte pero NO se cumplia lo
   prometido (usar todo el alto, como un <select> nativo), y ademas el alto "natural" que mide el JS
   para decidir hacia que lado abrir venia ya recortado, falseando la decision.

   z-index 50: sobre el contenido y los menus del encabezado (40). OJO, no sirve para ordenarse
   frente a los velos de pantalla completa: `.page-shell` declara `isolation: isolate`, asi que todo
   lo que se pinta DENTRO de el (p. ej. `.processing-overlay`, z-index 100) queda confinado a ese
   contexto y no puede tapar a un hijo directo de <body> como esta lista, por alto que sea su
   z-index. Solo lo tapan los velos que cuelgan del propio <body> (el lightbox, z-index 1000, que se
   inyecta con `document.body.appendChild`). Si algun dia una pantalla junta un desplegable con un
   velo interno, el velo es el que debe subir al <body>, no esta lista la que debe bajar. */
.record-search-results.is-floating {
  bottom: auto;
  margin: 0;
  max-height: none;
  position: fixed;
  right: auto;
  z-index: 50;
}

/* Plegado hacia ARRIBA de la lista flotante (lo aplica float_fit.js cuando abajo no hay espacio y
   arriba si, como el desplegable de un <select> nativo cerca del fondo). Lo comparten el combobox
   con busqueda y el autocompletado (misma lista). Solo aporta el ASPECTO: la posicion la fija el JS.
   La sombra de elevacion se invierte al abrir hacia arriba: si apuntara hacia abajo, embarraria el
   propio campo en el que se esta escribiendo. */
.record-search-results.drop-up {
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.12);
}

.record-search-option {
  border-radius: 6px;
  cursor: pointer;
  padding: 8px 10px;
}

.record-search-option:hover,
.record-search-option.is-active {
  background: var(--ul-turquoise-dark);
  color: var(--ul-white);
}

/* Lista desplegable con busqueda (searchable_select.js enriquece <select data-searchable>): muestra
   TODOS los items (ojeable) y filtra al escribir. Reutiliza el look del autocompletado (.record-search-*)
   y del <select> del formulario; el contenedor ancla la lista flotante y dibuja el caret del desplegable
   para que se lea como una lista, no como una caja de texto suelta. */
.searchable-select {
  position: relative;
  width: 100%;
}

.searchable-select::after {
  border-bottom: 2px solid var(--ul-navy);
  border-right: 2px solid var(--ul-navy);
  content: "";
  height: 9px;
  pointer-events: none;
  position: absolute;
  right: 13px;
  top: 50%;
  transform: translateY(-70%) rotate(45deg);
  width: 9px;
}

.searchable-select.is-disabled::after {
  opacity: 0.35;
}

/* Igual borde/alto que los <input>/<select> del formulario (Principio 6: controles uniformes). */
.searchable-select-input {
  border-width: 1.5px;
  padding-right: 30px;
}

/* Oculta el <select> nativo una vez enriquecido (sigue enviando el valor y validando el formulario).
   Sin JS el <select> queda visible (respaldo), porque el contenedor .searchable-select lo crea el JS. */
.searchable-select select {
  display: none;
}

/* En un grid de DOS columnas, la fila de una lista desplegable con busqueda ocupa las dos columnas:
   su contenido son nombres largos de un catalogo (clientes, paises) y en media celda se recortan.
   Regla CENTRAL (principio 5): cubre sola cualquier formulario 2col con desplegable buscable, con y
   sin JS (el <select data-searchable> permanece dentro de la fila tras el enriquecimiento). */
.ul-form-grid--2col .ul-form-row:has(select[data-searchable]) {
  grid-column: 1 / -1;
}

/* Navegacion de paginas (partial _pager.html): se usa donde una lista pagina en la BD. */
.pager {
  align-items: center;
  display: flex;
  gap: 16px;
  justify-content: space-between;
  margin-top: 14px;
}

.pager-status {
  color: var(--ul-navy);
  font-size: 13px;
  font-weight: 600;
}

.ul-form-row {
  align-items: center;
  display: grid;
  gap: 14px;
  grid-template-columns: var(--label-width, 120px) minmax(0, 1fr);
}

/* El titulo de la previsualizacion (FR-096) comparte la regla CENTRAL de las etiquetas del grid
   (uniformidad desde la clase central, principio UI #6), no una copia propia. */
.ul-form-row label,
.ul-form-row .font-preview-titulo {
  color: var(--ul-navy);
  font-size: 15px;
  font-weight: 700;
}

.ul-form-row input,
.ul-form-row select,
.ul-form-row textarea {
  border: 1.5px solid var(--ul-turquoise-dark);
  min-height: 40px;
  width: 100%;
}

.ul-form-row textarea {
  line-height: 1.55;
  /* Contenido grande (p. ej. las Instrucciones del proyecto): se acota la altura con
     scroll interno para no forzar scroll de toda la pagina; el usuario puede agrandarla. */
  min-height: 110px;
  max-height: 26vh;
  overflow: auto;
  resize: vertical;
}

/* Encabezado de seccion dentro de un .ul-form: clase central reutilizable (antes eran estilos en
   linea repetidos en cada plantilla). Concentra el look (navy, ~1rem, separacion) en un solo sitio
   (principios 5 y 7), para que se mantenga coherente solo. */
.ul-form-section {
  color: var(--ul-navy);
  font-size: 1rem;
  font-weight: 700;
  margin: 16px 0 4px;
}

.ul-form-section:first-of-type {
  margin-top: 6px;
}

/* Densidad compacta para formularios LARGOS (muchos campos): reduce el alto por fila para mostrar
   mas informacion sin scroll vertical (principio de UI 1). Mecanismo GENERICO y reutilizable: basta
   anadir `is-dense` al <form class="ul-form"> de cualquier pantalla con un formulario extenso; los
   formularios que no la activan no cambian. El textarea se EXCLUYE del alto reducido (conserva su
   propia altura util). */
.ul-form.is-dense .ul-form-grid {
  /* Solo el alto entre filas: el `column-gap` se deja al grid (irrelevante en grids de 1 columna y,
     en `.ul-form-grid--2col`, controlado por su propia regla sin que esta lo pise por especificidad). */
  row-gap: 6px;
}

/* Input numerico COMPACTO (p. ej. tamano de letra del chat): ancho central unico para todo campo
   corto, en vez de estilos inline campo por campo (principio UI #6). */
.ul-form-row input.input-compact {
  max-width: 110px;
}

/* Previsualizacion viva de la letra del chat (FR-096, parcial _font_size_preview.html): la frase
   adopta al instante el tamano/tipografia elegidos en el formulario. El titulo ocupa la columna de
   etiquetas del grid con el mismo peso visual que un label. */
.font-preview-row {
  margin-top: 4px;
}

.font-preview-text {
  background: rgba(14, 239, 218, 0.08);
  border: 1.5px dashed var(--ul-turquoise-dark);
  border-radius: var(--radius-md);
  color: var(--ul-navy-deep);
  font-size: 15px; /* punto de partida = default del cliente (15); el JS lo re-estiliza en vivo */
  margin: 0;
  padding: 10px 14px;
}

.ul-form.is-dense .ul-form-row {
  gap: 12px;
}

.ul-form.is-dense .ul-form-row input,
.ul-form.is-dense .ul-form-row select {
  min-height: 34px;
}

.ul-form.is-dense .ul-form-section {
  margin: 6px 0 2px;
}

.ul-form.is-dense .ul-form-section:first-of-type {
  margin-top: 2px;
}

/* Ventana modal compacta: acompana a `.ul-form.is-dense` recortando el relleno del titulo, del
   cuerpo y del parrafo de ayuda para ganar mas alto util (mismo objetivo: menos scroll). Scopeado a
   `.ul-modal.is-dense`, asi que las demas ventanas no cambian. */
.ul-modal.is-dense .ul-modal-title {
  padding-top: 9px;
  padding-bottom: 5px;
}

.ul-modal.is-dense .ul-modal-body {
  padding-top: 9px;
  padding-bottom: 9px;
}

.ul-modal.is-dense .up-hint {
  font-size: 13px;
  line-height: 1.3;
  /* Sin sangria lateral propia (el cuerpo del modal ya tiene su padding): usa todo el ancho para
     caber en UNA linea y aprovechar el ancho (principios 1 y 2). */
  padding: 0 0 8px;
}

.ul-modal.is-dense .ul-modal-actions {
  margin-top: 7px;
}

.ul-two-col {
  align-items: start;
  display: grid;
  gap: 14px 32px;
  grid-template-columns: 1.05fr 0.95fr;
}

/* Pantalla Crear / Actualizar proyecto: configuracion a la izquierda e Instrucciones a la
   derecha (dos columnas) para que la pantalla quepa sin scroll vertical de toda la pagina. */
.project-form-grid {
  display: grid;
  gap: 16px 30px;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
}

.project-fields {
  align-content: start;
  display: grid;
  gap: 11px;
}

.project-prompt {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.project-prompt > label {
  color: var(--ul-navy);
  font-size: 15px;
  font-weight: 700;
  margin-bottom: 7px;
}

.project-prompt textarea {
  border: 1.5px solid var(--ul-turquoise-dark);
  line-height: 1.55;
  /* Respeta su `rows` (8) en vez de estirarse a toda la columna: un alto moderado que no obliga a
     hacer scroll de toda la pagina. El SM puede agrandarla (resize) para prompts largos. Solo la usa
     el form de EXPERTO IA (el de proyecto usa .project-ficha, no .project-prompt). */
  resize: vertical;
  width: 100%;
}

.project-prompt-note {
  align-self: flex-end;
  color: var(--ul-muted);
  font-size: 12px;
  margin-top: 6px;
}

/* Ficha del experto IA (FR-106): tarjeta de SOLO LECTURA en la columna derecha del form de proyecto.
   El cliente ve que resuelve el experto IA y que documento entrega; nunca el prompt ni los parametros. */
.project-ficha {
  align-content: start;
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  display: grid;
  gap: 10px;
  padding: 16px 18px;
}

.project-ficha-title {
  color: var(--ul-navy);
  font-size: 15px;
  font-weight: 700;
  margin: 0;
}

.project-ficha-list {
  display: grid;
  gap: 3px;
  margin: 0;
}

.project-ficha-list dt {
  color: var(--ul-sky-dark);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.project-ficha-list dd {
  color: var(--ul-slate);
  line-height: 1.5;
  margin: 0 0 10px;
}

.project-ficha-empty {
  color: var(--ul-muted);
  font-size: 13px;
  line-height: 1.55;
  margin: 0;
}

/* --- Catalogo de expertos IA (FR-106, System Manager) -------------------------------------------- */

/* Sub-navegacion (tabs) compartida por las pantallas del catalogo. */
.catalog-subnav {
  border-bottom: 1px solid var(--ul-border);
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0 22px 8px;
  padding-top: 2px;
}

.catalog-subnav a {
  border-bottom: 2px solid transparent;
  color: var(--ul-muted);
  font-weight: 600;
  padding: 8px 12px;
  text-decoration: none;
}

.catalog-subnav a:hover {
  color: var(--ul-navy);
}

.catalog-subnav a.is-active {
  border-bottom-color: var(--ul-turquoise-dark);
  color: var(--ul-navy);
}

/* Hub: tarjetas de acceso con conteo. */
.catalog-hub {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

.catalog-hub-card {
  align-items: center;
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 18px 14px;
  text-align: center;
  text-decoration: none;
  transition: border-color 0.12s, box-shadow 0.12s;
}

.catalog-hub-card:hover {
  border-color: var(--ul-turquoise-dark);
  box-shadow: var(--shadow-sm);
}

.catalog-hub-count {
  color: var(--ul-navy);
  font-family: "Oswald", sans-serif;
  font-size: 30px;
  font-weight: 600;
  line-height: 1;
}

.catalog-hub-label {
  color: var(--ul-slate);
  font-weight: 700;
}

.catalog-hub-sub {
  color: var(--ul-muted);
  font-size: 12px;
}

/* Ficha de detalle de experto IA (SM ve TODO, incluido el prompt). */
/* Ficha de experto IA como rejilla ETIQUETA | VALOR (2 columnas) en vez de apilar label sobre valor:
   aprovecha el ancho y baja a la mitad el alto de los metadatos (principios de UI #1 y #2). El
   prompt/KB (cajas .experto-ia-prompt) viven en la columna de valor, que es ancha (1fr). */
.experto-ia-detail {
  align-items: start;
  column-gap: 20px;
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr);
  margin: 0;
  row-gap: 9px;
}

.experto-ia-detail dt {
  color: var(--ul-sky-dark);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.experto-ia-detail dd {
  color: var(--ul-slate);
  line-height: 1.5;
  margin: 0;
}

.experto-ia-prompt {
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-sm);
  font-size: 13px;
  margin: 0;
  max-height: 320px;
  overflow: auto;
  padding: 12px 14px;
  white-space: pre-wrap;
  word-break: break-word;
}

/* Dial de version inline en la tabla de licencias (canario). */
.dial-version {
  align-items: center;
  display: inline-flex;
  gap: 6px;
  margin-top: 6px;
}

.dial-version select {
  min-width: 96px;
}

.ul-modal-subtitle {
  color: var(--ul-muted);
  font-size: 0.62em;
  font-weight: 600;
}

/* Intro de "Solicitar proyecto" (FR-106 F3): parrafos de contexto antes de entrar al chat. */
.solicitar-intro {
  color: var(--ul-slate);
  line-height: 1.6;
  margin: 0 0 14px;
}

/* Base de conocimiento (FR-091): cargador (archivo + boton + estado) sobre un textarea editable a
   todo el ancho del formulario, bajo el grid de dos columnas. */
.project-knowledge {
  margin-top: 16px;
}

.project-knowledge > label {
  color: var(--ul-navy);
  display: block;
  font-size: 15px;
  font-weight: 700;
  margin-bottom: 7px;
}

.kb-uploader {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 4px 0 8px;
}

.kb-uploader .kb-file {
  flex: 1 1 240px;
  min-width: 0;
}

.kb-status {
  color: var(--ul-muted);
  font-size: 13px;
}

.kb-status.is-error {
  color: #c0392b;
}

.project-knowledge textarea {
  border: 1.5px solid var(--ul-turquoise-dark);
  line-height: 1.55;
  resize: vertical;
  width: 100%;
}

/* Dos campos numericos cortos lado a lado (Temperatura / Umbral de cierre). */
.ul-field-duo {
  display: grid;
  gap: 13px 16px;
  grid-template-columns: 1fr 1fr;
}

/* Campo con etiqueta arriba (numeros cortos y archivo). */
.ul-stack-field {
  align-content: start;
  display: grid;
  gap: 6px;
}

.ul-stack-field > label,
.ul-field-label-row > label {
  color: var(--ul-navy);
  font-size: 14px;
  font-weight: 700;
}

.ul-stack-field > input,
.ul-stack-field > select {
  border: 1.5px solid var(--ul-turquoise-dark);
  min-height: 40px;
  width: 100%;
}

.ul-stack-field small {
  color: var(--ul-muted);
  font-size: 11.5px;
  line-height: 1.4;
}

/* Ayuda de campo (GENERICA, para cualquier etiqueta que necesite un ejemplo/contrato): un icono "?"
   junto a la etiqueta (details/summary nativo, sin JS) despliega un panel con la ayuda. El <details>
   es transparente al layout (display:contents, principio 7): el icono participa DIRECTO en el flex
   de la fila de etiqueta y el panel, al abrirse, salta a su propia linea a todo el ancho
   (flex-basis:100% + flex-wrap). EN FLUJO, no flotante: el ejemplo empuja el campo hacia abajo y
   queda visible MIENTRAS se escribe en el, en vez de taparlo. */
.ul-field-label-row {
  align-items: center;
  column-gap: 7px;
  display: flex;
  flex-wrap: wrap;
}

.ul-field-help {
  display: contents;
}

.ul-field-help > summary {
  color: var(--ul-turquoise-dark);
  cursor: pointer;
  display: inline-flex;
  list-style: none; /* oculta el triangulo nativo del <summary> (el "?" ya anuncia el toggle) */
  padding: 3px; /* area de clic comoda alrededor del glifo de 16px */
}

.ul-field-help > summary::-webkit-details-marker {
  display: none;
}

.ul-field-help > summary:hover,
.ul-field-help[open] > summary {
  color: var(--ul-navy);
}

.ul-field-help-panel {
  background: var(--ul-white);
  border: 1px solid var(--ul-border-strong);
  border-radius: var(--radius-sm);
  color: var(--ul-slate);
  flex-basis: 100%;
  font-size: 12px;
  line-height: 1.45;
  margin: 2px 0 4px;
  /* Principio 1: la ayuda no debe hacer crecer la pantalla sin tope; el exceso scrollea aqui. */
  max-height: 320px;
  overflow-y: auto;
  padding: 10px 12px;
}

.ul-field-help-panel p {
  /* El generico `form p {display:grid}` (filas de campo del render as_p) alcanza a estos <p> por
     vivir dentro del <form>; aqui son PROSA: sin la vuelta a block, cada <code> del parrafo se
     blockifica como item de grid y rompe la linea. */
  display: block;
  margin: 0 0 6px;
}

.ul-field-help-panel ul {
  margin: 0 0 8px;
  padding-left: 18px;
}

.ul-field-help-panel pre {
  background: var(--ul-bg-soft);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, "Cascadia Code", "Consolas", monospace;
  font-size: 11.5px;
  line-height: 1.4;
  margin: 0 0 8px;
  overflow-x: auto; /* principio 2: scroll DENTRO del panel antes que envolver el JSON */
  padding: 8px 10px;
}

/* Plantilla .docx: el widget de archivo de Django se ordena dentro de un panel y el
   selector de archivo toma el estilo de marca. */
.ul-file-control {
  background: var(--ul-white);
  border: 1.5px solid var(--ul-turquoise-dark);
  border-radius: var(--radius-sm);
  color: var(--ul-muted);
  font-size: 13px;
  line-height: 1.5;
  padding: 8px 11px;
}

.ul-file-control a {
  color: var(--ul-turquoise-dark);
  font-weight: 600;
  word-break: break-all;
}

.ul-file-control label {
  color: var(--ul-muted);
  display: inline;
  font-size: 13px;
  font-weight: 600;
}

.ul-file-control input[type="file"] {
  background: transparent;
  border: 0;
  color: var(--ul-muted);
  font-size: 13px;
  margin-top: 4px;
  min-height: 0;
  padding: 0;
  width: 100%;
}

.ul-file-control input[type="file"]::file-selector-button {
  background: var(--ul-navy);
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--ul-turquoise);
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 700;
  margin-right: 10px;
  padding: 7px 14px;
}

.ul-file-control input[type="file"]::file-selector-button:hover {
  background: var(--ul-navy-deep);
}

.ul-price-panel {
  background: var(--ul-bg-tint);
  border: 1px solid rgba(14, 239, 218, 0.32);
  border-radius: var(--radius-md);
  display: grid;
  gap: 12px;
  padding: 15px 16px;
}

.ul-modal-actions {
  align-items: stretch;
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  margin-top: 14px;
}

/* Los <form> que solo envuelven un boton de accion (para POST) no deben generar
   una caja propia: con display:contents el boton participa DIRECTO en el flex de
   .ul-modal-actions y estira a la misma altura que el resto (sin contenedor inutil). */
.ul-modal-actions > form {
  display: contents;
}

/* Pagina de Terminos y Condiciones: compacta para leerse sin scroll vertical; los puntos
   del tratamiento de datos van en dos columnas. */
.terms-body {
  color: var(--ul-slate);
  font-size: 13.5px;
}

.terms-version {
  color: var(--ul-muted);
  font-size: 12.5px;
  margin: 0 0 10px;
}

.terms-h2 {
  color: var(--ul-navy);
  font-size: 16px;
  font-weight: 700;
  margin: 12px 0 5px;
}

.terms-body > .terms-h2:first-of-type {
  margin-top: 2px;
}

.terms-p {
  line-height: 1.45;
  margin: 0 0 7px;
}

.terms-grid {
  align-items: start;
  display: grid;
  gap: 0 30px;
  grid-template-columns: 1fr 1fr;
}

/* Pagina de inicio (home): solo la cabecera con los menus por rol; el cuerpo es un saludo
   centrado sobre el fondo de marca, sin ninguna ventana/modal. */
.home-hub {
  align-items: center;
  display: flex;
  flex-direction: column;
  gap: 12px;
  justify-content: center;
  min-height: calc(100vh - 220px);
  position: relative;
  text-align: center;
  z-index: 1;
}

.home-hub-title {
  color: var(--ul-on-navy-deep);
  font-family: var(--font-display);
  font-size: 42px;
  letter-spacing: 0.01em;
  margin: 0;
  text-transform: uppercase;
}

/* Recuadro translucido (navy) detras del saludo para que el texto sea legible sobre
   cualquier imagen de fondo configurada. */
.home-hub-card {
  backdrop-filter: blur(3px);
  background: rgba(16, 0, 70, 0.82);
  border: 1px solid rgba(14, 239, 218, 0.28);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  max-width: 620px;
  padding: 30px 44px;
}

.home-hub-sub {
  color: var(--ul-turquoise);
  font-size: 16px;
  margin: 0;
  max-width: 540px;
}

/* Panel de tabla. Por defecto llena el ancho disponible del .ul-screen (principio de UI:
   aprovechar el ancho horizontal) hasta un tope generoso; cada pantalla puede ajustar
   --table-width (p. ej. 100% para reportes con muchas columnas). */
.ul-table-panel {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  margin: 36px auto 0;
  max-width: var(--table-width, 1280px);
  overflow: hidden;
  position: relative;
  width: 100%;
}

/* Boton "X" (cerrar -> home) de las pantallas tipo panel (Configuracion, Asignar proyectos,
   Importar/Exportar). Icono pequeno (~34px) arriba a la derecha del panel. */
.panel-close {
  align-items: center;
  border-radius: var(--radius-sm);
  color: var(--ul-muted);
  display: inline-flex;
  height: 34px;
  justify-content: center;
  position: absolute;
  right: 14px;
  top: 12px;
  width: 34px;
  z-index: 2;
}

.panel-close:hover,
.panel-close:focus-visible {
  background: var(--ul-bg-tint);
  color: var(--ul-navy);
}

.panel-close:focus-visible {
  outline: 2px solid var(--ul-sky);
  outline-offset: 2px;
}

/* Overlay de "procesando" (spinner + texto) para POST sincronos que tardan, p. ej. el reporte
   libre mientras el LLM arma la consulta. Lo activa partials/_processing_overlay.html. */
.processing-overlay {
  align-items: center;
  background: rgba(15, 23, 42, 0.55);
  display: flex;
  inset: 0;
  justify-content: center;
  position: fixed;
  z-index: 100;
}

.processing-overlay[hidden] {
  display: none;
}

.processing-box {
  align-items: center;
  background: var(--ul-white);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 32px 44px;
}

.processing-spinner {
  animation: processing-spin 0.8s linear infinite;
  border: 4px solid var(--ul-border);
  border-top-color: var(--ul-turquoise-dark);
  border-radius: 50%;
  height: 46px;
  width: 46px;
}

.processing-text {
  color: var(--ul-navy);
  font-weight: 600;
  margin: 0;
}

@keyframes processing-spin {
  to {
    transform: rotate(360deg);
  }
}

.ul-table-panel h2 {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 21px;
  margin: 0;
  padding: 18px 22px 10px;
  text-transform: uppercase;
}

/* Cabecera de panel de tabla con una accion a la derecha (p. ej. "Crear cliente" junto al titulo).
   El header aporta el padding; el h2 interior lo resetea para no duplicarlo. */
.ul-table-panel-header {
  align-items: center;
  display: flex;
  gap: 12px;
  justify-content: space-between;
  padding: 18px 22px 10px;
}

.ul-table-panel-header h2 {
  padding: 0;
}

.ul-table-panel table {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  /* La regla base `table` trae overflow:hidden (para sus esquinas redondeadas, que aqui ya
     resetea el panel). Sin este reset, ese overflow:hidden en el <table> se vuelve el limite
     de position:sticky (la celda Acciones queda "pegada" a la propia tabla, que se mueve
     junto con el scroll, en vez de a .ul-table-scroll) y la columna de acciones deja de fijarse. */
  overflow: visible;
}

/* Scroll horizontal DENTRO del panel: cuando una tabla tiene muchas columnas (p. ej. un
   reporte pivoteado), se desplaza en horizontal en vez de apretar/envolver el texto. El
   panel conserva overflow:hidden (esquinas redondeadas); este envoltorio es el que scrollea.
   Principio de UI: aprovechar el ancho horizontal (ver CLAUDE.md). */
.ul-table-scroll {
  overflow-x: auto;
}

/* border-collapse:collapse (regla global de `table`) impide que position:sticky funcione en
   celdas de tabla en Chromium/WebKit: la celda "Acciones" sticky quedaba con position:sticky
   en el computed style pero sin efecto visual (detectado con captura + inspeccion de
   bounding rect). border-spacing:0 mantiene el mismo aspecto (los bordes ya son solo
   border-bottom en th/td, sin doble borde) sin perder la fijacion horizontal.
   ACOTADO al panel: fuera de .ul-table-panel (api_key_result, constancia) la tabla conserva el
   borde exterior de la regla base y con `separate` el border-bottom de la ultima fila dejaria
   de colapsar con el (linea doble); alli no hay columnas sticky, asi que conservan collapse. */
.ul-table-panel .ul-table-scroll table {
  border-collapse: separate;
  border-spacing: 0;
}

/* Densidad COMPACTA por defecto de los paneles de tabla (principio de UI #1: ver el maximo de items
   sin scroll vertical). Aplica a TODA tabla en `.ul-table-panel` (System Manager, reportes, catalogo).
   Antes era opt-in (`.ul-table-panel--compact`) solo para el catalogo; se promovio a la base porque
   "filas compactas" vale para todas las tablas admin (no habia razon para dejar unas densas y otras
   no). Reduce ~64% el relleno vertical de las celdas (11px -> 4px), aprieta el header/titulo y baja el
   boton-icono de accion a 26px (su cuadro de 32px fijaba la altura MINIMA de la fila; el glifo SVG mide
   16px, a 26px conserva aire y sigue comodo con raton). El truncado a un renglon de un texto largo lo
   aporta `.ul-cell-ellipsis` por columna. */
.ul-table-panel table th,
.ul-table-panel table td {
  padding-bottom: 4px;
  padding-top: 4px;
}

.ul-table-panel-header,
.ul-table-panel > h2 {
  padding-bottom: 6px;
  padding-top: 12px;
}

.ul-table-panel .ul-table-actions a,
.ul-table-panel .ul-table-actions button {
  height: 26px;
  width: 26px;
}

/* ===========================================================================
   Barra de filtros y agrupamientos de reportes tabulares (TD-S35). Principio
   de producto: TODO reporte ofrece filtros y agrupamientos (granularidad a
   eleccion) sin pasar por Excel. Tarjeta compacta SOBRE el panel de tabla
   (fuera de el: los paneles de tabla recortan y las listas flotantes de los
   combobox no deben recortarse). Etiqueta ENCIMA de cada control, fila que
   envuelve, casillas "Agrupar por" en linea y acciones a la derecha. Generica:
   cualquier reporte tabular la reutiliza tal cual.
   =========================================================================== */
/* Superficie propia (misma que .ul-table-panel) para que la barra no flote sobre el fondo de marca:
   sin ella las etiquetas quedaban sobre la fotografia, con contraste pobre, y el grupo de controles
   no se leia como una unidad. NO lleva `overflow: hidden` (a diferencia del panel de tabla): las
   listas flotantes de los combobox deben poder desbordar. Ancho identico al panel (ambos son hijos
   directos de .ul-screen y ocupan su ancho), asi los bordes quedan alineados. */
.report-filters {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0 0 14px;
  padding: 14px 18px;
}

/* Rejilla de columnas UNIFORMES que se auto-reparte el ancho (Principio 2): con flex, un
   control que baja de fila se estira solo a todo el ancho (feo) o deja espacio muerto; la
   rejilla conserva el ritmo de columna en cualquier ancho. */
.report-filters-grid {
  display: grid;
  gap: 10px 14px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

.report-filters-row {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
  justify-content: space-between;
}

.report-filtro {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.report-filtro label {
  font-size: 13px;
}

.report-agrupar {
  border: 0;
  margin: 0;
  min-width: 0;
  padding: 0;
}

/* La leyenda participa EN LINEA con las casillas (float: un legend no puede ser item flex). */
.report-agrupar legend {
  color: var(--ul-navy);
  float: left;
  font-size: 13px;
  font-weight: 700;
  line-height: 24px;
  padding: 0 12px 0 0;
}

.report-agrupar > div {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
}

/* El envoltorio por casilla que genera Django no aporta nada: transparente al layout
   (Principio 7: sin contenedores sin proposito). */
.report-agrupar > div > div {
  display: contents;
}

.report-agrupar label {
  align-items: center;
  display: inline-flex;
  font-weight: 500;
  gap: 6px;
  margin: 0;
}

.report-filters-acciones {
  display: flex;
  flex: 0 0 auto;
  gap: 9px;
}

/* Tabla de un reporte tabular (Costos LLM y los reportes operativos): UNA sola linea por celda.
   Principio 1 (minimizar el scroll vertical): con nombres largos de proyecto/modelo cada fila ocupaba
   DOS renglones y la pagina crecia al doble.

   Principio 2 (aprovechar el ancho): el texto largo se corta con elipsis en vez de empujar las
   columnas NUMERICAS fuera de la vista. Solo con `nowrap` la tabla medía ~1400px y el Costo (USD) --la
   razon de ser del reporte-- quedaba tras el scroll horizontal. El scroll de `.ul-table-scroll` sigue
   ahi como red de seguridad para pantallas estrechas, pero ya no es necesario para leer la cifra.
   `title` en cada celda (plantilla) devuelve el texto completo al pasar el cursor.

   Clase propia, no un selector global de tablas: otras pantallas si necesitan envolver. */
.report-table th,
.report-table td {
  white-space: nowrap;
}

/* El tope de ancho es SOLO para las celdas de datos. Un encabezado dice que SIGNIFICA la columna y
   recortarlo la vuelve ilegible; y la celda de "sin resultados" (un unico td con colspan) es
   justamente el mensaje que el usuario necesita leer entero -- con el tope quedaba en "Sin costos
   registrados para los filt...". */
.report-table td:not([colspan]) {
  max-width: 24ch;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Totales del filtro (la granularidad mas gruesa), bajo el titulo del panel de tabla. */
.report-totales {
  color: var(--ul-muted);
  font-weight: 600;
  margin: 0;
  padding: 0 22px 10px;
}

/* Encabezado del panel de resultados de un reporte: titulo a la izquierda y acciones de icono
   (p. ej. descargar a Excel) a la derecha. El titulo (.ul-table-panel h2) conserva su padding
   propio; la accion reserva a su derecha el hueco de la "X" de cierre (.panel-close, absoluta
   arriba-derecha) para no solaparse con ella. */
.report-result-head {
  align-items: center;
  display: flex;
  gap: 12px;
  justify-content: space-between;
}
.report-result-head .ul-table-actions {
  padding-right: 56px;
}

/* Aviso cuando el detalle supera el maximo de filas exportable a Excel: se avisa en vez de
   truncar en silencio o atar un worker construyendo un .xlsx descomunal. */
.report-export-aviso {
  color: #b42318;
  font-weight: 600;
  margin: 0;
  padding: 0 22px 10px;
}

/* Titulo de la pantalla de un reporte operativo, encima de la barra de filtros (Fase C: unifica la
   pantalla con Costos LLM). Alineado al ancho del contenido. */
.report-page-title {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 23px;
  letter-spacing: 0.01em;
  margin: 4px auto 16px;
  max-width: 1280px;
  padding: 0 4px;
  text-transform: uppercase;
  width: 100%;
}

/* Resumen (datos agregados) al pie del panel de resultados de un reporte: una linea por dato,
   legible aun cuando son muchos (p. ej. la distribucion por estrella de satisfaccion). */
.report-summary {
  margin: 14px 22px 4px;
}
.report-summary p {
  font-weight: 600;
  margin: 4px 0;
}

/* ===========================================================================
   Centro de Reportes (llm_core/reports/index.html). Lanzador compacto AGRUPADO
   por categoria que ESCALA SOLO: la rejilla es data-driven (auto-fill, se
   reacomoda al agregar reportes o categorias) y un buscador en vivo + filtros
   por categoria permiten encontrar entre muchos. Filas de UNA sola linea con
   icono; la descripcion completa va en title= (tooltip al pasar el mouse).
   =========================================================================== */
.report-center {
  --modal-width: 1080px;
  position: relative;
}
.report-sprite {
  height: 0;
  position: absolute;
  width: 0;
}
.report-toolbar {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 14px;
}
.report-search {
  flex: 1 1 240px;
  position: relative;
}
.report-search > svg {
  color: var(--ul-muted);
  height: 17px;
  left: 11px;
  pointer-events: none;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 17px;
}
/* Solo lo especifico del buscador de reportes: sitio para el icono de lupa y el halo de foco.
   El borde/alto/radio/ancho vienen del contrato compartido con .record-search-input (arriba). */
.report-search input {
  font-size: 14px;
  padding-left: 34px;
}
.report-search input:focus {
  border-color: var(--ul-turquoise);
  box-shadow: 0 0 0 3px rgba(14, 239, 218, 0.25);
  outline: none;
}
.report-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.report-chip {
  background: var(--ul-white);
  border: 1px solid var(--ul-turquoise-dark);
  border-radius: var(--radius-pill);
  color: var(--ul-navy);
  cursor: pointer;
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  padding: 6px 13px;
}
.report-chip.is-on {
  background: var(--ul-navy);
  border-color: var(--ul-navy);
  color: var(--ul-turquoise);
}
.report-sections {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.report-cat-head {
  align-items: center;
  border-bottom: 1px solid var(--ul-border);
  display: flex;
  gap: 9px;
  margin-bottom: 8px;
  padding-bottom: 5px;
}
.report-cat-title {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin: 0 auto 0 0;
  text-transform: uppercase;
}
.report-cat-only {
  background: var(--ul-white);
  border: 1px solid var(--ul-border-strong);
  border-radius: var(--radius-pill);
  color: var(--ul-muted);
  font-size: 11.5px;
  font-weight: 500;
  padding: 1px 9px;
}
.report-cat-count {
  background: var(--ul-bg-tint);
  border-radius: var(--radius-pill);
  color: var(--ul-turquoise-dark);
  font-size: 11.5px;
  font-weight: 700;
  padding: 1px 9px;
}
.report-grid {
  display: grid;
  gap: 7px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.report-row {
  align-items: center;
  border-radius: var(--radius-md);
  display: flex;
  gap: 10px;
  min-width: 0;
  padding: 6px 8px;
  text-decoration: none;
}
.report-row:hover {
  background: var(--ul-bg-tint);
}
.report-ic {
  align-items: center;
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  color: var(--ul-turquoise-dark);
  display: flex;
  flex: 0 0 auto;
  height: 30px;
  justify-content: center;
  width: 30px;
}
.report-ic svg {
  height: 16px;
  width: 16px;
}
.report-row:hover .report-ic {
  background: var(--ul-navy);
  border-color: var(--ul-navy);
  color: var(--ul-turquoise);
}
.report-tx {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.report-name {
  color: var(--ul-navy);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.report-desc {
  color: var(--ul-muted);
  font-size: 11.5px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.report-empty {
  color: var(--ul-muted);
  font-size: 14px;
  padding: 24px;
  text-align: center;
}

/* Centrado vertical en las listas: el texto y los iconos de acciones quedan alineados
   aunque una fila sea alta (p. ej. descripcion o nombre en varias lineas). */
.ul-table-panel table td,
.llm-list table td {
  vertical-align: middle;
}

/* Celda de acciones con iconos: el <td> sigue siendo celda de tabla (vertical-align:middle
   centra los iconos aunque la fila sea alta por texto multilinea); los iconos van en linea,
   sin el hueco que deja el espacio en blanco entre etiquetas (font-size:0). Antes el td era
   display:flex, lo que anulaba el centrado vertical nativo de la tabla.
   `.ul-table-actions` tambien se reutiliza (fuera de tabla) como cuadro de icono suelto, p. ej.
   el boton "Descargar a Excel" de reporte.html/costs.html: el sticky/right y el fondo solo
   tienen sentido dentro de una celda, por eso van acotados a th/td y no a la clase base. */
.ul-table-actions {
  vertical-align: middle;
  white-space: nowrap;
}

/* El colapso del whitespace entre iconos (font-size:0) aplica SOLO a los CONTENEDORES de iconos:
   el td de fila y el span suelto de los reportes ("Descargar a Excel"). El th queda POR FUERA:
   contiene el rotulo visible "Acciones" y la clase base se lo volvia invisible (0px) en las 7
   pantallas con rotulo (hallazgo del review 2026-07-06). */
td.ul-table-actions,
span.ul-table-actions {
  font-size: 0;
}

th.ul-table-actions,
td.ul-table-actions {
  /* PEGADA (sticky) al borde derecho dentro de .ul-table-scroll: en tablas anchas con scroll
     horizontal, los iconos de accion deben verse siempre sin desplazarse (principio de UI
     "iconografia para las acciones"). */
  position: sticky;
  right: 0;
}

/* Fondo OPACO para no transparentar el contenido que pasa por debajo al hacer scroll: el th ya lo
   hereda de la regla central `th` (bg-tint) — duplicarlo aqui divergiria en silencio si el tema
   cambia; solo el td necesita el suyo. */
td.ul-table-actions {
  background: var(--ul-white);
}

/* Boton-icono de accion: identico al <a>, para acciones POST (<button> dentro de un <form>).
   Comparten el cuadro de 32px; el <button> resetea ademas sus estilos nativos de control. */
.ul-table-actions a,
.ul-table-actions button {
  align-items: center;
  border-radius: 8px;
  color: var(--ul-turquoise-dark);
  cursor: pointer;
  display: inline-flex;
  height: 32px;
  justify-content: center;
  text-decoration: none;
  transition: background 120ms ease, color 120ms ease;
  vertical-align: middle;
  width: 32px;
}

.ul-table-actions button {
  background: none;
  border: 0;
  font: inherit;
  min-height: 0;  /* anula el min-height:42px global de button para conservar el cuadro de 32px */
  padding: 0;
}

.ul-table-actions a + a {
  margin-left: 4px;
}

.ul-table-actions a:hover,
.ul-table-actions a:focus-visible,
.ul-table-actions button:hover,
.ul-table-actions button:focus-visible {
  background: var(--ul-bg-tint);
  color: var(--ul-navy);
}

.ul-table-actions a.is-danger,
.ul-table-actions button.is-danger {
  color: #b42318;
}

.ul-table-actions a.is-danger:hover,
.ul-table-actions a.is-danger:focus-visible,
.ul-table-actions button.is-danger:hover,
.ul-table-actions button.is-danger:focus-visible {
  background: #fdeceb;
}

/* UNA sola accion POST en una celda: el <form> que envuelve el boton-icono debe ser transparente
   al layout. Sin esto, la regla global form{} le aplica su recuadro (borde + sombra + padding 20px
   + margin 22px), que dibuja una caja inutil alrededor del unico icono (Principio 7) e infla el
   alto de cada fila (Principio 1). display:contents hace que el <button> participe DIRECTO en la
   celda. Generaliza a una accion lo que .ul-actions-group ya hace para varias. */
.ul-table-actions form {
  display: contents;
}

/* Varias acciones POST en una celda: agruparlas en un inline-flex con gap separa los iconos
   sin romper el centrado vertical nativo del <td>. Cada <form> va con display:contents
   (Principio 7: el envoltorio no debe crear caja) para que el <button> participe directo. */
.ul-actions-group {
  align-items: center;
  display: inline-flex;
  gap: 4px;
  vertical-align: middle;
}

.ul-actions-group > form {
  display: contents;
}

/* Celda de texto que se trunca con elipsis para mantener la fila en un solo renglon
   (Principio 1); el title del <span> muestra el texto completo al pasar el cursor. */
.ul-cell-trunc {
  display: inline-block;
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
  white-space: nowrap;
}

/* Form de cupo en la tabla de permisos: anula el recuadro/relleno que la regla global form{}
   aplica por defecto (borde + padding 20px + sombra), que inflaba la altura de cada fila y
   envolvia el campo y el boton en una tarjeta. */
.cupo-form {
  align-items: center;
  background: none;
  border: 0;
  box-shadow: none;
  display: flex;
  gap: 6px;
  margin: 0;
  padding: 0;
}

.cupo-form .cupo-input {
  min-height: 36px;
  text-align: center;
  width: 72px;
}

/* Boton de guardar reducido a un icono cuadrado (sustituye al boton de texto "Guardar"). */
.icon-save {
  align-items: center;
  background: var(--ul-navy);
  border-radius: 8px;
  color: var(--ul-turquoise);
  display: inline-flex;
  flex: 0 0 auto;
  height: 36px;
  justify-content: center;
  min-height: 0;
  padding: 0;
  width: 36px;
}

.icon-save:hover,
.icon-save:focus-visible {
  background: var(--ul-navy-deep);
}

.up-hint {
  color: var(--ul-muted);
  font-size: 14px;
  margin: 0;
  padding: 0 22px 14px;
}

/* Recarga de saldo (FR-101). Desglose de la cotizacion USD->COP: filas etiqueta/valor con el total
   resaltado; hereda el ancho del cuerpo del modal (sin padding lateral propio). */
.ul-quote {
  margin: 4px 22px 8px;
  border: 1px solid var(--ul-border);
  border-radius: 8px;
  overflow: hidden;
}
.ul-quote-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 14px;
  font-size: 14px;
  color: var(--ul-slate);
}
.ul-quote-row + .ul-quote-row {
  border-top: 1px solid var(--ul-border);
}
.ul-quote-total {
  background: var(--ul-bg-tint);
  font-size: 15px;
  font-weight: 700;
  color: var(--ul-navy);
}
.ul-form-error {
  color: #c0392b;
  font-size: 14px;
  margin: 0;
  padding: 0 22px 10px;
}
/* Fila de formulario con casilla: la etiqueta a la izquierda como el resto, el check alineado al
   inicio del campo (no estirado a todo el ancho como un input de texto). */
.ul-form-row--check input[type="checkbox"] {
  width: auto;
  justify-self: start;
}
/* Celda de tabla que trunca con ellipsis (nombre/correo/referencia largos): mantiene la fila de un
   solo renglon (principio de minimizar el scroll). El title del <td> muestra el valor completo. */
.ul-cell-ellipsis {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Franja para habilitar un proyecto nuevo, integrada en la tarjeta de permisos: comparte
   tarjeta con la tabla en vez de ser un bloque aparte. Anula el recuadro del form global. */
.perm-add-form {
  align-items: end;
  background: var(--ul-bg-tint);
  border: 0;
  border-bottom: 1px solid var(--ul-border);
  border-radius: 0;
  box-shadow: none;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin: 0;
  padding: 16px 22px;
}

.perm-add-field {
  display: grid;
  gap: 6px;
  margin: 0;
}

.perm-add-form label {
  font-size: 13px;
  margin: 0;
}

.perm-add-form select {
  min-width: 240px;
  width: auto;
}

.perm-add-form input[type="number"] {
  width: 130px;
}

.perm-add-form .primary-action {
  flex: 0 0 auto;
}

.perm-add-errors {
  color: #b42318;
  padding: 12px 22px 0;
}

/* --- Pantalla "Asignar proyectos a un usuario" (objectives/user_projects) -------------------
   Ajustes ACOTADOS a esta pantalla (clase .assign-projects en el <section>): no alteran otras
   pantallas. El desalineado del selector "Usuario" en paneles de tabla se resuelve de forma
   GENERICA en `.ul-table-panel > .record-selector-bar` (no aqui). */

/* Combos "Proyecto"/"Modelo" comodos: el min-width vivia sobre el <select> nativo, que el widget
   de busqueda oculta (por eso salian estrechos); aqui va sobre el campo VISIBLE, que ademas crece
   para repartir el ancho de la franja. El campo numerico y el boton conservan su tamano. */
.assign-projects .perm-add-combo {
  flex: 1 1 260px;
  min-width: 260px;
}

/* Filas de permiso compactas (minimizar el scroll vertical): menos relleno vertical y una sola
   linea. Nombre/modelo largos se recortan con ellipsis y muestran el valor completo en el title. */
.assign-projects table th,
.assign-projects table td {
  padding-bottom: 7px;
  padding-top: 7px;
}

.assign-projects td.assign-name,
.assign-projects td.assign-model {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Topes generosos: el nombre del proyecto (identidad de la fila) cabe completo con los datos
   actuales; el modelo, mas largo por incluir el proveedor, se recorta con ellipsis y su valor
   completo queda en el title (hover). No caben ambos enteros en un panel de 1280px con las otras
   dos columnas; priorizar el proyecto y dar tooltip al modelo es el mejor equilibrio sin ensanchar
   el panel (decision del responsable) ni envolver texto (principio de minimizar scroll vertical). */
.assign-projects td.assign-name {
  max-width: 440px;
}

.assign-projects td.assign-model {
  max-width: 480px;
}

/* Columna "Entrevistas creadas": encabezado y valor centrados. */
.assign-projects table th.col-num,
.assign-projects table td.col-num {
  text-align: center;
}

/* Paginador alineado con el inset del panel (no pegado al borde). */
.assign-projects .pager {
  padding: 0 22px 14px;
}

/* Pagina Importar/Exportar: boton de descarga por entidad y etiqueta de pendiente. */
/* Boton-icono de exportar/importar: accion de fila con ICONO, no texto (principio de UI #3),
   consistente con exports/list y deliverables. Cuadro de 26px como las demas acciones de tabla; el
   <button> resetea sus estilos nativos de control. Los rotulos van en aria-label/title. */
.ie-btn {
  align-items: center;
  background: none;
  border: 0;
  border-radius: 8px;
  color: var(--ul-turquoise-dark);
  cursor: pointer;
  display: inline-flex;
  height: 26px;
  justify-content: center;
  padding: 0;
  text-decoration: none;
  width: 26px;
}

.ie-btn:hover,
.ie-btn:focus-visible {
  background: var(--ul-bg-tint);
  color: var(--ul-navy);
}

.ie-soon {
  color: var(--ul-muted);
  font-size: 13px;
  font-style: italic;
}

/* Pildora compacta de estado de una exportacion en segundo plano (Principio 1: el estado va inline,
   sin alargar la fila). Pendiente/Procesando en tinte neutro, Listo en verde, Error en el rojo que
   ya usa .is-danger en las acciones de tabla. */
/* Base compartida de los pills de estado (exportaciones y registro de proteccion de datos):
   una sola geometria que mantener (principio UI #5/#6); cada dominio aporta solo sus colores. */
.export-pill,
.pd-pill {
  border-radius: 999px;
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  padding: 2px 10px;
  white-space: nowrap;
}

.export-pill--pendiente,
.export-pill--procesando {
  background: var(--ul-bg-tint);
  color: var(--ul-turquoise-dark);
}

.export-pill--listo {
  background: #e7f7ef;
  color: #1a7f4b;
}

.export-pill--error {
  background: #fdeceb;
  color: #b42318;
}

/* Pildora generica de estado/situacion para tablas admin (estado de la entrevista; Activa/Eliminada).
   Reutilizable: tono neutro por defecto, verde para "activa", rojo para "eliminada". */
.estado-pill {
  background: var(--ul-bg-soft);
  border-radius: 999px;
  color: var(--ul-muted);
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 11px;
  white-space: nowrap;
}

.estado-pill--on {
  background: #e7f7ef;
  color: #1a7f4b;
}

.estado-pill--off {
  background: #fdeceb;
  color: #b42318;
}

/* Lista de Super Administradores en la ficha del cliente (System Manager): cada admin en UN solo
   renglon (Principio 1) — nombre con elipsis, correo y WhatsApp atenuados, estado como pill y el
   icono de editar (Principio 3) alineado a la derecha. La uniformidad (alto del icono, gap) vive
   aqui, no por elemento (Principio 6). */
.sm-admin-list {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
}

.sm-admin-row {
  align-items: center;
  border-bottom: 1px solid var(--ul-border, #e5e7eb);
  display: flex;
  gap: 12px;
  min-height: 38px;
}

.sm-admin-row:last-child {
  border-bottom: 0;
}

.sm-admin-name {
  font-weight: 600;
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sm-admin-meta {
  color: var(--ul-muted);
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* El correo se queda con el espacio sobrante; el resto no se estira. */
.sm-admin-row .sm-admin-meta:first-of-type {
  flex: 1 1 auto;
  min-width: 0;
}

/* Icono de editar: mismo cuadro de 32px y tono que las acciones de tabla, empujado a la derecha. */
.sm-admin-edit {
  align-items: center;
  border-radius: 8px;
  color: var(--ul-turquoise-dark);
  display: inline-flex;
  flex: none;
  height: 32px;
  justify-content: center;
  margin-left: auto;
  text-decoration: none;
  transition: background 120ms ease, color 120ms ease;
  width: 32px;
}

.sm-admin-edit:hover,
.sm-admin-edit:focus-visible {
  background: var(--ul-bg-tint);
  color: var(--ul-navy);
}

/* Ficha de SOLO DATOS (consultar entrevista): tabla clave/valor de dos columnas, etiqueta a la
   izquierda en tono atenuado, valor a la derecha. Filas separadas por una linea sutil. */
.ul-detail {
  border-collapse: collapse;
  width: 100%;
}

.ul-detail th {
  color: var(--ul-muted);
  font-weight: 600;
  padding: 7px 14px 7px 0;
  text-align: left;
  vertical-align: top;
  white-space: nowrap;
  width: 38%;
}

.ul-detail td {
  padding: 7px 0;
  vertical-align: top;
}

.ul-detail tr + tr th,
.ul-detail tr + tr td {
  border-top: 1px solid var(--ul-border, rgba(0, 0, 0, 0.08));
}

/* Pagina Importar (carga masiva): columnas esperadas y resumen del resultado. */
.import-cols {
  background: var(--ul-bg-soft);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  font-family: var(--font-display);
  letter-spacing: 0.02em;
  margin: 4px 0 0;
  padding: 8px 12px;
}

.import-result {
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-left: 4px solid var(--ul-turquoise);
  border-radius: var(--radius-md);
  margin-top: 20px;
  padding: 14px 16px;
}

.import-result.is-error {
  border-left-color: var(--color-error);
}

.import-result h3 {
  color: var(--ul-navy);
  font-family: var(--font-display);
  margin: 0 0 8px;
}

.import-result ul {
  margin: 8px 0 0;
  padding-left: 20px;
}

.import-result.is-error li {
  color: var(--color-error);
}

/* Previsualizacion de los primeros registros creados por una carga masiva. El scroll horizontal
   dentro del panel lo da la clase generica .ul-table-scroll (la plantilla combina ambas); el ADN
   de la tabla (bordes, th tint/navy) viene de las reglas base `table`/`th, td` — aqui SOLO los
   deltas compactos de la muestra (principio de UI: minimizar alto; una fila = un renglon). */
.import-muestra {
  margin-top: 8px;
}

.import-muestra table {
  font-size: 0.9rem;
}

.import-muestra th,
.import-muestra td {
  padding: 5px 10px;
  white-space: nowrap;
}

.ul-warning {
  background: #fff7e6;
  border: 1px solid #f2c36b;
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  font-weight: 700;
  margin: 0 0 18px;
  padding: 12px 14px;
}

.danger-action {
  background: #d94343;
  color: #fff;
}

.ul-auth-digits {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-bottom: 22px;
}

.ul-auth-digit {
  background: var(--ul-bg-soft);
  border: 1.5px solid var(--ul-border-strong);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 700;
  height: 60px;
  text-align: center;
  width: 52px;
}

.ul-auth-digit:focus {
  border-color: var(--ul-turquoise);
  box-shadow: 0 0 0 3px rgba(14, 239, 218, 0.15);
}

.project-card-list {
  display: grid;
  gap: 10px;
  margin: 0 0 24px;
}

.project-choice {
  align-items: center;
  background: var(--ul-bg-tint);
  border: 1.5px solid var(--ul-turquoise);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  display: flex;
  font-weight: 700;
  justify-content: space-between;
  min-height: 46px;
  padding: 0 14px;
  text-decoration: none;
}

/* Iconos de accion en filas (editar/eliminar), reutilizable. El reset de min-height/padding
   neutraliza la regla global de `button` (que con box-sizing:border-box colapsaria el SVG). */
.row-action {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  min-height: 0;
  padding: 0;
  border-radius: 8px;
  background: var(--ul-white);
  font-weight: 400;
  cursor: pointer;
  text-decoration: none;
}

.row-action--edit {
  border: 1.5px solid var(--ul-turquoise-dark);
  color: var(--ul-navy);
}

.row-action--delete {
  border: 1.5px solid #e0a3a3;
  color: #b91c1c;
}

body.chat-page {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  min-height: 100vh;
  overflow: hidden;
}

body.chat-page .app-header {
  flex: 0 0 auto;
}

body.chat-page:not(.auth-page) .page-shell {
  display: grid;
  flex: 1 1 0;
  gap: 6px;
  /* 2 filas (FR-093 §4.9): ventana de conversacion (1fr) + compositor (auto). El contexto de la
     entrevista (proyecto/entrevista) ya NO vive aqui: se movio al ENCABEZADO (.header-context), para
     que no aparezca dentro de la ventana del dialogo. */
  grid-template-rows: minmax(0, 1fr) auto;
  height: auto;
  min-height: 0;
  overflow: hidden;
  /* Padding vertical compacto (principio UI #1: minimizar el scroll): la ventana de conversacion
     gana alto y la franja entre el header y el chat, y bajo el compositor, no desperdicia espacio. */
  padding: 10px 14px;
}

.chat-panel {
  background: rgba(244, 246, 251, 0.96);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 13px;
  height: 100%;
  justify-content: flex-start;
  margin: 0;
  min-height: 0;
  overflow: hidden auto;
  padding: 18px 24px;
  position: relative;
  z-index: 2;
}

.chat-message {
  font-size: var(--ul-chat-font-size);
  /* interlineado muy compacto: line-height 1.1 a peticion del responsable, para
     maximizar los renglones visibles en la ventana de la conversacion */
  line-height: 1.1;
  padding: 11px 17px;
}

.chat-status-notice {
  align-self: center;
  background: rgba(14, 239, 218, 0.12);
  border: 1px solid rgba(14, 239, 218, 0.46);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  font-weight: 700;
  margin: 0 auto 10px;
  max-width: min(760px, 100%);
  padding: 12px 16px;
  text-align: center;
}

/* Aviso de respuesta interrumpida tras agotar los reintentos automaticos (resiliencia del chat):
   mismo lenguaje visual que chat-status-notice, con un boton para reintentar a mano. */
.chat-retry-notice {
  align-items: center;
  align-self: center;
  background: rgba(14, 239, 218, 0.12);
  border: 1px solid rgba(14, 239, 218, 0.46);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  display: flex;
  font-weight: 600;
  gap: 12px;
  margin: 0 auto 10px;
  max-width: min(620px, 100%);
  padding: 10px 14px;
}

.chat-retry-button {
  background: var(--ul-turquoise-dark);
  border: 0;
  border-radius: var(--radius-pill);
  color: #fff;
  cursor: pointer;
  flex: 0 0 auto;
  font-weight: 700;
  padding: 6px 14px;
}

.chat-retry-button:hover,
.chat-retry-button:focus-visible {
  background: var(--ul-navy);
}

/* Avance de la entrevista (FR-084d): texto compacto "Progreso: NN%" en la barra del compositor,
   junto al boton Enviar. `margin-left:auto` empuja este texto y el boton a la derecha (y mantiene el
   boton alineado a la derecha aunque el texto este vacio, antes del primer reporte). El numero lo
   auto-reporta la IA y deriva de la serie por mensaje (porcentaje_completado, fuente unica); vacio
   hasta el primer reporte (no se muestra un 0% que desmotive). */
.chat-progress-text {
  margin-left: auto;
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 700;
  color: var(--ul-navy);
}

.chat-message-content p {
  /* espacio entre parrafos reducido 30% (8px -> 5.6px) para mas densidad */
  margin: 0 0 5.6px;
}

.chat-message-content p:last-child,
.chat-message-content ul:last-child,
.chat-message-content ol:last-child {
  margin-bottom: 0;
}

.chat-message-content ul,
.chat-message-content ol {
  /* mismo ritmo que los parrafos: 30% menos (8px -> 5.6px) */
  margin: 5.6px 0;
  padding-left: 22px;
}

.chat-message-content li + li {
  margin-top: 4px;
}

.chat-md-heading {
  color: var(--ul-navy);
  font-weight: 700;
}

/* Enlaces clicables saneados (solo mensajes de la IA). El icono de "enlace externo" se pinta con un
   pseudo-elemento para no ampliar la lista blanca de bleach con etiquetas extra (SVG/span). */
.chat-message-content a.chat-link {
  color: var(--ul-turquoise-dark);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}

.chat-message-content a.chat-link:hover,
.chat-message-content a.chat-link:focus-visible {
  color: var(--ul-navy);
}

.chat-message-content a.chat-link::after {
  content: "\2197"; /* ↗ flecha de enlace externo */
  display: inline-block;
  margin-left: 2px;
  font-size: 0.82em;
  font-weight: 700;
  text-decoration: none;
  vertical-align: baseline;
}

/* Enlaces de MEDIO (imagen/video/audio/PDF): icono de lupa/vista-previa (SVG via mask, nitido y sin
   ampliar la lista blanca de bleach) en vez de la flecha de enlace externo: comunican "se abre aqui
   en una vista previa", no "te lleva fuera". */
.chat-message-content a.chat-link-media::after {
  content: "";
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M21 21l-5-5'/%3E%3C/svg%3E") no-repeat center / contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M21 21l-5-5'/%3E%3C/svg%3E") no-repeat center / contain;
  background-color: currentColor;
  width: 0.92em;
  height: 0.92em;
  margin-left: 3px;
  vertical-align: -0.12em;
}

/* Chips de respuesta rapida (Fase 3): botones tocables que la IA ofrece en su mensaje. Tocar uno
   envia su texto como respuesta del entrevistado (alto valor en movil: evita teclear). */
.chat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.chat-chip {
  border: 1.5px solid var(--ul-turquoise);
  background: var(--ul-bg-tint);
  color: var(--ul-navy-deep);
  border-radius: var(--radius-pill);
  padding: 7px 16px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  min-height: 36px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}

.chat-chip:hover:not(:disabled),
.chat-chip:focus-visible {
  background: var(--ul-turquoise-dark);
  border-color: var(--ul-turquoise-dark);
  color: #fff;
}

.chat-chip:focus-visible {
  outline: 2px solid var(--ul-turquoise-dark);
  outline-offset: 2px;
}

/* Chips ya usados o de mensajes anteriores: inertes (no reenvian respuestas viejas). */
.chat-chip:disabled,
.chat-chip-spent {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}

/* Vista previa de adjuntos (Fase 5): el archivo subido se muestra como un chip clicable; al abrirlo
   (<details>) se ve el texto que la IA recibio. Cierra el circulo visual de lo que se envio. */
.chat-attach {
  margin: 6px 0;
}

.chat-attach-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  max-width: 100%;
  padding: 5px 13px;
  background: var(--ul-bg-tint);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-pill);
  color: var(--ul-navy);
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  list-style: none; /* oculta el triangulo nativo del <summary> */
}

.chat-attach-chip::-webkit-details-marker {
  display: none;
}

.chat-attach-chip:hover,
.chat-attach-chip:focus-visible {
  background: var(--ul-bg-soft);
  border-color: var(--ul-turquoise);
}

.chat-attach-icon {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 8.5l-9.2 9.2a4 4 0 0 1-5.7-5.7l9.2-9.2a2.5 2.5 0 0 1 3.5 3.5l-8.5 8.5a1 1 0 0 1-1.4-1.4l7.8-7.8'/%3E%3C/svg%3E") no-repeat center / contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 8.5l-9.2 9.2a4 4 0 0 1-5.7-5.7l9.2-9.2a2.5 2.5 0 0 1 3.5 3.5l-8.5 8.5a1 1 0 0 1-1.4-1.4l7.8-7.8'/%3E%3C/svg%3E") no-repeat center / contain;
}

.chat-attach-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-attach-body {
  margin-top: 6px;
  padding: 8px 12px;
  /* texto extraido grande (p. ej. un PDF completo): se acota con scroll INTERNO en vez de desbordar
     el panel (Principio de UI: scroll dentro del contenedor antes que romper el layout). */
  max-height: 320px;
  overflow-y: auto;
  background: rgba(255, 255, 255, 0.55);
  border-left: 3px solid var(--ul-turquoise);
  border-radius: var(--radius-md);
  font-size: 0.95em;
}

.chat-attach-body > :last-child {
  margin-bottom: 0;
}

/* Tarjeta de confirmacion de datos (Fase 6): cuando la IA resume lo capturado, se muestra como una
   tarjeta estructurada (titulo + pares clave/valor) en vez de un parrafo. */
.chat-card {
  margin: 8px 0;
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-md);
  background: var(--ul-bg-soft);
  overflow: hidden;
}

.chat-card-title {
  padding: 8px 14px;
  background: var(--ul-navy);
  color: var(--ul-on-navy);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.chat-card-fields {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin: 0;
  padding: 9px 14px 11px;
}

.chat-card-row {
  display: grid;
  grid-template-columns: minmax(90px, 32%) 1fr;
  gap: 10px;
  align-items: baseline;
}

.chat-card-row dt {
  margin: 0;
  color: var(--ul-muted);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.chat-card-row dd {
  margin: 0;
  color: var(--ul-navy-deep);
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* En movil la columna util es estrecha: apilar clave sobre valor en vez de apretar el valor. */
@media (max-width: 480px) {
  .chat-card-row {
    grid-template-columns: 1fr;
    gap: 1px;
  }
}

/* Cajas de intencion comunicativa (TEMA #6): la IA marca un mensaje breve segun su INTENCION
   (advertencia/error/nota) y se resalta como caja de marca, con la MISMA taxonomia que el Word.
   El ROL de color (clase .chat-callout-<rol>) define la barra lateral, el icono y el tinte de fondo;
   todos derivados de tokens UL (el tinte = el mismo color a baja opacidad). La etiqueta va en navy
   para legibilidad. */
.chat-callout {
  margin: 8px 0;
  padding: 8px 13px;
  border: 1px solid var(--ul-border);
  border-left: 4px solid var(--callout-accent, var(--ul-border-strong));
  border-radius: var(--radius-md);
  background: var(--callout-bg, var(--ul-bg-soft));
}

.chat-callout-head {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 3px;
  color: var(--ul-navy);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.chat-callout-icon {
  flex: 0 0 auto;
  color: var(--callout-accent, var(--ul-muted));
  font-size: 15px;
  line-height: 1;
}

.chat-callout-body {
  font-size: 0.97em;
  /* un token largo sin espacios (p. ej. una URL o identificador) se parte en vez de romper la caja
     y empujar el ancho del panel (Principio de UI: no desbordar; igual que .chat-link/.chat-card dd). */
  overflow-wrap: anywhere;
}

/* El primer/ultimo bloque del cuerpo no agrega margen extra (la caja ya tiene su padding). */
.chat-callout-body > :first-child {
  margin-top: 0;
}

.chat-callout-body > :last-child {
  margin-bottom: 0;
}

.chat-callout-warning {
  --callout-accent: var(--ul-yellow);
  --callout-bg: rgba(244, 169, 69, 0.12);
}

.chat-callout-danger {
  --callout-accent: var(--color-error);
  --callout-bg: rgba(224, 85, 85, 0.1);
}

.chat-callout-neutral {
  --callout-accent: var(--ul-muted);
  --callout-bg: var(--ul-bg-soft);
}

/* --- Pulido (Fase 7): codigo, tablas, copiar, marca de tiempo, agrupacion --- */

/* Bloque de codigo con boton "copiar". */
.chat-code {
  position: relative;
  margin: 8px 0;
}

.chat-code pre {
  margin: 0;
  padding: 12px 14px;
  background: var(--ul-navy-deep);
  color: #e8eefc;
  border-radius: var(--radius-md);
  overflow-x: auto;
  font-family: ui-monospace, "Cascadia Code", "SF Mono", Consolas, monospace;
  font-size: 13px;
  line-height: 1.45;
}

.chat-code code {
  font-family: inherit;
  white-space: pre;
}

/* Codigo en linea `...` (no el bloque cercado): monospace con un fondo sutil. El contenido va
   literal (sin cursiva/negrita); los guiones bajos de un snake_case se conservan. */
.chat-message-content code {
  font-family: ui-monospace, "Cascadia Code", "SF Mono", Consolas, monospace;
  font-size: 0.92em;
  background: rgba(14, 239, 218, 0.12);
  border-radius: 4px;
  padding: 1px 5px;
}

/* El bloque cercado conserva su propio estilo (sin el fondo/padding del inline). */
.chat-message-content .chat-code code {
  background: none;
  border-radius: 0;
  padding: 0;
  font-size: 13px;
}

/* Cita en bloque markdown (`> ...`): barra lateral turquesa + sangria; el contenido va sin el `>`. */
.chat-message-content blockquote {
  margin: 5.6px 0;
  padding: 2px 0 2px 12px;
  border-left: 3px solid var(--ul-turquoise-dark);
  color: var(--ul-navy);
  font-style: italic;
}

.chat-copy {
  border: 0;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  cursor: pointer;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
}

.chat-code .chat-copy {
  position: absolute;
  top: 8px;
  right: 8px;
}

.chat-copy:hover,
.chat-copy:focus-visible {
  background: rgba(255, 255, 255, 0.3);
}

.chat-copy.is-copied {
  background: var(--ul-turquoise-dark);
}

/* Tablas: scroll horizontal DENTRO del panel antes que desbordar (Principio de UI #2). */
.chat-table-wrap {
  margin: 8px 0;
  overflow-x: auto;
}

.chat-table {
  border-collapse: collapse;
  font-size: 13px;
  min-width: 100%;
}

.chat-table th,
.chat-table td {
  border: 1px solid var(--ul-border);
  padding: 6px 10px;
  text-align: left;
  white-space: nowrap;
}

.chat-table th {
  background: var(--ul-bg-tint);
  color: var(--ul-navy);
  font-weight: 700;
}

/* Marca de tiempo + "copiar mensaje": fila revelada al pasar el cursor (sin robar scroll en reposo). */
.chat-message-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 140ms ease, opacity 140ms ease, margin-top 140ms ease;
}

.chat-message:hover .chat-message-meta,
.chat-message:focus-within .chat-message-meta,
.chat-message.has-feedback .chat-message-meta {
  max-height: 40px;
  margin-top: 5px;
  opacity: 1;
}

.chat-message-user .chat-message-meta {
  justify-content: flex-end;
}

.chat-time {
  color: var(--ul-muted);
  font-size: 11px;
}

.chat-message-meta .chat-copy {
  background: var(--ul-bg-soft);
  color: var(--ul-navy);
}

.chat-message-meta .chat-copy:hover,
.chat-message-meta .chat-copy:focus-visible {
  background: var(--ul-bg-tint);
}

@media (prefers-reduced-motion: reduce) {
  .chat-message-meta {
    transition: none;
  }
}

/* Agrupar mensajes seguidos del mismo emisor: menos separacion y esquina "encadenada". */
article.chat-message-ai + article.chat-message-ai,
article.chat-message-user + article.chat-message-user {
  margin-top: -8px;
}

article.chat-message-ai + article.chat-message-ai {
  border-top-left-radius: 6px;
}

article.chat-message-user + article.chat-message-user {
  border-top-right-radius: 6px;
}

/* Lightbox: UN solo modal generico para imagen/video/audio/PDF (clic-para-abrir). */
body.sc-lightbox-open {
  overflow: hidden;
}

.sc-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(16, 0, 70, 0.74);
}

.sc-lightbox-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-width: min(1100px, 96vw);
  max-height: 92vh;
}

.sc-lightbox-media {
  max-width: 100%;
  max-height: 80vh;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  background: #fff;
}

iframe.sc-lightbox-media {
  width: min(1000px, 92vw);
  height: 80vh;
  border: 0;
}

audio.sc-lightbox-media {
  width: min(560px, 90vw);
  box-shadow: none;
}

.sc-lightbox-close {
  position: absolute;
  top: -16px;
  right: -16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: #fff;
  color: var(--ul-navy);
  box-shadow: var(--shadow-md);
  cursor: pointer;
}

.sc-lightbox-close:hover,
.sc-lightbox-close:focus-visible {
  background: var(--ul-bg-tint);
  color: var(--ul-turquoise-dark);
}

.sc-lightbox-newtab {
  color: #fff;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

@media (max-width: 640px) {
  .sc-lightbox {
    padding: 12px;
  }
  /* En movil el boton de cerrar va DENTRO del panel (las esquinas negativas se saldrian). */
  .sc-lightbox-close {
    top: 6px;
    right: 6px;
  }
  .sc-lightbox-media {
    max-height: 74vh;
  }
  iframe.sc-lightbox-media {
    height: 74vh;
  }
}

.chat-message-ai {
  align-self: flex-start;
  background: #fff;
  border: 1px solid var(--ul-border);
  border-radius: 4px 16px 16px 16px;
  box-shadow: var(--shadow-sm);
  color: var(--ul-slate);
  max-width: 85%;
}

.chat-message-user {
  align-self: flex-end;
  background: var(--ul-bg-tint);
  border: 1.5px solid var(--ul-turquoise);
  border-radius: 16px 4px 16px 16px;
  color: var(--ul-navy-deep);
  max-width: 85%;
}

body.chat-page:not(.auth-page) .page-shell > form.chat-input-bar {
  align-items: stretch;
  background: #fff;
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  max-width: none;
  min-height: 64px;
  /* min-width:0 evita que el min-content de la barra (con muchos chips de adjuntos) ensanche el
     form mas alla del ancho disponible: asi los chips hacen scroll en su zona y "Enviar" no se sale
     de la pantalla. Sin esto, un flex-item toma su min-content como ancho minimo. */
  min-width: 0;
  padding: 10px 14px;
  position: relative;
  width: 100%;
  z-index: 2;
}

body.chat-page:not(.auth-page) .page-shell > form.chat-input-bar.is-disabled {
  opacity: 0.78;
}

.chat-input-bar .spellcheck-input {
  flex: 1 1 auto;
  min-height: 0;
}

.chat-input-toolbar {
  align-items: center;
  display: flex;
  flex: 0 0 auto;
  gap: 12px;
  justify-content: flex-start;
  min-width: 0;
}

/* El boton Enviar queda a la derecha gracias al `margin-left:auto` de `.chat-progress-text`, que va
   justo antes (y permanece aunque el texto de avance este vacio). */

#attach-button {
  background: var(--ul-bg-tint);
  color: var(--ul-turquoise-dark);
  flex-basis: 42px;
  font-size: 26px;
  font-weight: 800;
  height: 42px;
  line-height: 1;
  transition: background 120ms ease, color 120ms ease;
  width: 42px;
}

#attach-button:hover:not(:disabled),
#attach-button:focus-visible {
  background: var(--ul-turquoise-dark);
  color: #fff;
}

.icon-button.is-busy {
  cursor: progress;
  opacity: 0.55;
}

/* Comandos del usuario (FR-097 c): el rayo abre un popover ANCLADO a su icono, encima de la barra
   de escritura. Reusa los tokens de superficie/borde del sistema; no crea contenedores sin funcion. */
.chat-commands {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
}

/* El atributo `hidden` debe ganar al `display:flex` de abajo (si no, menu y paneles salen SIEMPRE
   visibles). Misma cura que `#messages[hidden]` en el chat. */
.chat-commands-menu[hidden],
.chat-commands-panel[hidden] {
  display: none !important;
}

.chat-commands-menu {
  background: var(--ul-surface, #fff);
  border: 1px solid var(--ul-turquoise-dark);
  border-radius: var(--radius-md);
  bottom: calc(100% + 8px);
  box-shadow: 0 12px 30px rgba(7, 17, 77, 0.18);
  display: flex;
  flex-direction: column;
  gap: 8px;
  left: 0;
  min-width: 320px;
  max-width: min(92vw, 420px);
  /* Con poco alto visible (teclado en pantalla, apaisado) float_fit.js le pone tope de alto
     (capUp) y el exceso scrollea aqui adentro en vez de pasar el techo recortado del chat. */
  overflow-y: auto;
  padding: 14px;
  position: absolute;
  z-index: 20;
}

/* Encabezado de MENU (no de pantalla): discreto, en mayusculas, para que los comandos sean lo
   protagonico del popover. */
.chat-commands-title {
  color: var(--ul-muted);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  margin: 0 0 2px;
  text-transform: uppercase;
}

.chat-commands-item {
  align-items: center;
  background: var(--ul-bg-soft);
  border: 0;
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  cursor: pointer;
  display: flex;
  font: inherit;
  gap: 9px;
  padding: 9px 12px;
  text-align: left;
}

.chat-commands-item svg {
  flex: 0 0 auto;
}

/* El comando ACTIVO (su panel esta abierto) conserva el mismo resaltado del hover: se lee de cual
   comando es el panel de abajo. */
.chat-commands-item:hover,
.chat-commands-item:focus-visible,
.chat-commands-item.is-active {
  background: var(--ul-turquoise-dark);
  color: #fff;
}

.chat-commands-panel {
  border-top: 1px solid var(--ul-border, #e4e7ec);
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
  padding-top: 10px;
}

/* Con el ancestro .chat-commands-menu en el selector: los paneles viven DENTRO del form
   .chat-input-bar, cuyo reset de textarea (border 0, fondo transparente, mas abajo en este
   archivo) ganaria por orden a igual especificidad y dejaria este textarea invisible. */
.chat-commands-menu .chat-commands-panel textarea {
  background: var(--ul-white);
  border: 1.5px solid var(--ul-turquoise-dark);
  border-radius: var(--radius-md);
  font: inherit;
  font-size: 14px;
  padding: 8px 10px;
  resize: vertical;
  width: 100%;
}

.chat-commands-hint {
  color: var(--ul-muted);
  font-size: 13px;
  margin: 0;
}

.chat-commands-actions {
  display: flex;
  justify-content: flex-end;
}

.chat-commands-error {
  color: var(--ul-danger, #c0392b);
  font-size: 13px;
  margin: 0;
}

/* Confirmacion de guardado (comandos.js): el boton del panel pasa un instante al verde de exito
   del sistema (mismo par de colores de .estado-pill--on) antes de cerrarse el popover. */
.chat-commands-actions .primary-action.is-saved,
.chat-commands-actions .primary-action.is-saved:disabled {
  background: #e7f7ef;
  color: #1a7f4b;
  opacity: 1;
}

.chat-input-bar textarea {
  background: transparent;
  border: 0;
  box-shadow: none;
  color: var(--ul-navy-deep);
  display: block;
  font-family: inherit;
  font-size: var(--ul-chat-font-size);
  font-weight: 400;
  line-height: 1.45;
  min-width: 0;
  max-height: 40vh;
  /* Reposo = 2 renglones (principio UI #1) + 8px de padding border-box, DERIVADO del tamano
     efectivo de letra (FR-096). Dos declaraciones en cascada: la primera (var * line-height 1.45 *
     2) es el respaldo de soporte amplio; la segunda (`2lh` = line-height computado) la reemplaza en
     navegadores modernos y ademas sigue sola cualquier cambio futuro del line-height. Si el usuario
     escribe mas, el textarea crece solo hasta max-height (auto-grow en chat.js). */
  min-height: calc(var(--ul-chat-font-size) * 2.9 + 8px);
  min-height: calc(2lh + 8px);
  overflow-y: auto;
  padding: 4px 2px;
  position: relative;
  resize: none;
  z-index: 2;
  width: 100%;
}

.chat-input-bar textarea:focus {
  box-shadow: none;
}

.spellcheck-input {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 160px;
  position: relative;
}

.icon-button {
  align-items: center;
  background: var(--ul-bg-soft);
  border: 0;
  border-radius: 50%;
  color: var(--ul-navy);
  display: inline-flex;
  height: 38px;
  flex: 0 0 38px;
  justify-content: center;
  min-height: 0;
  padding: 0;
  width: 38px;
}

/* Enviar = boton circular con una flecha (ya no la palabra "Enviar"): mismo relleno navy de
   .primary-action, pero redondo y del MISMO tamano (38px) que sus vecinos .icon-button (adjuntar,
   microfono, comandos) de la barra, para que el grupo sea uniforme (Principio de UI #6). Selector propio
   de la pantalla de entrevista. */
.send-button {
  border-radius: 50%;
  flex: 0 0 38px;
  height: 38px;
  min-height: 38px;
  padding: 0;
  width: 38px;
}

.send-button svg {
  height: 20px;
  width: 20px;
}

/* Un boton de enviar deshabilitado (mientras se transmite un turno, o mientras se PREPARA el documento
   en el cierre) debe VERSE deshabilitado. Sin esto se veia activo y, al no responder al clic, el chat
   "parecia roto" (justo la confusion del cierre lento). Solucion generica: cualquier :disabled se atenua
   y muestra el cursor de no permitido, en todos los estados sin casos especiales. */
.send-button:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

/* Utilidad: solo para lectores de pantalla (oculto visualmente, presente en el arbol a11y). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Adjuntos APILADOS por enviar: ocupan el espacio libre entre el microfono y "Enviar".
   `flex: 1 1 0` (base 0, no el ancho del contenido) + `min-width: 0` + scroll interno aseguran que,
   con muchos archivos, los chips se desplacen DENTRO de su zona y NUNCA empujen el boton "Enviar"
   fuera de la pantalla (critico en movil). */
.attach-chips {
  align-items: center;
  display: flex;
  flex: 1 1 0;
  gap: 8px;
  min-width: 0;
  overflow-x: auto;
  padding: 2px 0;
  scrollbar-width: thin;
}

.attach-chips:empty {
  display: none;
}

.attach-chip {
  align-items: center;
  background: var(--ul-bg-tint);
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-pill);
  color: var(--ul-navy);
  display: inline-flex;
  flex: 0 0 auto;
  font-size: 13px;
  gap: 6px;
  height: 30px;
  max-width: 220px;
  padding: 0 6px 0 12px;
}

.attach-chip-name {
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.attach-chip-size {
  color: var(--ul-muted);
  flex: 0 0 auto;
  font-size: 11px;
}

.attach-chip-remove {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: var(--ul-muted);
  cursor: pointer;
  display: inline-flex;
  flex: 0 0 auto;
  height: 20px;
  justify-content: center;
  padding: 0;
  width: 20px;
}

.attach-chip-remove:hover:not(:disabled) {
  background: rgba(16, 0, 70, 0.08);
  color: var(--ul-navy);
}

.attach-chip-remove:disabled {
  cursor: progress;
  opacity: 0.5;
}

.attach-chip.has-error {
  background: #fdeceb;
  border-color: var(--color-error);
  /* Rojo mas oscuro que --color-error para el TEXTO: sobre el fondo claro #fdeceb cumple el
     contraste AA (>=4.5:1) del nombre y el tamano del archivo en error. */
  color: #b00020;
}

.attach-chip.has-error .attach-chip-size {
  color: #b00020;
}

.chat-processing {
  align-self: center;
  background: var(--ul-bg-soft);
  border-radius: var(--radius-pill);
  color: var(--ul-navy);
  font-size: 14px;
  font-style: italic;
  margin: 8px auto;
  max-width: 90%;
  padding: 7px 18px;
  width: fit-content;
  animation: chat-processing-pulse 1.2s ease-in-out infinite;
}

@keyframes chat-processing-pulse {
  0%,
  100% {
    opacity: 0.55;
  }
  50% {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat-processing {
    animation: none;
    opacity: 0.85;
  }
}

#voice-input {
  align-items: center;
  display: flex;
  flex: 0 0 auto;
  gap: 8px;
}

#voice-record {
  background: var(--ul-bg-tint);
  color: var(--ul-turquoise-dark);
}

#voice-record:hover:not(:disabled):not(.is-recording),
#voice-record:focus-visible:not(.is-recording) {
  background: var(--ul-turquoise-dark);
  color: #fff;
}

/* Grabando: el boton se vuelve un circulo AZUL de marca con 3 barras blancas que oscilan como una
   onda de audio, mas un anillo de pulso que se expande. Estado inequivoco para que el usuario no
   dude de que se esta grabando (el rojo anterior se confundia con un error). El clic de nuevo
   detiene la grabacion (voice.js). */
#voice-record.is-recording {
  animation: voice-recording-pulse 1.5s ease-out infinite;
  background: var(--ul-navy);
  color: var(--ul-on-navy);
}

#voice-record.is-recording .voice-mic-icon {
  display: none;
}

#voice-record.is-recording .voice-bars {
  display: inline-flex;
}

#voice-record.is-transcribing {
  color: var(--ul-turquoise);
  opacity: 0.8;
}

/* Las 3 barras de la onda (ocultas salvo al grabar). `currentColor` = blanco mientras se graba. */
.voice-bars {
  align-items: center;
  display: none;
  gap: 2.5px;
  height: 15px;
}

.voice-bars i {
  animation: voice-wave 0.9s ease-in-out infinite;
  background: currentColor;
  border-radius: 2px;
  display: block;
  height: 100%;
  transform: scaleY(0.4);
  transform-origin: center;
  width: 2.5px;
}

.voice-bars i:nth-child(2) {
  animation-delay: 0.18s;
}

.voice-bars i:nth-child(3) {
  animation-delay: 0.36s;
}

/* La onda: cada barra escala su altura; los desfases entre las tres dan el efecto de onda. */
@keyframes voice-wave {
  0%,
  100% {
    transform: scaleY(0.35);
  }

  50% {
    transform: scaleY(1);
  }
}

/* El pulso: un anillo (box-shadow) que crece y se desvanece alrededor del circulo azul. */
@keyframes voice-recording-pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(26, 0, 114, 0.4);
  }

  70% {
    box-shadow: 0 0 0 11px rgba(26, 0, 114, 0);
  }

  100% {
    box-shadow: 0 0 0 0 rgba(26, 0, 114, 0);
  }
}

/* Sin movimiento: igual queda claro que graba (circulo azul + barras estaticas + anillo fijo). */
@media (prefers-reduced-motion: reduce) {
  #voice-record.is-recording {
    animation: none;
    box-shadow: 0 0 0 3px rgba(26, 0, 114, 0.25);
  }

  .voice-bars i {
    animation: none;
    transform: scaleY(0.7);
  }
}

@media (max-width: 760px) {
  .ul-screen {
    padding: 34px 16px 42px;
  }

  .ul-two-col,
  .ul-form-row,
  .ul-form-grid--2col,
  .project-form-grid,
  .ul-field-duo,
  .terms-grid {
    grid-template-columns: 1fr;
  }

  .ul-form-row {
    gap: 7px;
  }

  .ul-auth-digits {
    gap: 6px;
  }

  .ul-auth-digit {
    height: 52px;
    width: 42px;
  }

  .chat-panel {
    padding: 14px;
  }

  .chat-message-ai,
  .chat-message-user {
    max-width: 92%;
  }

  body.chat-page:not(.auth-page) .page-shell > form.chat-input-bar {
    border-radius: var(--radius-md);
    padding: 10px;
  }

  .chat-input-bar .spellcheck-input {
    min-width: 0;
  }

  /* En movil la barra es estrecha: el nombre del chip se acorta y la fila de chips desplaza
     horizontalmente para no empujar el boton "Enviar" fuera de la pantalla. */
  .attach-chip {
    max-width: 160px;
  }

  .attach-chip-name {
    max-width: 90px;
  }
}

/* ===== Valoracion de satisfaccion al cerrar la entrevista (FR-082) ===================== */
.valoracion-card {
  align-self: center;
  background: #fff;
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 6px auto 2px;
  max-width: min(520px, 100%);
  padding: 16px 20px;
  text-align: center;
  width: 100%;
}

.valoracion-titulo {
  color: var(--ul-navy);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  margin: 0;
}

/* Objetivo del proyecto citado en la pregunta P1 (hasta ~30 palabras): bloque PROPIO y tranquilo
   (texto normal, borde de acento), separado del titulo display — fundirlo alli volvia la tarjeta
   un ladrillo de negrilla. Sin margenes laterales del user-agent para blockquote. */
.valoracion-objetivo {
  border-left: 3px solid var(--ul-sky);
  color: var(--ul-muted);
  font-size: 14px;
  line-height: 1.45;
  margin: 0;
  padding: 2px 0 2px 10px;
  text-align: left; /* parrafo de lectura: el centrado de la tarjeta pelea con la barra de acento */
}

.valoracion-estrellas {
  border: 0;
  display: inline-flex;
  /* DOM en orden 5..1 + row-reverse = se ve 1..5 y permite el llenado con el combinador ~ */
  flex-direction: row-reverse;
  gap: 4px;
  justify-content: center;
  margin: 0 auto;
  padding: 0;
}

.valoracion-estrellas input {
  height: 1px;
  opacity: 0;
  position: absolute;
  width: 1px; /* oculto a la vista pero enfocable por teclado */
}

.valoracion-estrellas label {
  color: var(--ul-border-strong);
  cursor: pointer;
  font-size: 34px;
  line-height: 1;
  transition: color 0.12s ease;
}

.valoracion-estrellas label:hover,
.valoracion-estrellas label:hover ~ label,
.valoracion-estrellas input:checked ~ label {
  color: var(--ul-yellow);
}

.valoracion-estrellas input:focus-visible + label {
  border-radius: var(--radius-sm);
  outline: 2px solid var(--ul-sky);
  outline-offset: 2px;
}

.valoracion-comentario {
  border: 1px solid var(--ul-border-strong);
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-size: 15px;
  padding: 8px 10px;
  resize: vertical;
  width: 100%;
}

.valoracion-actions {
  align-items: stretch;
  display: flex;
  gap: 10px;
  justify-content: center;
}

/* Principio UI #6: misma altura para ambos controles, definida en el grupo (no boton por boton). */
.valoracion-actions .primary-action,
.valoracion-actions .secondary-action {
  flex: 1 1 0;
  font-size: 15px;
  min-height: 44px;
  padding: 0 18px;
}

.valoracion-error {
  color: var(--color-error);
  font-size: 14px;
  font-weight: 600;
  margin: 0;
}

.valoracion-gracias {
  align-self: center;
  background: rgba(14, 239, 218, 0.12);
  border: 1px solid rgba(14, 239, 218, 0.46);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  font-weight: 700;
  margin: 6px auto 2px;
  max-width: min(520px, 100%);
  padding: 12px 16px;
  text-align: center;
}

/* Bloque de descarga del entregable (FR-089): se revela en el chat tras la encuesta de sesion. Misma
   tarjeta centrada que la valoracion, con el boton de descarga y el aviso del correo/spam debajo. */
.descarga-card {
  align-self: center;
  background: #fff;
  border: 1px solid var(--ul-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 6px auto 2px;
  max-width: min(520px, 100%);
  padding: 16px 20px;
  text-align: center;
  width: 100%;
}

/* Principio UI #6: el boton comparte la altura de control (44px) de las acciones de la valoracion. */
.descarga-card .descarga-boton {
  align-items: center;
  align-self: center;
  display: inline-flex;
  justify-content: center;
  min-height: 44px;
  padding: 0 24px;
}

.descarga-aviso {
  color: var(--ul-muted);
  font-size: 13px;
  line-height: 1.45;
  margin: 0;
}

/* Boton "Cerrar" del embudo de cierre (tarea Salir entrevista): accion secundaria bajo la descarga.
   Al pulsarlo, chat.js oculta la conversacion y la barra de escritura y deja solo el menu. Comparte la
   altura de control (44px) de la tarjeta (Principio UI #6); estilo discreto para no competir con la
   descarga (CTA principal). */
.descarga-card .descarga-cerrar {
  align-items: center;
  align-self: center;
  background: none;
  border: none;
  color: var(--ul-muted);
  cursor: pointer;
  display: inline-flex;
  font-size: 14px;
  justify-content: center;
  min-height: 44px;
  padding: 0 16px;
  text-decoration: underline;
}

.descarga-card .descarga-cerrar:hover,
.descarga-card .descarga-cerrar:focus-visible {
  color: var(--ul-navy);
}

/* Foco visible coherente con el sistema (anillo 2px), no solo cambio de color. */
.descarga-card .descarga-cerrar:focus-visible {
  outline: 2px solid var(--ul-sky);
  outline-offset: 2px;
}

/* Variante PUBLICA de la tarjeta de valoracion (FR-083, pagina del enlace del correo). */
.valoracion-card-public {
  margin: 40px auto;
}

.valoracion-public-text {
  color: var(--ul-muted);
  font-size: 15px;
  line-height: 1.5;
  margin: 6px 0 0;
}

/* ================= FR-093: retroalimentacion 👍/👎 + encuesta + encabezado contextual ============ */

/* Contexto de la entrevista DENTRO del encabezado (FR-093 §4.9): tres renglones centrados = proyecto +
   entrevista (.header-context) y el menu (.header-nav-row, el tercero). Vacio fuera del chat. Sin
   fondo/tarjeta: es parte del encabezado, no un panel sobre la ventana del dialogo. */
.header-context {
  text-align: center;
  margin: 0;
  min-width: 0;
}

.header-context-proyecto {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 16px;
  color: var(--ul-navy);
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.header-context-entrevista {
  margin: 0;
  font-size: 13px;
  color: var(--ul-muted);
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Durante la entrevista el encabezado es UNA banda horizontal de tres zonas (principio UI #1 y #2:
   menos scroll vertical, mejor uso del ancho), en vez de apilar tres renglones a ancho completo:
   IZQUIERDA = menu (Herramientas), CENTRO = contexto (proyecto + entrevista), DERECHA = columna de
   cuenta. Reproduce el mockup del encabezado de entrevista. */
body.chat-page .header-content {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

body.chat-page .header-nav-row {
  order: 1;
  flex: 0 0 auto;
  justify-content: flex-start;
}

body.chat-page .header-context {
  order: 2;
  flex: 1 1 auto;
}

/* Zona derecha: columna de cuenta, alineada a la derecha: la marca (SUPERCHAT) arriba, los botones en
   medio y la identidad del usuario abajo. La insignia "TyC" se ancla al final del renglon de identidad
   (esquina inferior derecha), segun la referencia, sin robar un renglon. */
body.chat-page .header-title-row {
  order: 3;
  position: relative;
  flex: 0 0 auto;
  align-self: center;
  align-items: flex-end;
  gap: 3px;
}

body.chat-page .header-account {
  flex-direction: column;
  align-items: flex-end;
  gap: 3px;
}

/* Botones (Salir entrevista + Cerrar sesion) arriba; identidad del usuario en el renglon de abajo. */
body.chat-page .session-actions {
  order: 1;
}

body.chat-page .user-identity {
  order: 2;
}

/* En la entrevista la insignia "TyC" (estilo global) solo cambia de ANCLAJE: esquina inferior
   derecha del bloque de cuenta, fuera de flujo para no consumir un renglon. */
body.chat-page .header-terms-link {
  position: absolute;
  bottom: 0;
  right: 0;
}

/* Mas aire entre el titulo del proyecto y el de la entrevista (legibilidad del contexto). */
body.chat-page .header-context-entrevista {
  margin-top: 6px;
}

/* Encabezado de entrevista ~25% mas bajo (principio UI #1) SIN encoger el logo: la altura la fijaba
   la columna derecha de tres renglones (~100px), no el logo (72px). Se comprime esa columna (renglones
   y controles mas ajustados) hasta caber dentro del alto del logo, de modo que el header baja al piso
   del logo + padding (~88px). El logo conserva sus 72px. */
body.chat-page .app-header {
  padding-bottom: 6px;
  padding-top: 6px;
}

body.chat-page .brand-title strong {
  font-size: 17px;
  letter-spacing: 0.4px;
  line-height: 1.1;
}

/* La insignia "TyC" va al final del renglon de identidad: se reserva un hueco a la derecha del nombre
   para que se asiente ahi sin encimarse con el texto. El borde derecho de TyC coincide con el del
   nombre, los botones y "SUPERCHAT". */
body.chat-page .user-identity {
  padding-right: 28px;
}

body.chat-page .session-actions {
  gap: 8px;
}

body.chat-page .session-actions .logout-button,
body.chat-page .session-actions .interview-exit-button {
  min-height: 28px;
}

body.chat-page .user-pill {
  font-size: 12px;
  height: 22px;
  width: 22px;
}

body.chat-page .user-name {
  font-size: 13px;
}

/* En pantallas estrechas la banda de 3 zonas de la entrevista no cabe en una fila y desbordaria el
   ancho: aqui se reapila en columna como el resto del encabezado movil. Va DESPUES del bloque de
   escritorio de body.chat-page (misma especificidad) para ganarle por orden de origen; la insignia
   "TyC" (representacion unica) deja el anclaje absoluto y vuelve al FLUJO de la cuenta. */
@media (max-width: 960px) {
  body.chat-page .header-content {
    align-items: stretch;
    flex-direction: column;
  }

  body.chat-page .header-title-row {
    align-items: flex-start;
    order: 0;
    padding-right: 0;
  }

  body.chat-page .header-account {
    align-items: center;
    flex-direction: row;
  }

  body.chat-page .session-actions,
  body.chat-page .user-identity {
    order: 0;
  }

  /* En movil la insignia "TyC" esta EN FLUJO (position static), asi que el hueco reservado a la
     derecha de la identidad (para la insignia ANCLADA de escritorio) ya no aplica. */
  body.chat-page .user-identity {
    padding-right: 0;
  }

  body.chat-page .header-context {
    order: 1;
    text-align: left;
  }

  body.chat-page .header-nav-row {
    justify-content: flex-start;
    order: 2;
  }

  /* En el encabezado apilado del movil la insignia vuelve al FLUJO (el anclaje absoluto de
     escritorio se solaparia con la pila). El margen le da respiracion respecto a sus vecinos de
     pila (el gap de 3px de la cuenta del chat es para los renglones compactos, no para separar
     dos circulos de 22px casi tocandose). */
  body.chat-page .header-terms-link {
    margin: 2px 8px 2px 0;
    position: static;
  }
}

/* Acciones de mensaje como ICONOS (~34px) en vez de botones de texto (Principio UI #3, R7): copiar,
   👍 y 👎. Boton transparente cuadrado con el SVG centrado. */
.chat-icon-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ul-muted);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}

.chat-icon-action svg {
  display: block;
}

/* Gana sobre `.chat-message-meta .chat-copy` (misma especificidad, definido despues): el copiar pasa de
   pildora de texto a icono dentro de la meta. */
.chat-message-meta .chat-icon-action {
  background: transparent;
  color: var(--ul-muted);
}

.chat-icon-action:hover,
.chat-icon-action:focus-visible {
  background: var(--ul-bg-tint);
  color: var(--ul-navy);
}

.chat-icon-action.is-copied {
  color: var(--ul-turquoise-dark);
}

/* 👎 reusa el trazo del 👍 volteado verticalmente (un solo SVG). */
.chat-feedback-down svg {
  transform: scaleY(-1);
}

.chat-feedback-up:hover,
.chat-feedback-up:focus-visible {
  color: var(--ul-turquoise-dark);
}

.chat-feedback-down:hover,
.chat-feedback-down:focus-visible {
  color: #c0392b;
}

/* Mensaje del sistema (SUPERCHAT): nota informativa centrada, distinta de las burbujas usuario/IA. */
.chat-message-system {
  align-self: center;
  max-width: min(680px, 100%);
  background: rgba(14, 239, 218, 0.08);
  border: 1px dashed rgba(14, 239, 218, 0.5);
  border-radius: var(--radius-md);
  color: var(--ul-navy);
  font-size: 14px;
  text-align: center;
}

/* Banda del modo retroalimentacion (R2): se muestra sobre el cajon al dar 👍/👎, con la X de cancelar. */
.chat-feedback-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 12px;
  margin-bottom: 6px;
  background: rgba(14, 239, 218, 0.12);
  border: 1px solid rgba(14, 239, 218, 0.5);
  border-radius: var(--radius-md);
}

.chat-feedback-bar[hidden] {
  display: none;
}

.chat-feedback-label {
  flex: 1 1 auto;
  font-size: 13px;
  font-weight: 600;
  color: var(--ul-navy);
}

.chat-feedback-bar .chat-feedback-cancel {
  flex: 0 0 auto;
  color: var(--ul-navy);
}

/* Marca visual del cajon en modo retroalimentacion (acento segun 👍/👎). */
.chat-input-bar.is-feedback {
  position: relative;
}

.chat-input-bar.is-feedback-positiva .chat-feedback-bar {
  background: rgba(14, 239, 218, 0.12);
  border-color: rgba(14, 239, 218, 0.6);
}

.chat-input-bar.is-feedback-negativa .chat-feedback-bar {
  background: rgba(192, 57, 43, 0.10);
  border-color: rgba(192, 57, 43, 0.45);
}

/* Encuesta data-driven: separacion entre preguntas cuando hay mas de una en la tarjeta. */
.valoracion-pregunta + .valoracion-pregunta {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--ul-border);
}

/* --- Proteccion de Datos (derechos del titular, Ley 1581) ------------------------------------ */

.pd-intro {
  color: var(--ul-slate);
  font-size: 14px;
  line-height: 1.4;
  margin: 0 0 14px;
}

.pd-list {
  display: grid;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* El form de las acciones informativas es transparente al layout (principio UI #7): el boton
   participa DIRECTO en la lista, con la MISMA geometria que las filas-enlace (principio #6). */
.pd-form {
  display: contents;
}

.pd-row {
  align-items: center;
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: 10px;
  color: var(--ul-slate);
  cursor: pointer;
  display: grid;
  font: inherit;
  gap: 12px;
  grid-template-columns: 34px 1fr 18px;
  padding: 8px 12px;
  text-align: left;
  text-decoration: none;
  width: 100%;
}

.pd-row:hover,
.pd-row:focus-visible {
  border-color: var(--ul-turquoise-dark);
  background: var(--ul-bg-tint);
}

.pd-ico {
  align-items: center;
  color: var(--ul-navy);
  display: flex;
  height: 34px;
  justify-content: center;
  width: 34px;
}

.pd-text {
  min-width: 0;
}

.pd-row-title {
  color: var(--ul-navy);
  display: block;
  font-weight: 600;
}

/* Descripcion en UN renglon con ellipsis (principio #1: filas compactas, poco scroll). */
.pd-row-desc {
  color: var(--ul-muted);
  display: block;
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pd-go {
  color: var(--ul-muted);
}

.pd-foot {
  color: var(--ul-muted);
  font-size: 13px;
  margin: 14px 0 0;
}

/* Reenvio de la constancia: icono-accion suelto (mismo tamano de control que las acciones de fila).
   Neutraliza el estilo global de form-como-tarjeta: este form no es una caja de contenido, solo
   posiciona el icono (principio #7: sin contenedores sin proposito). */
.pd-resend {
  background: none;
  border: 0;
  box-shadow: none;
  display: flex;
  justify-content: flex-end;
  margin: 10px 0 0;
  max-width: none;
  padding: 0;
}

.pd-icon-btn {
  align-items: center;
  background: var(--ul-white);
  border: 1px solid var(--ul-border);
  border-radius: 8px;
  color: var(--ul-navy);
  display: inline-flex;
  height: 34px;
  justify-content: center;
  padding: 0;
  width: 34px;
}

.pd-icon-btn:hover,
.pd-icon-btn:focus-visible {
  background: var(--ul-bg-tint);
  border-color: var(--ul-turquoise-dark);
}

.pd-solicitud-form label {
  color: var(--ul-slate);
  display: block;
  font-size: 14px;
  font-weight: 600;
  margin: 0 0 6px;
}

.pd-form-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
}

/* Colores de estado del registro de solicitudes (la base del pill se comparte con .export-pill). */
.pd-pill--pendiente {
  background: #fdf3e0;
  color: #9a6a12;
}

.pd-pill--en_tramite {
  background: var(--ul-bg-tint);
  color: var(--ul-turquoise-dark);
}

.pd-pill--atendida {
  background: #e7f7ef;
  color: #1a7f4b;
}

/* Advertencia de datos sensibles al pie de la barra de escritura (punto 7 de la politica):
   discreta, para no robar espacio vertical a la conversacion. Vive DENTRO del form (flex-column,
   con gap propio): sin margenes, se oculta junto con la barra al cerrar la conversacion. */
.chat-privacy-note {
  color: var(--ul-muted);
  font-size: 12px;
  line-height: 1.3;
  margin: -4px 0 0;
  text-align: center;
}

/* FR-107: base de conocimiento dinamica por identidad ------------------------------------------ */

/* Lista de eleccion de registro en la desambiguacion (interviews/instance_desambiguar.html):
   botones de una fila, misma altura, alineados a la izquierda con su icono (controles uniformes,
   Principio 6). Centralizado aqui (no inline) por el Principio 5 (solucion generica). */
.ul-choice {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 14px;
  text-align: left;
  border: 1px solid var(--ul-border, #d0d7de);
  border-radius: 10px;
  background: var(--ul-surface, #fff);
  color: var(--ul-navy, #0f2c4d);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease;
}
.ul-choice:hover { border-color: var(--ul-sky-dark, #007494); background: var(--ul-sky-wash, #f0f8fb); }
.ul-choice svg { flex: 0 0 auto; color: var(--ul-sky-dark, #007494); }

/* Fila de casilla + etiqueta (p. ej. "Contenido dinamico" en el experto IA): alineadas, sin robar
   alto vertical (Principio 1). */
.ul-check-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-weight: 600;
  cursor: pointer;
}
.ul-check-row input { flex: 0 0 auto; }

/* Textarea para JSON/descriptor (editor de la fuente dinamica en la licencia): monoespaciada para
   leer la estructura sin envolver. */
.code-textarea {
  font-family: ui-monospace, "Cascadia Code", "Consolas", monospace;
  font-size: 13px;
  line-height: 1.4;
  white-space: pre;
  overflow-wrap: normal;
}
