/* ==========================================================================
   INVEXUS · components.css
   Componentes de las 9 secciones de contenido de la Home.
   Cada bloque corresponde a una SECTION de ARQUITECTURA_VISUAL_UX §12.
   Depende de tokens.css y base.css.
   ========================================================================== */

/* ==========================================================================
   SECTION 02 · HERO
   ========================================================================== */
.inv-hero {
  /* Scrim + gradiente. Ver --inv-scrim-dark en tokens.css: sobre el extremo
     claro del gradiente (#2D80C3) el texto atenuado caía a 1.9:1. */
  background-image: var(--inv-scrim-dark), var(--inv-gradient-brand);
  background-color: var(--inv-navy);
  color: var(--inv-on-dark);
  padding-block: var(--inv-space-8) var(--inv-space-7);
  overflow: hidden;
}
.inv-hero h1 { color: var(--inv-on-dark); }
.inv-hero__sub {
  font-family: var(--inv-font-heading);
  font-size: var(--inv-fs-body-lg);
  font-weight: var(--inv-fw-semibold);
  color: var(--inv-cyan-bright);
  margin-bottom: var(--inv-space-3);
}
.inv-hero__text { color: var(--inv-on-dark-muted); max-width: 58ch; }
.inv-hero__actions { margin-top: var(--inv-space-5); }
.inv-hero__proof {
  margin-top: var(--inv-space-4);
  font-size: var(--inv-fs-small);
  color: var(--inv-on-dark-muted);
}
/* Mockup "INVEXUS Intelligence". Placeholder mientras no exista el asset. */
.inv-hero__visual {
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--inv-radius-lg);
  box-shadow: var(--inv-shadow-lg);
  padding: var(--inv-space-3);
  min-height: 320px;
}

/* ==========================================================================
   SECTION 03 · PROOF STRIP  (KPIs con count-up)
   ========================================================================== */
.inv-proof {
  background: var(--inv-surface);
  border-bottom: 1px solid var(--inv-border);
  padding-block: var(--inv-space-5);
}
.inv-metric__value {
  font-family: var(--inv-font-heading);
  font-size: var(--inv-fs-kpi);
  font-weight: var(--inv-fw-bold);
  line-height: 1;
  color: var(--inv-ink-strong);
  font-variant-numeric: tabular-nums;   /* evita saltos durante el count-up */
}
.inv-metric__label {
  margin-top: var(--inv-space-1);
  font-size: var(--inv-fs-small);
  color: var(--inv-muted);
}

/* ==========================================================================
   SECTION 04 · PROBLEMS   |   SECTION 05 · SOLUTIONS
   ========================================================================== */
.inv-card {
  background: var(--inv-surface);
  border: 1px solid var(--inv-border);
  border-radius: var(--inv-radius-md);
  padding: var(--inv-space-4);
  box-shadow: var(--inv-shadow-sm);
  transition: transform var(--inv-duration-base) var(--inv-ease),
              box-shadow var(--inv-duration-base) var(--inv-ease),
              border-color var(--inv-duration-base) var(--inv-ease);
  height: 100%;
}
/* Hover con elevación y cambio de borde (§5.6). Sólo donde hay puntero fino:
   §13 prohíbe depender del hover en móvil. */
@media (hover: hover) and (pointer: fine) {
  .inv-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--inv-shadow-md);
    border-color: var(--inv-brand);
  }
  .inv-card:hover .inv-card__icon { transform: scale(1.08); }
}
.inv-card__num {
  font-family: var(--inv-font-heading);
  font-size: var(--inv-fs-small);
  font-weight: var(--inv-fw-bold);
  color: var(--inv-brand-ink);
  letter-spacing: .1em;
}
.inv-card__icon {
  width: 44px; height: 44px; margin-bottom: var(--inv-space-3);
  color: var(--inv-brand);
  transition: transform var(--inv-duration-base) var(--inv-ease);
}
.inv-card__title { margin-bottom: var(--inv-space-2); }
.inv-card__text  { color: var(--inv-muted); margin: 0; }
.inv-card__link  { display: inline-block; margin-top: var(--inv-space-3);
                   font-weight: var(--inv-fw-semibold); }

/* Grid 3+2 de soluciones (§12 SECTION 05). Cinco tarjetas: 3 arriba, 2 abajo
   centradas. Se resuelve con span, sin markup extra. */
.inv-solutions__grid { grid-template-columns: repeat(6, minmax(0,1fr)); }
.inv-solutions__grid > * { grid-column: span 2; }
.inv-solutions__grid > *:nth-child(4) { grid-column: 2 / span 2; }
.inv-solutions__grid > *:nth-child(5) { grid-column: 4 / span 2; }

/* ==========================================================================
   SECTION 06 · FUNDING RADAR
   ========================================================================== */
.inv-funding { background: var(--inv-soft); }
.inv-funding-card {
  background: var(--inv-surface);
  border: 1px solid var(--inv-border);
  border-left: 4px solid var(--inv-brand);
  border-radius: var(--inv-radius-sm);
  padding: var(--inv-space-3);
}
.inv-funding-card__meta {
  display: flex; flex-wrap: wrap; gap: var(--inv-space-2);
  font-size: var(--inv-fs-small); color: var(--inv-muted);
  margin-top: var(--inv-space-2);
}
.inv-funding-card__amount {
  font-family: var(--inv-font-heading); font-weight: var(--inv-fw-bold);
  color: var(--inv-green-ink);
}
.inv-updated { font-size: var(--inv-fs-small); color: var(--inv-muted);
               margin-top: var(--inv-space-3); }

/* ==========================================================================
   SECTION 07 · CASE  (50/50)
   ========================================================================== */
.inv-case__media {
  border-radius: var(--inv-radius-lg); overflow: hidden;
  box-shadow: var(--inv-shadow-md); background: var(--inv-soft);
  aspect-ratio: 4 / 3;
}
.inv-case__media img { width: 100%; height: 100%; object-fit: cover; }
.inv-case__facts {
  display: grid; grid-template-columns: repeat(3, minmax(0,1fr));
  gap: var(--inv-space-3); margin-block: var(--inv-space-4);
  padding-block: var(--inv-space-3);
  border-block: 1px solid var(--inv-border);
}
.inv-case__fact-label { font-size: var(--inv-fs-small); color: var(--inv-muted); }
.inv-case__fact-value { font-family: var(--inv-font-heading);
                        font-weight: var(--inv-fw-bold); color: var(--inv-ink-strong); }

/* ==========================================================================
   SECTION 08 · INTELLIGENCE DEMO  (tabs accesibles)
   ========================================================================== */
/* DEFECTO CORREGIDO EL 01/09/2026, y venia de antes de la capa dinamica.
   Esta seccion tiene fondo navy pero NO declaraba el color de sus titulares,
   asi que el h2 heredaba el color de titular general -que era navy tambien- y
   quedaba NAVY SOBRE NAVY: contraste 1:1, es decir, invisible.
   No se detecto antes porque una captura de pantalla no distingue "no hay
   titular" de "el titular no esta"; lo encontro motion-qa.mjs midiendo el
   color computado contra el fondo real.
   Se resuelve como en .inv-section--navy, que ya lo hacia bien. */
.inv-demo { background: var(--inv-navy); color: var(--inv-on-dark); }
.inv-demo :where(h1,h2,h3) { color: var(--inv-on-dark); }
.inv-demo .inv-lead, .inv-demo .inv-muted { color: var(--inv-on-dark-muted); }
.inv-demo .inv-eyebrow { color: var(--inv-cyan-bright); }
.inv-demo__panel {
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--inv-radius-lg);
  padding: var(--inv-space-4);
}
.inv-tabs__list { display: flex; gap: var(--inv-space-1); flex-wrap: wrap;
                  margin-bottom: var(--inv-space-3); }
.inv-tabs__tab {
  min-height: 44px; padding: 0 var(--inv-space-3);
  background: transparent; color: var(--inv-on-dark-muted);
  border: 1px solid rgba(255,255,255,.18);
  border-radius: var(--inv-radius-pill);
  font-family: var(--inv-font-heading); font-weight: var(--inv-fw-medium);
  cursor: pointer;
}
.inv-tabs__tab[aria-selected="true"] {
  background: var(--inv-cyan-bright); color: var(--inv-navy);
  border-color: var(--inv-cyan-bright); font-weight: var(--inv-fw-semibold);
}
.inv-demo__query {
  font-family: var(--inv-font-body); color: var(--inv-on-dark);
  background: rgba(0,0,0,.25); border-radius: var(--inv-radius-sm);
  padding: var(--inv-space-3); border: 1px solid rgba(255,255,255,.12);
}
.inv-demo__answer { color: var(--inv-on-dark-muted); margin-top: var(--inv-space-3); }
.inv-demo__disclaimer { font-size: var(--inv-fs-small); color: var(--inv-on-dark-muted);
                        margin-top: var(--inv-space-4); }

/* ==========================================================================
   SECTION 09 · INSIGHTS
   ========================================================================== */
.inv-insight-card__tag { font-size: var(--inv-fs-small); font-weight: var(--inv-fw-semibold);
                         color: var(--inv-cyan-ink); text-transform: uppercase;
                         letter-spacing: .08em; }
.inv-insight-card__date { font-size: var(--inv-fs-small); color: var(--inv-muted); }

/* ==========================================================================
   SECTION 10 · CTA FINAL
   ========================================================================== */
.inv-cta {
  background-image: var(--inv-scrim-dark), var(--inv-gradient-brand);
  background-color: var(--inv-navy);
  color: var(--inv-on-dark);
  text-align: center;
}
.inv-cta h2 { color: var(--inv-on-dark); }
.inv-cta p  { color: var(--inv-on-dark-muted); max-width: 56ch; margin-inline: auto; }
.inv-cta .inv-actions { justify-content: center; margin-top: var(--inv-space-5); }

/* ==========================================================================
   CONTENEDORES DE COMPONENTE
   Clases que el marcado ya usaba y que no tenían regla propia. Sin ellas el
   espaciado dependía de márgenes heredados, que es frágil.
   ========================================================================== */
.inv-section__head { margin-bottom: var(--inv-space-6); max-width: 60ch; }
.inv-section__head:last-child { margin-bottom: 0; }
.inv-center .inv-section__head { margin-inline: auto; }

.inv-hero__body { min-width: 0; }          /* evita desbordes en grid */
.inv-metric { min-width: 0; }
.inv-insight-card { display: flex; flex-direction: column; }
.inv-insight-card .inv-card__title { flex: 1 0 auto; }

.inv-funding__list { display: flex; flex-direction: column; gap: var(--inv-space-2); }
.inv-funding-card__top { margin-bottom: var(--inv-space-2); }

.inv-tabs { min-width: 0; }
.inv-tabs__panel:focus-visible { outline: 3px solid var(--inv-cyan-bright); outline-offset: 4px; }

/* ==========================================================================
   MOTION · estados de entrada (motion.js añade .is-visible)
   ========================================================================== */
.inv-reveal {
  opacity: 0; transform: translateY(16px);
  transition: opacity var(--inv-duration-slow) var(--inv-ease),
              transform var(--inv-duration-slow) var(--inv-ease);
}
.inv-reveal.is-visible { opacity: 1; transform: none; }

/* Sin JS, el contenido debe verse igual. Regla de seguridad. */
.no-js .inv-reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .inv-reveal { opacity: 1; transform: none; transition: none; }
  .inv-card:hover { transform: none; }
}

/* ==========================================================================
   ICONOGRAFÍA  (§10)
   Outline, stroke 1.75, heredan color del contenedor con currentColor.
   ========================================================================== */
.inv-icon { width: 24px; height: 24px; display: block; flex: 0 0 auto; }
.inv-icon--sm { width: 18px; height: 18px; }
.inv-icon--xs { width: 15px; height: 15px; }

/* Contenedor del icono en las tarjetas: cuadrado suave con fondo tenue.
   §6.1 pide que escale 1.04 en hover, no la tarjeta entera. */
.inv-card__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px;
  margin-bottom: var(--inv-space-3);
  border-radius: var(--inv-radius-sm);
  background: var(--inv-soft);
  color: var(--inv-brand-ink);
  transition: transform var(--inv-duration-base) var(--inv-ease),
              background-color var(--inv-duration-base) var(--inv-ease),
              color var(--inv-duration-base) var(--inv-ease);
}

/* ==========================================================================
   TEXTURA TECNOLÓGICA  (§11)
   Rejilla de puntos al 4% de opacidad. Sólo en hero, funding e intelligence,
   que son los tres bloques donde §11 la autoriza. Se pinta con un
   radial-gradient repetido: cero peticiones, cero imágenes.
   ========================================================================== */
.inv-dotgrid { position: relative; isolation: isolate; }
.inv-dotgrid::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: radial-gradient(currentColor 1px, transparent 1px);
  background-size: 22px 22px;
  opacity: .04;
}
/* Sobre fondo claro el punto debe ser navy; sobre oscuro, blanco. */
.inv-funding.inv-dotgrid::before { color: var(--inv-navy); opacity: .06; }
.inv-hero.inv-dotgrid::before,
.inv-demo.inv-dotgrid::before { color: var(--inv-on-dark); opacity: .05; }

/* ==========================================================================
   HERO · composición
   ========================================================================== */
.inv-hero { position: relative; }

/* Halo cian muy tenue detrás del mockup. Da profundidad sin recurrir a
   partículas ni vídeo, ambos prohibidos por §11. */
.inv-hero::after {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  width: 46vw; max-width: 720px; aspect-ratio: 1;
  right: -12vw; top: 50%; transform: translateY(-50%);
  background: radial-gradient(circle, rgba(63,195,222,.16) 0%, rgba(63,195,222,0) 68%);
}
.inv-hero > .inv-container { position: relative; z-index: 1; }

.inv-hero__body { max-width: 46rem; }
.inv-hero .inv-eyebrow { color: var(--inv-cyan-bright); }

/* Línea de acento antes del eyebrow: ancla la composición y marca inicio. */
.inv-eyebrow::before {
  content: ""; display: inline-block; vertical-align: middle;
  width: 28px; height: 2px; margin-right: 10px;
  background: currentColor; opacity: .8;
}

.inv-hero__sub {
  display: inline-flex; flex-wrap: wrap; max-width: 100%;
  align-items: center; gap: 4px 10px;
  padding: 6px 14px; border-radius: var(--inv-radius-pill);
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.16);
  font-size: var(--inv-fs-small);
  letter-spacing: .01em;
}

.inv-hero__proof {
  display: flex; align-items: center; gap: 10px;
  padding-top: var(--inv-space-4);
  border-top: 1px solid rgba(255,255,255,.14);
  max-width: 30rem;
}

/* ==========================================================================
   MOCKUP "INVEXUS INTELLIGENCE"
   Todo el panel es HTML+CSS. Sin imagen, sin JS, sin cifras.
   ========================================================================== */
.inv-mock {
  border-radius: var(--inv-radius-lg);
  background: linear-gradient(180deg, rgba(255,255,255,.10) 0%, rgba(255,255,255,.04) 100%);
  border: 1px solid rgba(255,255,255,.18);
  box-shadow: var(--inv-shadow-lg);
  backdrop-filter: blur(2px);
  overflow: hidden;
}

.inv-mock__chrome {
  display: flex; align-items: center; gap: 7px;
  padding: 12px var(--inv-space-3);
  border-bottom: 1px solid rgba(255,255,255,.14);
  background: rgba(11,31,51,.35);
}
.inv-mock__dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: rgba(255,255,255,.24);
}
.inv-mock__title {
  display: inline-flex; align-items: center; gap: 8px;
  margin-left: auto;
  font-family: var(--inv-font-heading);
  font-size: var(--inv-fs-small);
  font-weight: var(--inv-fw-semibold);
  color: var(--inv-on-dark-muted);
  letter-spacing: .02em;
}
.inv-mock__brand-icon { width: 16px; height: 16px; color: var(--inv-cyan-bright); }

.inv-mock__body { padding: var(--inv-space-3); display: grid; gap: 14px; }

.inv-mock__row {
  display: grid;
  grid-template-columns: 26px minmax(0, 88px) 1fr auto;
  align-items: center; gap: 12px;
}
.inv-mock__icon { color: var(--inv-cyan-bright); display: flex; }
.inv-mock__label {
  font-size: var(--inv-fs-small);
  color: var(--inv-on-dark);
  font-weight: var(--inv-fw-medium);
}
.inv-mock__bar {
  height: 6px; border-radius: 999px;
  background: rgba(255,255,255,.12);
  overflow: hidden;
}
.inv-mock__bar-fill {
  display: block; height: 100%; border-radius: inherit;
  background: linear-gradient(90deg, var(--inv-brand) 0%, var(--inv-cyan-bright) 100%);
  width: var(--inv-mock-fill, 60%);
  transform-origin: left center;
}
/* Las proporciones viven AQUÍ, no en el marcado: el HTML no lleva ni un
   style inline. Son valores decorativos, no mediciones. */
.inv-mock__row:nth-child(1) .inv-mock__bar-fill { --inv-mock-fill: 78%; }
.inv-mock__row:nth-child(2) .inv-mock__bar-fill { --inv-mock-fill: 62%; }
.inv-mock__row:nth-child(3) .inv-mock__bar-fill { --inv-mock-fill: 88%; }
.inv-mock__row:nth-child(4) .inv-mock__bar-fill { --inv-mock-fill: 45%; }

.inv-mock__state {
  font-size: .8rem; color: var(--inv-on-dark-muted);
  white-space: nowrap;
  /* Sin opacidad: rebajarla anularia el contraste ya verificado de
     --inv-on-dark-muted. El texto es decorativo para lectores de pantalla,
     pero una persona con vista lo lee igual. */
}

.inv-mock__spark { margin-top: 4px; color: var(--inv-cyan-bright); }
.inv-mock__spark svg { width: 100%; height: 56px; display: block; }
.inv-mock__spark-area { fill: rgba(63,195,222,.14); }

.inv-mock__foot {
  display: flex; gap: 8px; align-items: center;
  padding-top: 12px; border-top: 1px solid rgba(255,255,255,.12);
}
.inv-mock__chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--inv-radius-pill);
  font-size: .75rem; letter-spacing: .02em;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14);
  color: var(--inv-on-dark-muted);
}
.inv-mock__chip--ai { color: var(--inv-cyan-bright); border-color: rgba(63,195,222,.35); }

/* Entrada suave del mockup, 350-500ms según §9.2. Un solo movimiento. */
@media (prefers-reduced-motion: no-preference) {
  .inv-hero__visual .inv-mock { animation: inv-mock-in var(--inv-duration-slow) var(--inv-ease) both; }
  @keyframes inv-mock-in {
    from { opacity: 0; transform: translateY(14px) scale(.985); }
    to   { opacity: 1; transform: none; }
  }
  /* Las barras crecen una vez, escalonadas. Sin bucle: §9.4 lo prohíbe. */
  .inv-mock__bar-fill { animation: inv-bar-in 620ms var(--inv-ease) both; }
  .inv-mock__row:nth-child(1) .inv-mock__bar-fill { animation-delay: 260ms; }
  .inv-mock__row:nth-child(2) .inv-mock__bar-fill { animation-delay: 350ms; }
  .inv-mock__row:nth-child(3) .inv-mock__bar-fill { animation-delay: 440ms; }
  .inv-mock__row:nth-child(4) .inv-mock__bar-fill { animation-delay: 530ms; }
  @keyframes inv-bar-in { from { transform: scaleX(0); } to { transform: scaleX(1); } }
}

/* ==========================================================================
   PROOF STRIP · más presencia
   ========================================================================== */
.inv-proof__grid { position: relative; }
.inv-metric { position: relative; padding-inline: var(--inv-space-2); }
/* Separadores finos entre métricas, sólo donde hay vecino a la izquierda. */
.inv-metric + .inv-metric::before {
  content: ""; position: absolute; left: 0; top: 12%; bottom: 12%;
  width: 1px; background: var(--inv-border);
}
.inv-metric__value {
  background: linear-gradient(135deg, var(--inv-navy) 0%, var(--inv-brand-ink) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.inv-metric__label {
  text-transform: uppercase; letter-spacing: .08em; font-size: .8rem;
  font-weight: var(--inv-fw-medium);
}

/* ==========================================================================
   TARJETAS · comportamiento aprobado en §6.1
   translateY(-6px) · borde brand 35% · sombra más profunda · icono 1.04
   ========================================================================== */
.inv-card { position: relative; display: flex; flex-direction: column; }
.inv-card__text { flex: 1 1 auto; }

.inv-card__arrow {
  transition: transform var(--inv-duration-micro) var(--inv-ease);
}
.inv-card__link {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 28px;   /* WCAG 2.5.8: objetivo minimo 24px */
}

@media (hover: hover) and (pointer: fine) {
  .inv-card:hover {
    transform: translateY(-6px);
    box-shadow: var(--inv-shadow-md);
    border-color: rgba(45,128,195,.35);
  }
  .inv-card:hover .inv-card__icon {
    transform: scale(1.04);
    background: var(--inv-brand-ink);
    color: var(--inv-surface);
  }
  .inv-card:hover .inv-card__arrow { transform: translateX(4px); }
}

/* El foco por teclado debe verse igual de claro que el hover. */
.inv-card:focus-within {
  border-color: rgba(45,128,195,.35);
  box-shadow: var(--inv-shadow-md);
}

/* Numeral de las tarjetas de problema, como marca de agua discreta. */
.inv-card__num {
  position: absolute; top: var(--inv-space-3); right: var(--inv-space-3);
  font-size: 1.5rem; font-weight: var(--inv-fw-bold);
  color: var(--inv-border); letter-spacing: 0;
}

/* ==========================================================================
   SOLUCIONES · acento superior en cada tarjeta
   ========================================================================== */
.inv-solutions__grid .inv-card__title a {
  color: var(--inv-ink-strong); text-decoration: none;
}
.inv-solutions__grid .inv-card:hover .inv-card__title a,
.inv-solutions__grid .inv-card:focus-within .inv-card__title a {
  color: var(--inv-brand-ink);
}
/* Toda la tarjeta es pulsable: el enlace del titulo se estira por encima.
   Mantiene un solo destino accesible por tarjeta, sin enlaces duplicados. */
.inv-solutions__grid .inv-card__title a::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
}

.inv-solutions__grid .inv-card::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  border-radius: var(--inv-radius-md) var(--inv-radius-md) 0 0;
  background: var(--inv-gradient-intelligence);
  opacity: 0; transition: opacity var(--inv-duration-base) var(--inv-ease);
}
.inv-solutions__grid .inv-card:hover::after,
.inv-solutions__grid .inv-card:focus-within::after { opacity: 1; }

/* ==========================================================================
   FUNDING · pill de estado con latido muy leve sólo en "Abierta"  (§9.3)
   ========================================================================== */
.inv-funding-card { transition: border-color var(--inv-duration-base) var(--inv-ease),
                                box-shadow var(--inv-duration-base) var(--inv-ease); }
@media (hover: hover) and (pointer: fine) {
  .inv-funding-card:hover { box-shadow: var(--inv-shadow-sm); border-left-color: var(--inv-cyan-ink); }
}
.inv-badge--open::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
@media (prefers-reduced-motion: no-preference) {
  .inv-badge--open::before { animation: inv-pulse 2.4s ease-in-out infinite; }
  @keyframes inv-pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
}

/* ==========================================================================
   DEMO DE INTELIGENCIA · más cuerpo
   ========================================================================== */
.inv-demo__panel { max-width: 62rem; margin-inline: auto; }
.inv-demo__query {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: var(--inv-fs-body-lg);
}
.inv-demo__query::before {
  content: "›"; color: var(--inv-cyan-bright);
  font-weight: var(--inv-fw-bold); line-height: 1.2;
}
.inv-demo__answer { padding-left: 22px; border-left: 2px solid rgba(63,195,222,.35); }

/* ==========================================================================
   CTA FINAL · más aire y jerarquía
   ========================================================================== */
.inv-cta { position: relative; }
.inv-cta .inv-eyebrow { color: var(--inv-cyan-bright); }
.inv-cta h2 { max-width: 20ch; margin-inline: auto; }

/* ==========================================================================
   RITMO ENTRE SECCIONES
   Reveal escalonado dentro de una misma sección: da sensación de composición
   en vez de que todo aparezca de golpe.
   ========================================================================== */
.inv-grid > .inv-reveal:nth-child(2) { transition-delay: 70ms; }
.inv-grid > .inv-reveal:nth-child(3) { transition-delay: 140ms; }
.inv-grid > .inv-reveal:nth-child(4) { transition-delay: 210ms; }
.inv-grid > .inv-reveal:nth-child(5) { transition-delay: 280ms; }
@media (prefers-reduced-motion: reduce) {
  .inv-grid > .inv-reveal { transition-delay: 0ms !important; }
}

/* ==========================================================================
   CABECERA INVEXUS  (§12 SECTION 01, §4)
   Sin barra superior de redes/correo/teléfono: §4.1 pide eliminarla.
   ========================================================================== */

/* Enlace de salto: invisible hasta recibir el foco. Es el primer elemento
   tabulable de la página, como debe ser. */
.inv .inv-skip, .inv-skip {
  position: absolute; left: 8px; top: -60px; z-index: var(--inv-z-overlay);
  padding: 12px 18px; border-radius: var(--inv-radius-btn);
  background: var(--inv-navy); color: var(--inv-on-dark);
  font-weight: var(--inv-fw-semibold); text-decoration: none;
  transition: top var(--inv-duration-micro) var(--inv-ease);
}
.inv-skip:focus { top: 8px; color: var(--inv-on-dark); }

.inv-header {
  position: sticky; top: 0; z-index: var(--inv-z-sticky);
  /* NAVY, no blanco. El logotipo de INVEXUS es blanco (luminancia media
     254/255) y no hay version oscura en la biblioteca: sobre fondo claro era
     invisible. Se detecto en la primera captura headless.
     §1.1 asigna DEEP NAVY a "navegacion", asi que esto es ademas lo que el
     sistema visual aprobado pide. */
  background: rgba(11,31,51,.92);
  backdrop-filter: saturate(180%) blur(10px);
  border-bottom: 1px solid rgba(255,255,255,.12);
}
.inv-header__inner {
  display: flex; align-items: center; gap: var(--inv-space-4);
  min-height: var(--inv-header-h);
}

.inv-header__brand { display: inline-flex; align-items: center; flex: 0 0 auto; }
.inv-header__logo  { width: auto; height: 44px; object-fit: contain; }
.inv-header__wordmark {
  font-family: var(--inv-font-heading); font-weight: var(--inv-fw-bold);
  font-size: 1.35rem; letter-spacing: -.02em; color: var(--inv-on-dark);
}

.inv-nav { display: flex; align-items: center; gap: var(--inv-space-4); margin-left: auto; }
.inv-nav__list {
  display: flex; align-items: center; gap: var(--inv-space-3);
  list-style: none; margin: 0; padding: 0;
}
.inv .inv-nav__link {
  display: inline-block; padding: 8px 2px;
  color: var(--inv-on-dark-muted); text-decoration: none;
  font-family: var(--inv-font-heading);
  font-size: .975rem; font-weight: var(--inv-fw-medium);
  position: relative;
}
/* Subrayado que crece desde el centro. Movimiento mínimo, sin desplazar
   texto: §9.4 prohíbe que el texto se mueva. */
.inv-nav__link::after {
  content: ""; position: absolute; left: 50%; right: 50%; bottom: 2px; height: 2px;
  background: var(--inv-cyan-bright); border-radius: 2px;
  transition: left var(--inv-duration-micro) var(--inv-ease),
              right var(--inv-duration-micro) var(--inv-ease);
}
.inv-nav__link:hover::after,
.inv-nav__link:focus-visible::after { left: 0; right: 0; }
.inv .inv-nav__link:hover,
.inv .inv-nav__link:focus-visible { color: var(--inv-on-dark); }

.inv-nav__cta { min-height: 46px; padding-inline: var(--inv-space-3); font-size: .95rem; }

/* Botón de menú: sólo visible por debajo de 992px. */
.inv-header__toggle {
  display: none; margin-left: auto;
  width: 46px; height: 46px; align-items: center; justify-content: center;
  background: transparent; border: 1px solid rgba(255,255,255,.28);
  border-radius: var(--inv-radius-sm); cursor: pointer; color: var(--inv-on-dark);
}
.inv-header__burger,
.inv-header__burger::before,
.inv-header__burger::after {
  display: block; width: 20px; height: 2px; border-radius: 2px;
  background: currentColor; transition: transform var(--inv-duration-base) var(--inv-ease),
                                        opacity var(--inv-duration-micro) var(--inv-ease);
}
.inv-header__burger { position: relative; }
.inv-header__burger::before,
.inv-header__burger::after { content: ""; position: absolute; left: 0; }
.inv-header__burger::before { top: -6px; }
.inv-header__burger::after  { top: 6px; }
/* Estado abierto: las tres barras se convierten en una X. */
[aria-expanded="true"] .inv-header__burger { background: transparent; }
[aria-expanded="true"] .inv-header__burger::before { transform: translateY(6px) rotate(45deg); }
[aria-expanded="true"] .inv-header__burger::after  { transform: translateY(-6px) rotate(-45deg); }

/* ==========================================================================
   PIE INVEXUS  (§12 SECTION 11)
   ========================================================================== */
.inv-footer {
  background: var(--inv-navy);
  color: var(--inv-on-dark-muted);
  padding-block: var(--inv-space-7) var(--inv-space-4);
  margin-top: 0;
}
.inv-footer__top {
  display: grid;
  /* minmax(0,...) es imprescindible: con 1fr a secas, min-width:auto impide
     que la columna baje del ancho de su enlace mas largo y el pie desborda.
     Medido por CDP a 1440: scrollWidth 1449 contra viewport 1425. */
  grid-template-columns: 1.5fr repeat(4, minmax(0, 1fr));
  gap: var(--inv-space-5);
  padding-bottom: var(--inv-space-6);
  border-bottom: 1px solid rgba(255,255,255,.12);
}
.inv-footer__logo { width: auto; height: 46px; object-fit: contain; }
.inv-footer__claim {
  margin-top: var(--inv-space-3); max-width: 26ch;
  font-size: var(--inv-fs-small); color: var(--inv-on-dark-muted);
}

.inv-footer__social {
  display: flex; gap: 10px; list-style: none; margin: var(--inv-space-4) 0 0; padding: 0;
}
.inv .inv-footer__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: var(--inv-radius-sm);
  border: 1px solid rgba(255,255,255,.18);
  color: var(--inv-on-dark-muted);
  transition: background-color var(--inv-duration-micro) var(--inv-ease),
              color var(--inv-duration-micro) var(--inv-ease),
              border-color var(--inv-duration-micro) var(--inv-ease);
}
.inv .inv-footer__social a:hover {
  background: rgba(255,255,255,.10);
  color: var(--inv-on-dark); border-color: rgba(255,255,255,.4);
}

.inv-footer__title {
  font-family: var(--inv-font-heading);
  font-size: .82rem; font-weight: var(--inv-fw-bold);
  text-transform: uppercase; letter-spacing: .1em;
  color: var(--inv-on-dark); margin: 0 0 var(--inv-space-3);
}
.inv-footer__col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.inv .inv-footer__col a {
  display: inline-flex; align-items: center; min-height: 26px;
  color: var(--inv-on-dark-muted); text-decoration: none; font-size: .93rem;
  transition: color var(--inv-duration-micro) var(--inv-ease);
}
.inv .inv-footer__col a:hover { color: var(--inv-on-dark); text-decoration: underline; }

.inv-footer__bottom {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--inv-space-2); padding-top: var(--inv-space-4);
}
.inv-footer__legal { margin: 0; font-size: var(--inv-fs-small); }

/*
 * ENLACES LEGALES DEL PIE
 *
 * Este bloque NO EXISTIA. La <nav> de enlaces legales solo se renderiza
 * cuando las paginas de privacidad, cookies y terminos estan PUBLICADAS, y
 * eso ocurrio el 31/08/2026. Hasta ese dia no habia nada que estilar y nadie
 * podia haberlo visto.
 *
 * Medidos a 360px salian de 20px de alto y pegados entre si. Dos problemas
 * distintos en el mismo sitio:
 *   · 24px es el minimo de un objetivo tactil (WCAG 2.2, 2.5.8). Por debajo,
 *     el dedo falla.
 *   · sin separacion horizontal, quien apunta a "Terminos" pulsa "Cookies".
 *     Y estos tres enlaces en concreto son a los que alguien acude cuando
 *     quiere saber que se hace con sus datos: no es donde conviene fallar.
 *
 * El gap vertical evita ademas que las tres etiquetas se toquen al envolver
 * en dos lineas, que es lo que hacen por debajo de 380px.
 */
.inv-footer__legal-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--inv-space-1) var(--inv-space-3);
}
.inv .inv-footer__legal-links a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  color: var(--inv-on-dark-muted);
  text-decoration: none;
  font-size: var(--inv-fs-small);
  transition: color var(--inv-duration-micro) var(--inv-ease);
}
.inv .inv-footer__legal-links a:hover,
.inv .inv-footer__legal-links a:focus-visible {
  color: var(--inv-on-dark);
  text-decoration: underline;
}
.inv .inv-footer__contact {
  display: inline-flex; align-items: center; gap: 8px; min-height: 28px;
  color: var(--inv-on-dark-muted); text-decoration: none; font-size: var(--inv-fs-small);
}
.inv .inv-footer__contact:hover { color: var(--inv-on-dark); }

/* La cabecera pegajosa no debe tapar el destino de un ancla interna. */
.inv-main, :target { scroll-margin-top: calc(var(--inv-header-h) + 14px); }

/* ==========================================================================
   PÁGINAS INTERNAS
   Los mismos tokens, tarjetas e iconos que la Home. No es un sistema aparte.
   ========================================================================== */

/* --- Hero de página interna ------------------------------------------------
   Más bajo que el de la Home: aquí el visitante ya sabe dónde está y lo que
   necesita es entrar en materia, no otro impacto a pantalla completa. */
.inv-phero {
  background-image: var(--inv-scrim-dark), var(--inv-gradient-brand);
  background-color: var(--inv-navy);
  color: var(--inv-on-dark);
  padding-block: var(--inv-space-7) var(--inv-space-6);
  position: relative;
}
.inv-phero .inv-eyebrow { color: var(--inv-cyan-bright); }
.inv .inv-phero__title {
  color: var(--inv-on-dark);
  font-size: var(--inv-fs-h1);
  max-width: 20ch;
  margin-bottom: var(--inv-space-3);
}
.inv .inv-phero__lead {
  color: var(--inv-on-dark-muted);
  font-size: var(--inv-fs-body-lg);
  max-width: 62ch;
}
.inv-phero__actions { margin-top: var(--inv-space-5); }

/* --- Proceso por pasos ------------------------------------------------------ */
.inv-steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--inv-space-4);
  counter-reset: none;
}
.inv-steps__item {
  position: relative;
  padding-left: var(--inv-space-6);
  padding-bottom: var(--inv-space-4);
  border-left: 2px solid var(--inv-border);
}
.inv-steps__item:last-child { border-left-color: transparent; padding-bottom: 0; }
.inv-steps__num {
  position: absolute; left: 0; top: 0;
  transform: translateX(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--inv-navy); color: var(--inv-on-dark);
  font-family: var(--inv-font-heading); font-size: .78rem;
  font-weight: var(--inv-fw-bold); letter-spacing: .02em;
}
.inv-steps__title { margin-bottom: 6px; }
.inv-steps__text  { color: var(--inv-muted); margin: 0; max-width: 62ch; }

/* --- Listas de verificación ------------------------------------------------- */
.inv-checklist { list-style: none; margin: var(--inv-space-3) 0 0; padding: 0;
                 display: grid; gap: 12px; }
.inv-checklist li { display: flex; align-items: flex-start; gap: 12px; }
.inv-checklist__icon { color: var(--inv-green-ink); margin-top: 2px; }

/* --- Otras soluciones ------------------------------------------------------- */
.inv-related { list-style: none; margin: var(--inv-space-3) 0 0; padding: 0;
               display: flex; flex-wrap: wrap; gap: 10px; }
.inv .inv-related a {
  display: inline-flex; align-items: center; gap: 8px; min-height: 40px;
  padding: 6px 16px; border-radius: var(--inv-radius-pill);
  border: 1px solid var(--inv-border); color: var(--inv-ink-strong);
  text-decoration: none; font-size: .93rem;
  transition: border-color var(--inv-duration-micro) var(--inv-ease),
              color var(--inv-duration-micro) var(--inv-ease);
}
.inv .inv-related a:hover { border-color: var(--inv-brand-ink); color: var(--inv-brand-ink); }

/* --- Estado vacío -----------------------------------------------------------
   Se usa cuando no hay datos reales. Explica qué falta en vez de dejar un
   hueco o, peor, rellenar con contenido inventado. */
.inv-empty {
  text-align: center; padding: var(--inv-space-6) var(--inv-space-3);
  border: 1px dashed var(--inv-border); border-radius: var(--inv-radius-md);
  background: var(--inv-surface);
}
.inv-empty__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--inv-soft); color: var(--inv-brand-ink);
  margin-bottom: var(--inv-space-3);
}
.inv-empty__title { margin-bottom: 8px; }
.inv-empty__text  { color: var(--inv-muted); margin: 0 auto; max-width: 48ch; }

/* --- Contenido del editor con estilos del sistema --------------------------- */
.inv-prose h2 { margin-top: var(--inv-space-5); }
.inv-prose h3 { margin-top: var(--inv-space-4); }
.inv-prose p, .inv-prose li { color: var(--inv-text); }
.inv-prose ul, .inv-prose ol { padding-left: 1.25rem; display: grid; gap: 8px; }
.inv-prose .inv-brief {
  border-left: 3px solid var(--inv-warning-ink);
  background: var(--inv-badge-warn-bg);
  padding: var(--inv-space-3); border-radius: var(--inv-radius-sm);
  margin-bottom: var(--inv-space-5);
}
.inv-prose .inv-brief p { margin: 0; color: var(--inv-warning-ink); }

/* ==========================================================================
   ARCHIVOS, FICHAS Y FORMULARIO
   ========================================================================== */

/* --- Migas de pan ----------------------------------------------------------- */
.inv-breadcrumbs { margin-bottom: var(--inv-space-3); }
.inv-breadcrumbs ol {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  font-size: var(--inv-fs-small);
}
.inv-breadcrumbs li + li::before { content: "/"; margin-right: 6px; opacity: .5; }
/* Los enlaces de migas son navegacion, no texto en linea dentro de un parrafo:
   les aplica el minimo de 24px de WCAG 2.5.8. Median 18px de alto. */
.inv .inv-breadcrumbs a,
.inv-breadcrumbs [aria-current] {
  display: inline-flex; align-items: center; min-height: 26px;
}
.inv-phero .inv-breadcrumbs { color: var(--inv-on-dark-muted); }
.inv .inv-phero .inv-breadcrumbs a { color: var(--inv-on-dark-muted); }
.inv .inv-phero .inv-breadcrumbs a:hover { color: var(--inv-on-dark); }
.inv-breadcrumbs [aria-current] { opacity: .75; }

.inv-phero__meta { color: var(--inv-on-dark-muted); font-size: var(--inv-fs-small);
                   margin-top: var(--inv-space-2); }

/* --- Barra de filtros -------------------------------------------------------
   Formulario normal por GET: funciona sin JS, cada combinacion tiene URL
   propia y el boton atras se comporta como el usuario espera. */
.inv-filtros {
  display: grid; gap: var(--inv-space-2);
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  align-items: end;
  padding: var(--inv-space-3);
  background: var(--inv-surface);
  border: 1px solid var(--inv-border);
  border-radius: var(--inv-radius-md);
  margin-bottom: var(--inv-space-4);
}
.inv-filtros__campo { display: grid; gap: 6px; min-width: 0; }
.inv-filtros label,
.inv-form label {
  font-size: var(--inv-fs-small); font-weight: var(--inv-fw-semibold);
  color: var(--inv-ink-strong);
}
.inv-filtros input, .inv-filtros select,
.inv-form input, .inv-form select, .inv-form textarea {
  width: 100%; min-height: 48px;              /* §14 exige 48-52px */
  padding: 10px 14px;
  border: 1px solid var(--inv-border);
  border-radius: var(--inv-radius-sm);
  background: var(--inv-surface);
  color: var(--inv-text);
  font-family: var(--inv-font-body); font-size: var(--inv-fs-body);
}
.inv-form textarea { min-height: 130px; padding-top: 12px; resize: vertical; }
.inv-filtros input:focus-visible, .inv-filtros select:focus-visible,
.inv-form input:focus-visible, .inv-form select:focus-visible,
.inv-form textarea:focus-visible { border-color: var(--inv-brand-ink); }
.inv-filtros__acciones { display: flex; align-items: center; gap: var(--inv-space-2); }
.inv .inv-filtros__limpiar { font-size: var(--inv-fs-small); min-height: 28px;
                             display: inline-flex; align-items: center; }

.inv-resultados { color: var(--inv-muted); font-size: var(--inv-fs-small);
                  margin: 0 0 var(--inv-space-3); }

/* --- Listado de convocatorias ----------------------------------------------- */
.inv-funding__list--archive { display: grid; gap: var(--inv-space-3);
                              grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.inv-funding-card__title { margin: 6px 0 8px; }
.inv .inv-funding-card__title a { color: var(--inv-ink-strong); text-decoration: none; }
.inv .inv-funding-card__title a:hover { color: var(--inv-brand-ink); }
.inv-funding-card__resumen { color: var(--inv-muted); font-size: .95rem;
                             margin: 0 0 var(--inv-space-2); }
.inv-funding-card__urgencia { font-size: var(--inv-fs-small); color: var(--inv-warning-ink);
                              font-weight: var(--inv-fw-semibold); }
.inv-funding-card__meta { display: grid; gap: 6px; margin: 0; }
.inv-funding-card__meta > div { display: flex; gap: 8px; font-size: var(--inv-fs-small); }
.inv-funding-card__meta dt { color: var(--inv-muted); min-width: 72px; }
.inv-funding-card__meta dd { margin: 0; color: var(--inv-text); font-weight: var(--inv-fw-medium); }
.inv-funding-card__verif { font-size: .8rem; color: var(--inv-muted);
                           margin: var(--inv-space-2) 0 0; }
.inv-badge--soon   { background: var(--inv-soft); color: var(--inv-brand-ink); }
.inv-badge--closed { background: var(--inv-border); color: var(--inv-muted); }
.inv-badge--soon::before, .inv-badge--closed::before { content: none; }

/* --- Ficha lateral ---------------------------------------------------------- */
.inv-ficha {
  background: var(--inv-surface); border: 1px solid var(--inv-border);
  border-radius: var(--inv-radius-md); padding: var(--inv-space-3);
  align-self: start; position: sticky; top: 100px;
}
.inv-ficha__lista { display: grid; gap: 12px; margin: 0 0 var(--inv-space-3); }
.inv-ficha__lista dt { font-size: var(--inv-fs-small); color: var(--inv-muted); }
.inv-ficha__lista dd { margin: 2px 0 0; font-weight: var(--inv-fw-medium); color: var(--inv-ink-strong); }
/*
 * Algunos campos de la ficha son un dato suelto y otros son prosa de varios
 * parrafos: 'Publico objetivo' enumera nueve tipos de entidad. El <p> propio
 * del navegador anadiria un margen superior que separaria el primer parrafo
 * de su <dt>, asi que el espacio se pone SOLO entre parrafos.
 */
.inv-ficha__lista dd > p { margin: 0; }
.inv-ficha__lista dd > p + p { margin-top: .55em; }
.inv-ficha__cta { width: 100%; }
.inv-ficha__fuente, .inv-ficha__aviso {
  font-size: .8rem; color: var(--inv-muted); margin: var(--inv-space-3) 0 0;
}
.inv-ficha__aviso { border-top: 1px solid var(--inv-border); padding-top: var(--inv-space-2); }

/*
 * El enlace a la fuente es un objetivo tactil, no texto corrido.
 *
 * A 0.8rem su caja medía 372x16 px: el barrido responsive lo marcó a 1440 y a
 * 768. En móvil pasaba de largo sólo porque el texto envuelve a dos líneas, lo
 * que no es una solución sino una casualidad del ancho.
 *
 * Con inline-block y 4px arriba y abajo la caja llega a 24px, el mínimo de la
 * WCAG 2.2 para objetivos, sin mover ni un píxel del texto que la rodea.
 */
.inv-ficha__fuente a {
  display: inline-block;
  padding-block: 4px;
}

/* --- Tarjetas con imagen ----------------------------------------------------- */
.inv-case-card, .inv-insight-card { padding: 0; overflow: hidden; }
.inv-case-card__media, .inv-insight-card__media { aspect-ratio: 16 / 10; background: var(--inv-soft); }
.inv-case-card__media img, .inv-insight-card__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--inv-duration-base) var(--inv-ease);
}
@media (hover: hover) and (pointer: fine) {
  /* §9.3 autoriza scale 1.02 en la imagen del caso. Nada mas. */
  .inv-case-card:hover .inv-case-card__media img { transform: scale(1.02); }
}
.inv-case-card__body, .inv-insight-card__body { padding: var(--inv-space-3); }
.inv-case-card__meta { display: flex; gap: var(--inv-space-3); margin: var(--inv-space-2) 0; }
.inv-case-card__meta dt { font-size: .78rem; color: var(--inv-muted); }
.inv-case-card__meta dd { margin: 0; font-weight: var(--inv-fw-semibold); color: var(--inv-ink-strong); }
.inv-metric__value--sm { font-size: 1.5rem; }

/* --- Paginacion -------------------------------------------------------------- */
.inv-pagination { margin-top: var(--inv-space-5); }
.inv-pagination ul { list-style: none; display: flex; flex-wrap: wrap; gap: 8px;
                     margin: 0; padding: 0; justify-content: center; }
.inv-pagination .page-numbers {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0 12px;
  border: 1px solid var(--inv-border); border-radius: var(--inv-radius-sm);
  color: var(--inv-ink-strong); text-decoration: none;
}
.inv-pagination .page-numbers.current {
  background: var(--inv-brand-ink); color: var(--inv-surface); border-color: var(--inv-brand-ink);
}

/* --- Formulario -------------------------------------------------------------- */
.inv-form { display: grid; gap: var(--inv-space-3); margin-top: var(--inv-space-4); }
.inv-field { display: grid; gap: 6px; min-width: 0; }
.inv-field--check { grid-template-columns: auto 1fr; align-items: start; gap: 12px; }
/* 24px es el minimo de WCAG 2.5.8 (AA). A 22 se quedaba justo por debajo. */
.inv-field--check input { width: 24px; min-height: 24px; height: 24px; margin-top: 1px; }
.inv-field--error input, .inv-field--error select, .inv-field--error textarea {
  border-color: var(--inv-error-ink); border-width: 2px;
}
.inv-field__error { color: var(--inv-error-ink); font-size: var(--inv-fs-small);
                    font-weight: var(--inv-fw-medium); margin: 0; }
.inv-field__ayuda { color: var(--inv-muted); font-size: var(--inv-fs-small); margin: 0; }
.inv-field__opt { color: var(--inv-muted); font-weight: var(--inv-fw-body); }
.inv-req { color: var(--inv-error-ink); }
.inv-form__nota { font-size: var(--inv-fs-small); color: var(--inv-muted); margin: 0; }

/* Campo trampa: fuera de pantalla, NUNCA display:none. Algunos bots detectan
   display:none y lo saltan; moverlo fuera del viewport es mas fiable. */
.inv-hp { position: absolute !important; left: -9999px; width: 1px; height: 1px;
          overflow: hidden; }

/* --- Avisos ------------------------------------------------------------------ */
.inv-alert { padding: var(--inv-space-3); border-radius: var(--inv-radius-md);
             margin-bottom: var(--inv-space-4); border-left: 4px solid; }
.inv-alert h2 { font-size: var(--inv-fs-h3); margin-bottom: 6px; }
.inv-alert p { margin: 0 0 6px; }
.inv-alert--ok      { background: var(--inv-badge-ok-bg); border-color: var(--inv-green-ink); }
.inv-alert--ok h2   { color: var(--inv-green-ink); }
.inv-alert--error   { background: var(--inv-error-bg); border-color: var(--inv-error-ink); }
.inv-alert--error h2 { color: var(--inv-error-ink); }
.inv-alert--aviso   { background: var(--inv-badge-warn-bg); border-color: var(--inv-warning-ink);
                      color: var(--inv-warning-ink); font-size: var(--inv-fs-small); }
.inv-alert__nota    { font-size: var(--inv-fs-small); color: var(--inv-muted); }

.inv-empty__actions { justify-content: center; margin-top: var(--inv-space-4); }

/* =========================================================================
   BLOQUES DE ARGUMENTO · transform · chain · routes · categories
   -------------------------------------------------------------------------
   Añadidos el 30/08/2026 para la auditoría del director (P1 y P2).

   Existen por dos razones, no sólo por estética:
   1. Comunican relaciones que una rejilla de tarjetas no comunica: un cambio
      de estado, una dependencia encadenada, dos caminos alternativos.
   2. Rompen la monotonía. Seis páginas seguidas de "tres tarjetas con icono"
      se leen todas igual aunque digan cosas distintas.

   Ninguno introduce color, radio, sombra ni tipografía fuera de tokens.
   ========================================================================= */

/* --- TRANSFORM · hoy -> después ----------------------------------------- */
.inv-transform {
  list-style: none;
  margin: var(--inv-space-5) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--inv-space-2);
}
.inv-transform__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: stretch;
  gap: var(--inv-space-2);
}
.inv-transform__side {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--inv-space-3);
  border-radius: var(--inv-radius-md);
  border: 1px solid var(--inv-border);
  background: var(--inv-surface);
}
/* La orilla izquierda es el problema: apagada, sin peso visual. */
.inv-transform__side--from {
  background: transparent;
  border-style: dashed;
}
.inv-transform__side--from .inv-transform__txt { color: var(--inv-muted); }
/* La derecha es el resultado: es donde debe caer la mirada. */
.inv-transform__side--to {
  border-left: 3px solid var(--inv-green-ink);
}
.inv-transform__tag {
  font-size: var(--inv-fs-small);
  font-weight: var(--inv-fw-semibold);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--inv-muted);
}
.inv-transform__side--to .inv-transform__tag { color: var(--inv-green-ink); }
.inv-transform__txt {
  font-weight: var(--inv-fw-medium);
  color: var(--inv-text);
  line-height: 1.4;
}
.inv-transform__arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--inv-brand-ink);
  flex: 0 0 auto;
}

/* --- CHAIN · etapas encadenadas ----------------------------------------- */
.inv-chain {
  list-style: none;
  margin: var(--inv-space-5) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--inv-space-2);
  counter-reset: inv-chain;
}
.inv-chain__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: var(--inv-space-3);
  border-radius: var(--inv-radius-md);
  background: var(--inv-surface);
  border: 1px solid var(--inv-border);
  position: relative;
}
/* El conector visual entre etapas. Decorativo: no lo lee nadie. */
.inv-chain__item + .inv-chain__item::before {
  content: "";
  position: absolute;
  left: calc(var(--inv-space-2) * -1);
  top: 50%;
  width: var(--inv-space-2);
  height: 1px;
  background: var(--inv-border);
}
.inv-chain__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--inv-radius-sm);
  background: var(--inv-soft);
  color: var(--inv-brand-ink);
}
.inv-chain__name {
  font-weight: var(--inv-fw-semibold);
  font-size: var(--inv-fs-small);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--inv-ink-strong);
}
.inv-chain__text {
  color: var(--inv-muted);
  font-size: .92rem;
  line-height: 1.45;
}
.inv-chain__note {
  margin: var(--inv-space-4) 0 0;
  color: var(--inv-muted);
  max-width: 68ch;
}

/* --- ROUTES · dos caminos de entrada ------------------------------------ */
.inv-route {
  padding: var(--inv-space-4);
  border-radius: var(--inv-radius-md);
  background: var(--inv-surface);
  border: 1px solid var(--inv-border);
  border-top: 3px solid var(--inv-brand-ink);
}
.inv-route:nth-child(2) { border-top-color: var(--inv-cyan-ink); }
.inv-route__label {
  margin: 0 0 6px;
  font-size: var(--inv-fs-small);
  font-weight: var(--inv-fw-semibold);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--inv-brand-ink);
}
.inv-route:nth-child(2) .inv-route__label { color: var(--inv-cyan-ink); }
.inv-route__title { margin: 0 0 10px; }
.inv-route__quote {
  margin: 0 0 var(--inv-space-3);
  padding-left: var(--inv-space-3);
  border-left: 2px solid var(--inv-border);
  color: var(--inv-muted);
  font-style: italic;
}
.inv-route__group {
  margin: var(--inv-space-3) 0 6px;
  font-size: var(--inv-fs-small);
  font-weight: var(--inv-fw-semibold);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--inv-ink-strong);
}
.inv-route__list {
  margin: 0;
  padding-left: 1.1rem;
  color: var(--inv-muted);
  line-height: 1.6;
}
.inv-route__list li { margin-bottom: 2px; }

/* --- CATEGORIES · familias de un mismo servicio ------------------------- */
.inv-cat {
  position: relative;
  padding: var(--inv-space-4);
  padding-top: var(--inv-space-5);
  border-radius: var(--inv-radius-md);
  background: var(--inv-surface);
  border: 1px solid var(--inv-border);
}
.inv-cat__letter {
  position: absolute;
  top: var(--inv-space-3);
  right: var(--inv-space-3);
  font-size: 2.4rem;
  font-weight: var(--inv-fw-bold);
  line-height: 1;
  color: var(--inv-brand);
  opacity: .16;
}
.inv-cat__title { margin: 0 0 8px; padding-right: 2.6rem; }
.inv-cat__text  { margin: 0 0 var(--inv-space-3); color: var(--inv-muted); }
.inv-cat__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.inv-cat__list li {
  font-size: var(--inv-fs-small);
  color: var(--inv-text);
  background: var(--inv-soft);
  border-radius: var(--inv-radius-sm);
  padding: 4px 10px;
}
.inv-cat__note {
  margin: var(--inv-space-4) 0 0;
  color: var(--inv-muted);
  max-width: 72ch;
}

/* --- Estado vacío dentro de una columna, no de una página --------------- */
/* El de Funding Radar vive en la mitad derecha del split, no centrado en la
   página, así que su relleno vertical debe ser menor o desequilibra la fila. */
.inv-funding__list .inv-empty {
  padding-top: var(--inv-space-4);
  padding-bottom: var(--inv-space-4);
  text-align: left;
  background: var(--inv-surface);
  border: 1px dashed var(--inv-border);
  border-radius: var(--inv-radius-md);
}
.inv-funding__list .inv-empty__text { margin: 0; max-width: none; }

/* --- Franja de KPI con pocas cifras -------------------------------------
   La franja se diseñó para cuatro métricas repartidas a lo ancho. Con las
   cifras vigentes son dos (proyectos y financiamiento; regiones e
   instrumentos siguen sin autorizar), y dos celdas de 600px con el número
   pegado a la izquierda dejaban la banda visualmente vacía.

   Con dos o tres, la fila se centra y se limita su ancho. El componente ya
   emite inv-grid--2 o --3 según cuántas haya, así que basta con estas dos
   reglas y no hace falta tocar PHP. Cuando el director autorice las otras
   cifras, el grid vuelve a --4 y estas reglas dejan de aplicar solas.       */
.inv-proof__grid.inv-grid--2,
.inv-proof__grid.inv-grid--3 {
  max-width: 62rem;
  margin-inline: auto;
  justify-items: center;
  text-align: center;
}

/* --- Tarjeta de bloque pulsable -----------------------------------------
   Mismo patron ya probado en la rejilla de soluciones de la Home: el enlace
   del titulo se estira por encima de toda la tarjeta con un ::before.

   Por que asi y no envolviendo la tarjeta en un <a>: envolverla meteria el
   <h3> dentro del enlace y romperia la navegacion por encabezados de los
   lectores de pantalla. Con este patron queda UN solo enlace por tarjeta,
   con el titulo como nombre accesible, y sin enlaces anidados.

   Las tarjetas sin destino no reciben la clase y se comportan como antes.  */
.inv-card--link .inv-card__title a {
  color: var(--inv-ink-strong);
  text-decoration: none;
}
.inv-card--link .inv-card__title a::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.inv-card--link:hover .inv-card__title a,
.inv-card--link:focus-within .inv-card__title a {
  color: var(--inv-brand-ink);
}
/* El cursor confirma que toda la superficie responde. */
.inv-card--link { cursor: pointer; }

/* --- Tarjeta de convocatoria en la Home ---------------------------------
   Añadido el 30/08/2026 al publicar las tres primeras oportunidades reales.

   La jerarquía es deliberada: entidad pequeña arriba, título grande, y el
   cierre con los días restantes destacado. Los días son lo que de verdad
   mueve a alguien: una fecha suelta obliga a calcular si da tiempo.

   El presupuesto NO aparece en esta tarjeta. Es el presupuesto del concurso
   entero y aquí no hay espacio para matizarlo, así que se leería como el
   monto que puede pedir un postulante. La ficha completa sí lo explica.   */
.inv-funding-card__entity {
  margin: 0 0 4px;
  font-size: var(--inv-fs-small);
  font-weight: var(--inv-fw-semibold);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--inv-muted);
}
.inv-funding-card__cierre {
  margin: 8px 0 0;
  font-size: var(--inv-fs-small);
  font-weight: var(--inv-fw-medium);
  color: var(--inv-text);
}

/* Aviso discreto, no alarmante: informa sin competir con el título. */
.inv-funding-card__parcial {
  margin: 6px 0 0;
  font-size: .8rem;
  color: var(--inv-muted);
  display: flex;
  align-items: center;
  gap: 6px;
}
.inv-funding-card__parcial::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--inv-warning-ink);
  flex: 0 0 auto;
}

/* ==========================================================================
   CONTACTO
   ==========================================================================
   Sustituye al armazón de Elementor. Dos zonas: los canales directos, con
   WhatsApp Business destacado, y el formulario de siempre.

   En escritorio son dos columnas; en móvil, una. El formulario baja al final
   porque quien tiene prisa usa WhatsApp, y quien quiere escribir con detalle
   ya ha decidido bajar.
   ========================================================================== */
.inv-contacto__split {
  display: grid;
  gap: var(--inv-space-5);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  align-items: start;
}
@media (max-width: 900px) {
  .inv-contacto__split { grid-template-columns: 1fr; gap: var(--inv-space-4); }
}

/* --- WhatsApp · el único con superficie propia -----------------------------
   La jerarquía la marca el material, no el tamaño de la letra: éste es el
   único canal con superficie, icono grande y sombra. Los demás son enlaces. */
.inv-contacto__wa {
  display: flex; align-items: center; gap: var(--inv-space-3);
  margin-top: var(--inv-space-3);
  padding: var(--inv-space-3);
  border-radius: var(--inv-radius-lg);
  text-decoration: none;
  color: var(--inv-ink-strong);
  box-shadow: var(--inv-shadow-sm);
  /* Sobre fondo claro el vidrio no refracta nada, así que aquí la superficie
     es un tinte verde de WhatsApp muy leve en vez de la transparencia. */
  background: color-mix(in srgb, var(--inv-whatsapp) 8%, var(--inv-surface));
  border: 1px solid color-mix(in srgb, var(--inv-whatsapp) 28%, var(--inv-border));
  transition: transform var(--inv-duration-base) var(--inv-ease),
              box-shadow var(--inv-duration-base) var(--inv-ease),
              border-color var(--inv-duration-base) var(--inv-ease);
}
@media (hover: hover) and (pointer: fine) {
  .inv-contacto__wa:hover {
    transform: translate3d(0, calc(-1 * var(--inv-lift)), 0);
    box-shadow: var(--inv-shadow-md);
    border-color: var(--inv-whatsapp);
  }
}
.inv-contacto__wa:focus-visible { outline: 3px solid var(--inv-color-focus); outline-offset: 3px; }

.inv-contacto__wa-icono {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; border-radius: var(--inv-radius-pill);
  background: var(--inv-whatsapp); color: var(--inv-whatsapp-fg);
}
.inv-contacto__wa-icono svg { width: 28px; height: 28px; display: block; }

.inv-contacto__wa-texto { display: grid; gap: 2px; min-width: 0; }
.inv-contacto__wa-texto strong {
  font-family: var(--inv-font-heading);
  font-size: 1.12rem; font-weight: var(--inv-fw-semibold);
  letter-spacing: -.01em;
}
.inv-contacto__wa-num {
  font-variant-numeric: tabular-nums;
  font-size: var(--inv-fs-body); color: var(--inv-text);
}
.inv-contacto__wa-nota { font-size: var(--inv-fs-small); color: var(--inv-muted); }

/* --- los otros tres canales ---------------------------------------------- */
.inv-contacto__lista {
  list-style: none; margin: var(--inv-space-4) 0 0; padding: 0;
  display: grid; gap: var(--inv-space-2);
}
.inv-contacto__lista a {
  display: grid; gap: 2px;
  padding: var(--inv-space-2) var(--inv-space-3);
  border: 1px solid var(--inv-border);
  border-radius: var(--inv-radius-md);
  text-decoration: none;
  color: var(--inv-ink-strong);
  min-height: 44px;
  transition: border-color var(--inv-duration-fast) var(--inv-ease),
              transform var(--inv-duration-base) var(--inv-ease);
  /* Un correo largo no puede desbordar la tarjeta en 360 px. */
  overflow-wrap: anywhere;
}
@media (hover: hover) and (pointer: fine) {
  .inv-contacto__lista a:hover {
    border-color: var(--inv-cyan-ink);
    transform: translate3d(0, calc(-1 * var(--inv-lift)), 0);
  }
}
.inv-contacto__lista a:focus-visible { outline: 3px solid var(--inv-color-focus); outline-offset: 2px; }
.inv-contacto__et  { font-size: var(--inv-fs-small); color: var(--inv-muted); }
.inv-contacto__val { font-weight: var(--inv-fw-medium); }
/* El correo institucional pesa más que los otros dos, y se ve. */
.inv-contacto__lista li.is-destacado a { border-color: color-mix(in srgb, var(--inv-brand-ink) 45%, var(--inv-border)); }
.inv-contacto__lista li.is-destacado .inv-contacto__val { color: var(--inv-brand-ink); font-weight: var(--inv-fw-semibold); }

.inv-contacto__nota { margin-top: var(--inv-space-3); font-size: var(--inv-fs-small); }

/* --- el formulario -------------------------------------------------------- */
/* SUPERFICIE PROPIA, no vidrio. Ver la nota en template-contacto.php: detrás
   de esta sección no hay nada que refractar, así que el panel se dibuja con
   tokens sólidos. --inv-bg es un gris azulado muy leve de día y casi negro de
   noche; en los dos casos se separa de la superficie de la sección, que es lo
   único que este panel tiene que hacer. */
.inv-contacto__form {
  padding: var(--inv-space-4);
  border-radius: var(--inv-radius-lg);
  background: var(--inv-bg);
  border: 1px solid var(--inv-border);
}
.inv-contacto__form > h2 { margin-top: 0; }
/* WPForms trae sus propios márgenes generosos; se ajustan al ritmo del sitio
   sin tocar el marcado del plugin. */
.inv-contacto__form .wpforms-container { margin: var(--inv-space-3) 0 0; }
.inv-contacto__form .wpforms-form .wpforms-field { padding: 0 0 var(--inv-space-3); }
.inv-contacto__form .wpforms-form input[type="text"],
.inv-contacto__form .wpforms-form input[type="email"],
.inv-contacto__form .wpforms-form textarea {
  width: 100%;
  min-height: 48px;
  padding: 10px var(--inv-space-2);
  border: 1px solid var(--inv-border);
  border-radius: var(--inv-radius-btn);
  /* Los campos van sobre --inv-surface y el panel sobre --inv-bg: el campo
     tiene que verse MAS claro que su panel de día y más claro que él de
     noche. Si ambos usaran el mismo token, el campo desaparecería dentro del
     panel y sólo lo delataría el borde. */
  background: var(--inv-surface);
  color: var(--inv-text);
  font-family: var(--inv-font-body);
  font-size: var(--inv-fs-body);
}
.inv-contacto__form .wpforms-form textarea { min-height: 9rem; resize: vertical; }
.inv-contacto__form .wpforms-form input:focus-visible,
.inv-contacto__form .wpforms-form textarea:focus-visible {
  outline: 3px solid var(--inv-color-focus); outline-offset: 2px;
}
.inv-contacto__form .wpforms-form label.wpforms-field-label {
  font-size: var(--inv-fs-small); font-weight: var(--inv-fw-semibold);
  color: var(--inv-ink-strong); margin-bottom: 6px; display: block;
}
.inv-contacto__form .wpforms-form .wpforms-required-label { color: var(--inv-error-ink); }
/* La casilla de consentimiento y su enlace a privacidad. El objetivo táctil
   es la etiqueta entera, no sólo el cuadradito de 13 px.

   EL FLEX VA EN EL <li>, NUNCA EN LA ETIQUETA, y esto costó una captura.
   La primera versión ponía display:flex en `.wpforms-field-checkbox label`.
   Eso hacía dos cosas mal a la vez:

     1. El selector alcanzaba TAMBIÉN a la etiqueta del grupo («Protección de
        datos»), que no es una fila de nada.
     2. Peor: en la etiqueta interna, cada trozo de texto y el enlace a la
        Política de privacidad se convertían en columnas independientes de una
        fila flex. En 390 px el consentimiento se leía, literalmente:
            «He leído y acept │ o la          │ y autorizo a INVEXUS…»
            «                 │ Política de   │»
            «                 │ privacida d   │»
        Un texto legal partido en tres columnas no es un defecto estético: es
        el texto que la persona tiene que poder leer ANTES de dar su
        consentimiento, y es el que un día habrá que poder defender.

   El <li> tiene exactamente dos hijos —la casilla y la etiqueta—, que es lo
   que una fila flex sabe repartir. La etiqueta vuelve a ser un párrafo normal
   y el enlace, un enlace dentro del párrafo.

   Se vio en la captura de móvil, no leyendo el CSS. Un flex mal puesto no da
   ningún error: maqueta perfectamente algo que nadie quería. */
.inv-contacto__form .wpforms-form .wpforms-field-checkbox > ul {
  list-style: none; margin: 0; padding: 0;
}
.inv-contacto__form .wpforms-form .wpforms-field-checkbox li {
  display: flex; gap: 10px; align-items: flex-start;
  min-height: 44px; padding: 6px 0;
}
.inv-contacto__form .wpforms-form .wpforms-field-label-inline {
  font-size: var(--inv-fs-small);
  color: var(--inv-text);
  line-height: var(--inv-lh-body);
  font-weight: var(--inv-fw-body);
  /* Se anula el display:block de la regla general de etiquetas: aquí la
     etiqueta es el segundo hijo de la fila y tiene que poder crecer. */
  display: block;
  margin: 0;
  min-width: 0;
  flex: 1 1 auto;
}
/* LA CASILLA SE DIBUJA AQUI, NO LA DIBUJA EL NAVEGADOR.
   accent-color sólo pinta el estado MARCADO. El estado sin marcar lo pintaba
   Chrome por su cuenta y, con color-scheme: dark, salía un gris cálido
   neutro —relleno ≈#3E3E3E, borde ≈#909090— sin una gota de azul, en medio de
   una interfaz enteramente navy. Se vio en la captura ampliada; a tamaño real
   parecía beige.

   Y había un problema por debajo del estético: el borde de un control tiene
   que llegar a 3:1 contra lo que lo rodea (WCAG 1.4.11), porque un control que
   no se ve no se puede usar. Ésta es la casilla del consentimiento: si alguien
   no la distingue, no envía el formulario y no hay forma de saber que pasó.

   Con appearance:none el control deja de pintarlo el navegador y pasa a
   pintarlo el sistema de tokens, igual de día que de noche. Lo que NO cambia
   es el elemento: sigue siendo un <input type="checkbox"> nativo, con su
   required, su name y su semántica. WPForms lee .checked y no se entera de
   nada. */
.inv-contacto__form .wpforms-form input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 20px; height: 20px; margin: 2px 0 0; flex: 0 0 auto;
  display: inline-grid; place-content: center;
  border: 2px solid var(--inv-control-border);
  border-radius: 5px;
  background: var(--inv-surface);
  cursor: pointer;
  transition: background-color var(--inv-duration-fast) var(--inv-ease),
              border-color var(--inv-duration-fast) var(--inv-ease);
}
/* La marca. Va en un ::before con clip-path y no como carácter: un ✓ de fuente
   cambia de forma según la tipografía instalada y aquí no puede depender de
   eso. */
.inv-contacto__form .wpforms-form input[type="checkbox"]::before {
  content: "";
  width: 11px; height: 11px;
  background: var(--inv-btn-primary-fg);
  transform: scale(0);
  transition: transform var(--inv-duration-micro) var(--inv-ease);
  clip-path: polygon(14% 47%, 0 61%, 39% 100%, 100% 22%, 85% 8%, 39% 71%);
}
.inv-contacto__form .wpforms-form input[type="checkbox"]:checked {
  background: var(--inv-brand-ink);
  border-color: var(--inv-brand-ink);
}
.inv-contacto__form .wpforms-form input[type="checkbox"]:checked::before {
  transform: scale(1);
}
.inv-contacto__form .wpforms-form input[type="checkbox"]:focus-visible {
  outline: 3px solid var(--inv-color-focus);
  outline-offset: 2px;
}
@media (hover: hover) and (pointer: fine) {
  .inv-contacto__form .wpforms-form input[type="checkbox"]:hover {
    border-color: var(--inv-brand-ink);
  }
}
/* Sin movimiento, la marca aparece; no crece. */
@media (prefers-reduced-motion: reduce) {
  .inv-contacto__form .wpforms-form input[type="checkbox"],
  .inv-contacto__form .wpforms-form input[type="checkbox"]::before {
    transition: none;
  }
}
/* La descripción del campo, debajo de la fila y alineada con la etiqueta. */
.inv-contacto__form .wpforms-form .wpforms-field-description {
  font-size: var(--inv-fs-small); color: var(--inv-muted);
  line-height: var(--inv-lh-body); margin-top: 6px;
}
.inv-contacto__form .wpforms-form .wpforms-submit {
  min-height: 48px; padding: 0 var(--inv-space-3);
  background: var(--inv-btn-primary-bg); color: var(--inv-btn-primary-fg);
  border: 0; border-radius: var(--inv-radius-btn);
  font-family: var(--inv-font-heading); font-weight: var(--inv-fw-semibold);
  font-size: var(--inv-fs-body); cursor: pointer;
  transition: background-color var(--inv-duration-base) var(--inv-ease),
              transform var(--inv-duration-micro) var(--inv-ease);
}
.inv-contacto__form .wpforms-form .wpforms-submit:hover { background: var(--inv-btn-primary-bg-hover); }
.inv-contacto__form .wpforms-form .wpforms-submit:focus-visible {
  outline: 3px solid var(--inv-color-focus); outline-offset: 2px;
}
/* Mensajes de error y de confirmación, con los colores accesibles del sistema. */
.inv-contacto__form .wpforms-error { color: var(--inv-error-ink); font-size: var(--inv-fs-small); }
.inv-contacto__form .wpforms-confirmation-container-full {
  background: var(--inv-badge-ok-bg); border: 1px solid var(--inv-green-ink);
  color: var(--inv-text); border-radius: var(--inv-radius-md);
  padding: var(--inv-space-3);
}

/* ==========================================================================
   BOTÓN FLOTANTE DE WHATSAPP
   ==========================================================================
   Enlace propio, sin plugin, sin JavaScript, sin peticiones externas y sin
   cookies. Un widget de WhatsApp habría traído las cuatro cosas.

   VA A LA IZQUIERDA. El botón de volver arriba de Astra vive abajo a la
   derecha; dos controles fijos en la misma esquina se solapan en móvil y uno
   de los dos deja de poder pulsarse.
   ========================================================================== */
.inv-wa {
  position: fixed;
  left: max(16px, env(safe-area-inset-left));
  bottom: max(16px, env(safe-area-inset-bottom));
  z-index: var(--inv-z-sticky);
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 56px; padding: 0 20px 0 16px;
  border-radius: var(--inv-radius-pill);
  background: var(--inv-whatsapp); color: var(--inv-whatsapp-fg);
  text-decoration: none;
  font-family: var(--inv-font-heading);
  font-weight: var(--inv-fw-semibold); font-size: .95rem;
  box-shadow: 0 8px 24px rgba(0,0,0,.24);
  transition: transform var(--inv-duration-base) var(--inv-ease),
              box-shadow var(--inv-duration-base) var(--inv-ease);
}
.inv-wa__icono { width: 24px; height: 24px; flex: 0 0 auto; }
@media (hover: hover) and (pointer: fine) {
  .inv-wa:hover { transform: translate3d(0, -2px, 0); box-shadow: 0 12px 30px rgba(0,0,0,.30); }
}
.inv-wa:focus-visible { outline: 3px solid var(--inv-color-focus); outline-offset: 3px; }

/* En móvil sólo el icono: un botón con texto ocupa un tercio del ancho de una
   pantalla de 360 px y tapa el contenido, que es justo lo que no debe hacer. */
@media (max-width: 767px) {
  .inv-wa { padding: 0; width: 56px; justify-content: center; }
  .inv-wa__texto { position: absolute; width: 1px; height: 1px; overflow: hidden;
                   clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
}

/* EN CONTACTO NO SE PINTA SIQUIERA. No se oculta con CSS: no se emite. Un
   elemento que se manda al navegador para esconderlo es marcado que alguien
   acabará encontrando en el DOM sin entender por qué está. La decisión vive en
   invexus-core/includes/helpers/contacto.php, junto al resto de la lógica. */

/* Nada de pulsos ni rebotes: es un canal de contacto profesional, no una
   notificación. La única transición es la respuesta al puntero. */
@media (prefers-reduced-motion: reduce) {
  .inv-wa { transition: none; }
}
@media print { .inv-wa { display: none !important; } }


/* ==========================================================================
   ESTADOS DE SUPERFICIE · normal / hover-foco / activo
   ==========================================================================
   EL PROBLEMA QUE RESUELVE
   Las tarjetas SI reaccionaban, pero el cambio era tan leve que habia que
   buscarlo: el borde pasaba de gris a azul al 35 % y la tarjeta subia 6 px.
   Sobre una rejilla de seis tarjetas iguales eso no se percibe, se intuye, y
   una persona que navega con teclado no llegaba a saber donde estaba.

   LA REGLA: LOS ESTADOS SE DISTINGUEN POR MATERIAL, NO POR MATIZ.
   Cambiar un color un 20 % produce un estado que hay que comparar con el de
   al lado para notarlo. Cambiar la superficie produce un estado que se ve
   solo. Por eso el hover TINE el fondo, sube el borde a contraste real y
   enciende una linea de acento; y por eso el activo INVIERTE la superficie
   en vez de ser un hover mas fuerte.

   :focus-visible VA SIEMPRE JUNTO A :hover, en la misma regla y nunca dentro
   de @media (hover: hover). Si el hover vive dentro de esa consulta y el foco
   fuera, en un movil con teclado externo no habria ningun estado. Y el foco
   ademas conserva su contorno propio: el color no es un indicador suficiente.

   ESTA HOJA NO TOCA EL HERO NI CONTACTO, congelados por el director.
   ========================================================================== */

.inv-card {
  /* La transicion se re-declara aqui porque la original no incluia el fondo
     ni el color: sin ellos el tinte del hover aparecia de golpe mientras el
     resto se movia con suavidad, y ese desajuste se nota mas que el efecto. */
  transition:
    transform        var(--inv-duration-state) var(--inv-ease),
    box-shadow       var(--inv-duration-state) var(--inv-ease),
    border-color     var(--inv-duration-state) var(--inv-ease),
    background-color var(--inv-duration-state) var(--inv-ease),
    color            var(--inv-duration-state) var(--inv-ease);
}

/* --- LA LINEA DE ACENTO SUPERIOR -----------------------------------------
   Crece desde la izquierda al entrar el puntero o el foco. Es el unico
   elemento del estado que no existe en reposo, y por eso es el que mas
   claramente dice "algo ha cambiado".
   Va en ::after y no en ::before porque varias tarjetas ya usan ::before para
   estirar el enlace del titulo sobre toda la superficie. */
.inv-card::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 3px;
  border-radius: var(--inv-radius-md) var(--inv-radius-md) 0 0;
  background: var(--inv-hover-accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--inv-duration-state) var(--inv-ease);
  pointer-events: none;   /* jamas debe robar un clic al enlace de la tarjeta */
  z-index: 1;
}

/* --- HOVER Y FOCO · el mismo estado, dos maneras de llegar ---------------- */
.inv-card:focus-within,
.inv-card:hover {
  background-color: var(--inv-hover-bg);
  border-color: var(--inv-hover-border);
  box-shadow: var(--inv-shadow-md);
}
.inv-card:focus-within::after,
.inv-card:hover::after { transform: scaleX(1); }

.inv-card:focus-within .inv-card__icon,
.inv-card:hover .inv-card__icon {
  background: var(--inv-hover-icon-bg);
  color: var(--inv-hover-icon-fg);
}
.inv-card:focus-within .inv-card__title,
.inv-card:hover .inv-card__title,
.inv-card:focus-within .inv-card__title a,
.inv-card:hover .inv-card__title a { color: var(--inv-brand-ink); }

/* La elevacion solo con puntero fino: en una pantalla tactil no hay hover, y
   un :hover pegajoso tras el toque deja la tarjeta levantada sin motivo. */
@media (hover: hover) and (pointer: fine) {
  .inv-card:hover { transform: translate3d(0, -3px, 0); }
}

/* --- ACTIVO / SELECCIONADO · la superficie se invierte -------------------- */
.inv-card.is-active,
.inv-card[aria-current],
.inv-card:active {
  background-color: var(--inv-active-bg);
  border-color: var(--inv-active-border);
  box-shadow: var(--inv-shadow-lg);
  transform: none;         /* seleccionado no es "levantado": es otro estado */
}
.inv-card.is-active::after,
.inv-card[aria-current]::after,
.inv-card:active::after { transform: scaleX(1); background: var(--inv-active-border); }

.inv-card.is-active,
.inv-card.is-active p,
.inv-card.is-active .inv-card__title,
.inv-card.is-active .inv-card__title a,
.inv-card[aria-current],
.inv-card[aria-current] p,
.inv-card[aria-current] .inv-card__title,
.inv-card[aria-current] .inv-card__title a,
.inv-card:active,
.inv-card:active p,
.inv-card:active .inv-card__title,
.inv-card:active .inv-card__title a { color: var(--inv-active-fg); }

.inv-card.is-active .inv-card__text,
.inv-card[aria-current] .inv-card__text,
.inv-card:active .inv-card__text,
.inv-card.is-active .inv-insight-card__date,
.inv-card[aria-current] .inv-insight-card__date,
.inv-card:active .inv-insight-card__date { color: var(--inv-active-muted); }

.inv-card.is-active .inv-card__icon,
.inv-card[aria-current] .inv-card__icon,
.inv-card:active .inv-card__icon {
  background: var(--inv-active-fg);
  color: var(--inv-active-bg);
}
.inv-card.is-active .inv-insight-card__tag,
.inv-card[aria-current] .inv-insight-card__tag,
.inv-card:active .inv-insight-card__tag { color: var(--inv-active-fg); }

/* Sin movimiento: los estados SIGUEN EXISTIENDO, solo desaparece el
   desplazamiento. Apagar el hover entero dejaria a quien pide menos
   movimiento sin saber donde esta el puntero, que es lo contrario de una
   mejora de accesibilidad. */
@media (prefers-reduced-motion: reduce) {
  .inv-card { transition: none; }
  .inv-card::after { transition: none; }
  .inv-card:hover { transform: none; }
}


/* ==========================================================================
   INSIGHTS · aire editorial
   ==========================================================================
   LA ETIQUETA ESTABA A 1 px DEL BORDE, y no por el tamano de la letra: por
   padding CERO. La regla `.inv-case-card, .inv-insight-card { padding: 0 }`
   se escribio para la variante con imagen, donde el aire lo pone __body. En
   la Home esas tarjetas NO tienen __body, asi que se quedaban sin nada.
   Medido en navegador: Home 1 px, archivo 25 px. El mismo componente, dos
   resultados distintos.

   LA CORRECCION DEVUELVE EL PADDING A LA TARJETA y se lo quita solo a la que
   de verdad lleva imagen, usando :has(). Si un navegador no soporta :has(),
   la imagen queda enmarcada en vez de a sangre: se degrada a algo correcto,
   no a algo roto.
   ========================================================================== */
.inv-insight-card,
.inv-case-card { padding: var(--inv-editorial-pad); }

/* LA CONDICION ES "TIENE CUERPO", NO "TIENE IMAGEN".
   La primera version preguntaba por la imagen, y el archivo de Insights tiene
   tarjetas CON cuerpo y SIN imagen: la tarjeta se quedaba su padding, el
   cuerpo anadia el suyo y salian 65 px de margen. Medido.
   La regla verdadera es mas simple y no depende de si hay foto: manda quien
   tenga el cuerpo. Si existe __body, el aire lo pone el; si no, lo pone la
   tarjeta. Un solo responsable, nunca dos. */
.inv-insight-card:has(> .inv-insight-card__body),
.inv-case-card:has(> .inv-case-card__body) { padding: 0; }

.inv-insight-card__body,
.inv-case-card__body { padding: var(--inv-editorial-pad); }

/* La jerarquia se declara con margenes explicitos y no se deja al azar de los
   margenes heredados: categoria, aire, titulo, aire mayor, fecha. */
.inv-insight-card__tag {
  margin: 0 0 var(--inv-space-2);
  /* 1.65 es interlineado de parrafo. En una etiqueta de una linea, en
     mayusculas y con espaciado entre letras, sobra: la separa de si misma. */
  line-height: 1.35;
}
.inv-insight-card .inv-card__title { margin: 0; }
.inv-insight-card__date { margin: var(--inv-space-3) 0 0; }

@media (max-width: 767px) {
  .inv-insight-card,
  .inv-case-card,
  .inv-insight-card__body,
  .inv-case-card__body { padding: var(--inv-editorial-pad-mobile); }
}


/* ==========================================================================
   FOTOGRAFÍA ESTRATÉGICA
   ==========================================================================
   EL ENCARGO ERA QUE NO PARECIERA «UNA FOTO DENTRO DE UN RECTÁNGULO DE
   WORDPRESS», y ése es exactamente el problema que resuelve esta hoja.

   Una fotografía metida en un contenedor con borde y esquina redondeada se lee
   como un adjunto: algo que alguien subió. Una banda a sangre cuyos cantos se
   disuelven en el fondo se lee como parte de la página. La diferencia no está
   en la foto, está en el borde, y por eso aquí no hay ninguno.

   TRES CAPAS Y NADA MÁS
     · la imagen, a sangre y recortada por el centro
     · una máscara que borra el canto superior e inferior
     · un velo que baja el contraste para que el texto de alrededor mande

   NO HAY TEXTO ENCIMA DE LA FOTO. Se evaluó y se descartó: un titular sobre
   una fotografía obliga a garantizar el contraste en cada píxel de la imagen,
   y en cuanto alguien cambie la foto el contraste se rompe sin que nadie se
   entere. El texto vive antes y después, sobre el fondo del sitio, donde su
   contraste es una propiedad del sistema y no de una imagen concreta.
   ========================================================================== */

.inv-foto {
  /* A SANGRE SIN ROMPER EL CONTENEDOR. 50vw a cada lado desde el centro de la
     columna: funciona dentro de cualquier contenedor centrado y no necesita
     saber su anchura. margin negativo en vez de position:fixed o width:100vw,
     que en una página con barra de desplazamiento provocan desborde
     horizontal —el fallo clásico del ancho completo—. */
  position: relative;
  left: 50%;
  width: 100vw;
  max-width: 100vw;
  margin-left: -50vw;
  margin-block: calc(-1 * var(--inv-space-5));
  overflow: hidden;
  /* La banda es decorativa: nunca debe capturar un gesto que iba dirigido al
     contenido que tiene encima o debajo. */
  pointer-events: none;
}

.inv-foto__marco {
  position: relative;
  height: clamp(200px, 30vw, 380px);
  /* LOS CANTOS DESAPARECEN. La máscara lleva la imagen a transparente arriba y
     abajo, así que no hay línea de corte: la fotografía se funde con el fondo
     de la página, sea blanco de día o navy de noche. Es lo que pedía el
     encargo: foto → degradado → fondo. */
  /* En una mascara el color NO se pinta: solo cuenta el canal alfa. `black`
     aqui significa "opaco", no "negro", y por eso no es un color de diseno ni
     debe convertirse en un token: hacerlo invitaria a cambiarlo con el tema y
     la mascara dejaria de funcionar. */
  -webkit-mask-image: linear-gradient(to bottom,
        transparent 0%, black 22%, black 78%, transparent 100%);
          mask-image: linear-gradient(to bottom,
        transparent 0%, black 22%, black 78%, transparent 100%);
}
.inv-foto--alta .inv-foto__marco { height: clamp(260px, 42vw, 520px); }

.inv-foto__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* PARALLAX MUY CORTO, DENTRO DEL LÍMITE ACORDADO: la imagen se mueve un poco
     menos que la página. La escala 1.06 existe sólo para que el recorrido
     vertical nunca deje ver un canto vacío; sin ella, el propio efecto abre un
     hueco por arriba o por abajo. */
  transform:
    translate3d(0, calc((var(--inv-progress, .5) - .5) * -34px * var(--inv-scene-fuerza, 1)), 0)
    scale(1.06);
  will-change: transform;
}

/* El velo. De día baja un poco el contraste para que la fotografía no compita
   con el texto; de noche la oscurece de verdad, porque una foto luminosa en
   una página oscura es un agujero de luz en mitad de la lectura. */
.inv-foto__velo {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
              color-mix(in srgb, var(--inv-bg) 55%, transparent),
              color-mix(in srgb, var(--inv-bg) 18%, transparent) 45%,
              color-mix(in srgb, var(--inv-bg) 55%, transparent));
}

/* En móvil el parallax se apaga: la banda es más baja, el recorrido se nota
   como un temblor y no como profundidad. */
@media (max-width: 767px) {
  .inv-foto { margin-block: calc(-1 * var(--inv-space-4)); }
  .inv-foto__marco { height: clamp(170px, 46vw, 260px); }
  .inv-foto__img { transform: scale(1.02); }
}

/* Sin movimiento no hay parallax. La fotografía se queda quieta y completa: no
   se oculta, porque no es movimiento, es contenido visual. */
@media (prefers-reduced-motion: reduce) {
  .inv-foto__img { transform: none; will-change: auto; }
}
[data-inv-motion="off"] .inv-foto__img { transform: none; }

@media print { .inv-foto { display: none; } }
