/* Trazen Systems — tokens y utilidades compartidas entre páginas */
/* Referencia visual: djectstudio.com — fondo blanco, tipografía Inter enorme
   con tracking muy cerrado, un solo azul de acento, botones y nav en pastilla,
   tarjetas blancas con sombra suave, listas numeradas. Un máximo de dos
   familias: Inter para todo el texto/titulares, League Spartan solo para el
   lockup "TRAZEN SYSTEMS" (la fuente geométrica más cercana al isotipo). */

:root {
  --bg: #ffffff;
  --bg-soft: #f6f7fb;
  --bg-elevated: #ffffff;
  --panel: #f3f4f9;
  --ink: #0a0a0f;
  --ink-muted: #53566a;
  --ink-subtle: #8a8da1;
  --hair: rgba(10,10,15,.08);
  --hair-strong: rgba(10,10,15,.14);
  /* Azul de marca oficial: #031CF5 / rgb(3,28,245) / hsl(234,98%,49%) —
     antes usábamos #3b55ff, un azul más claro que no coincidía con el
     logo real. Las variantes hover/deep son el mismo tono, solo más
     oscuro (misma proporción de oscurecido que antes). */
  --brand: #031CF5;
  --brand-deep: #0213B1;
  --brand-hover: #0218DE;
  --brand-soft: rgba(3,28,245,.08);
  --success: #16a34a;
  --error: #dc3b30;
  --focus: #031CF5;
  --shadow-card: 0 1px 2px rgba(10,10,15,.04), 0 20px 40px -24px rgba(10,10,15,.16);
  --shadow-card-lg: 0 2px 4px rgba(10,10,15,.05), 0 32px 64px -28px rgba(10,10,15,.22);
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
}

* { -webkit-font-smoothing: antialiased; }
/* overflow-x:hidden como red de seguridad, no como el fix en sí — la
   causa real (la tarjeta del FAQ corrida 48px antes de revelarse) está
   contenida en su propio selector más abajo. Esto solo evita que un
   futuro elemento con el mismo tipo de problema vuelva a generar scroll
   horizontal en todo el documento. */
html { scroll-behavior: smooth; overflow-x: hidden; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter', ui-sans-serif, system-ui, sans-serif;
}
h1, h2, h3, h4, .font-display {
  font-family: 'Inter', ui-sans-serif, system-ui, sans-serif;
  font-weight: 800;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
/* El lockup de marca "TRAZEN SYSTEMS" — la única razón para conservar League
   Spartan: es la fuente geométrica libre más cercana a Futura, la del isotipo. */
.font-wordmark {
  font-family: 'League Spartan', 'Inter', ui-sans-serif, sans-serif;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.font-mono-num {
  font-family: 'Inter', ui-sans-serif, sans-serif;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
  font-weight: 700;
  letter-spacing: -0.01em;
}
/* Titular masivo tipo djectstudio: Inter muy pesado, tracking muy cerrado,
   line-height casi 1. Se usa en el H1 del hero. */
.display-hero {
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 0.98;
}

/* Titular estándar de sección — más grande que el text-3xl/md:text-5xl de
   Tailwind (tope de 48px), que se sentía chico comparado con la
   referencia. clamp() para que crezca con la pantalla en vez de saltar
   solo en el breakpoint md. */
.section-heading {
  font-size: clamp(1.875rem, 4.6vw, 3.5rem);
  line-height: 1.05;
}

::selection { background: var(--brand); color: #fff; }

/* Skip link */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--brand);
  color: #fff;
  padding: 12px 18px;
  z-index: 100;
  border-radius: 0 0 8px 0;
  font-weight: 600;
}
.skip-link:focus { left: 0; }

/* Strong, visible focus ring everywhere — never remove outlines */
:focus-visible {
  outline: 2.5px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}
a, button, input, textarea, select, summary {
  -webkit-tap-highlight-color: transparent;
}

/* Tarjetas blancas con sombra suave, en vez del "glass" oscuro anterior */
.card {
  background: #fff;
  border: 1px solid var(--hair);
  box-shadow: var(--shadow-card);
}
.card-soft {
  background: var(--bg-soft);
  border: 1px solid var(--hair);
}
.card-strong {
  background: #fff;
  border: 1px solid var(--hair);
  box-shadow: var(--shadow-card-lg);
}

.btn-primary {
  background: var(--brand);
  color: #fff;
  transition: filter 160ms var(--ease-out), transform 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
  box-shadow: 0 12px 28px -10px rgba(3,28,245,.55);
}
.btn-primary:hover { filter: brightness(1.08); box-shadow: 0 16px 34px -10px rgba(3,28,245,.65); }
.btn-primary:active { transform: scale(0.97); }

.btn-secondary {
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--hair-strong);
  transition: border-color 160ms var(--ease-out), background 160ms var(--ease-out), transform 160ms var(--ease-out);
}
.btn-secondary:hover { border-color: var(--ink-subtle); background: var(--bg-soft); }
.btn-secondary:active { transform: scale(0.97); }

/* Texto de botón que "sube y se releva" al hover: el botón nunca se mueve,
   solo el texto — una copia sale por arriba mientras la otra entra por abajo. */
.btn-swap-inner {
  position: relative;
  display: block;
  overflow: hidden;
  height: 1.3em;
}
.btn-swap-text {
  display: block;
  height: 1.3em;
  line-height: 1.3em;
  transition: transform 250ms ease;
}
.btn-swap-text.is-copy {
  position: absolute;
  inset: 0;
  transform: translateY(100%);
}
a:hover > .btn-swap-inner > .btn-swap-text:not(.is-copy) { transform: translateY(-100%); }
a:hover > .btn-swap-inner > .btn-swap-text.is-copy { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .btn-swap-text { transition: none; }
}

/* Transición de identidad — el "Design × Inject" de djectstudio, en una
   sola secuencia pineada de dos fases:
   Fase 1: un círculo crece DESDE EL CENTRO vía clip-path (no transform:
   scale — escalar un círculo pequeño lo pixela al crecer 40-50x; clip-path
   recalcula el trazo en cada cuadro y siempre queda nítido) hasta cubrir
   toda la pantalla, mientras el texto "Datos × Ejecución" se desvanece por
   completo (no debe quedar nada del texto/× encima del círculo).
   Fase 2: ya sobre fondo oscuro, el titular entra desde la derecha, a la
   MISMA altura donde estaba el texto de la fase 1 (ambos comparten el
   mismo contenedor centrado — nunca "sube desde abajo").
   Pin vía position:sticky + GSAP ScrollTrigger (scrub) en site.js. */
.identity-transition {
  position: relative;
  height: 430vh;
}
.identity-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--bg);
}
.identity-circle {
  position: absolute;
  inset: 0;
  background: var(--brand);
  clip-path: circle(0% at 50% 50%);
  will-change: clip-path;
}
.identity-stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.identity-text {
  position: absolute;
  z-index: 1;
  font-family: 'Inter', ui-sans-serif, sans-serif;
  font-weight: 800;
  letter-spacing: -0.03em;
  font-size: clamp(2.2rem, 7vw, 5rem);
  color: var(--ink);
  margin: 0;
}
/* line-height:1 en el propio span: sin esto, getBoundingClientRect() del
   × en site.js mide la caja de línea completa (con el espacio extra
   arriba/abajo del glifo que deja el line-height heredado), y el origen
   calculado del círculo queda por encima del × en vez de centrado. */
.identity-text .identity-x { color: var(--brand); font-weight: 500; padding: 0 .15em; line-height: 1; display: inline-block; }
/* Sin opacity:0 ni fromTo de opacidad a propósito: la revelación es 100%
   posicional (entra por la derecha, sale por la izquierda). Un fade por
   umbral se ve como un "pop" si el usuario hace un scroll grande de un
   solo golpe (rueda del mouse, trackpad) y ese umbral queda en medio del
   salto — con posición pura nunca puede "aparecer de la nada": como
   mucho, avanza de golpe a lo largo del mismo camino continuo. */
.identity-scrub-line {
  position: absolute;
  z-index: 1;
  white-space: nowrap;
  font-family: 'Inter', ui-sans-serif, sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1;
  font-size: clamp(2.2rem, 7vw, 5rem);
  color: #fff;
  margin: 0;
  will-change: transform;
}

/* Letras de la palabra en azul del hero: cada una sube y aparece por
   separado, en ola, cuando el ciclo cambia de palabra. */
/* text-align:left explícito: si no, hereda el text-center del hero y las
   letras quedan centradas dentro de la caja de ancho fijo, dejando un
   hueco visible antes de la palabra — el único punto fijo debe ser el
   inicio (justo después de "Se"), el final es lo que varía por palabra. */
#scramble-word { display: inline-block; white-space: nowrap; text-align: left; }
.wave-letter {
  display: inline-block;
  white-space: pre;
  opacity: 0;
  transform: translateY(55%);
  transition: transform 550ms cubic-bezier(.2,.8,.2,1), opacity 420ms ease;
}
.wave-letter.is-up { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .wave-letter { opacity: 1; transform: none; transition: none; }
}
@media (prefers-reduced-motion: reduce) {
  .identity-transition { height: auto; }
  .identity-pin { position: relative; height: auto; padding: 12vh 0; background: var(--brand); }
  .identity-circle { display: none; }
  .identity-stage { position: relative; flex-direction: column; gap: 24px; text-align: center; }
  .identity-text { position: relative; color: #fff; }
  .identity-scrub-line { position: relative; opacity: 1; white-space: normal; max-width: 90vw; text-align: center; }
}

/* En mobile el piso del clamp() se sentía chico para un momento tan
   dramático de la página — lo subimos aparte del clamp de escritorio.
   La sección también se acorta: en una pantalla angosta cada "swipe"
   avanza menos vh percibidos, y con la altura de escritorio había que
   deslizar demasiado para cruzar la frase. */
@media (max-width: 640px) {
  .identity-text, .identity-scrub-line { font-size: clamp(2.75rem, 11vw, 3.5rem); }
  .identity-transition { height: 300vh; }
}

/* Tarjetas con ícono de "Lo que nos hace diferentes" — elevadas sobre el
   fondo oscuro de la sección, como las de djectstudio. */
.principle-icon {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  border: 1px solid var(--hair-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 20px;
}
.principle-icon svg { width: 22px; height: 22px; }

/* Lista numerada con revelado por scroll — el "What we do" de djectstudio:
   fila siempre visible (número + título), la descripción solo se expande
   en la fila activa (la más cercana al centro del viewport). */
.what-grid { grid-template-columns: 1fr; }
@media (min-width: 1024px) {
  .what-grid { grid-template-columns: minmax(0, 280px) 1fr; }
}
.what-row {
  border-bottom: 1px solid var(--hair);
  padding: 28px 0;
  cursor: default;
}
.what-row:first-child { padding-top: 4px; }
.what-row:last-of-type { border-bottom: none; }
.what-row-head {
  display: flex;
  align-items: baseline;
  gap: 24px;
}
.what-row-num {
  font-family: 'Inter', ui-sans-serif, sans-serif;
  font-weight: 300;
  font-size: 2.25rem;
  color: var(--ink-subtle);
  line-height: 1;
  min-width: 2.2ch;
}
.what-row-title {
  font-family: 'Inter', ui-sans-serif, sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-size: 1.5rem;
}
.what-row-desc {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 600ms var(--ease-out), opacity 480ms var(--ease-out), margin-top 600ms var(--ease-out);
}
.what-row-desc p {
  padding-left: calc(2.2ch + 24px);
  color: var(--ink-muted);
  line-height: 1.6;
  max-width: 46ch;
}
.what-row.is-active .what-row-desc {
  max-height: 140px;
  opacity: 1;
  margin-top: 14px;
}
.what-row.is-active .what-row-title { color: var(--brand); }
@media (prefers-reduced-motion: reduce) {
  .what-row-desc { transition: none; }
}
/* Tarjeta blanca que encierra las 5 filas — como el bloque con sombra de
   djectstudio, en vez de filas sueltas flotando sobre el fondo. */
.what-card {
  background: #fff;
  border: 1px solid var(--hair);
  border-radius: 24px;
  box-shadow: var(--shadow-card);
  padding: 8px 32px;
}
.what-card .what-row { padding: 28px 0; }
.what-card .what-row:first-child { padding-top: 28px; }
.what-card .what-row:last-child { border-bottom: none; padding-bottom: 28px; }

.eyebrow {
  font-family: 'Inter', ui-sans-serif, sans-serif;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  font-size: 13px;
  color: var(--brand);
}

/* Scroll reveal — respects prefers-reduced-motion */
[data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 600ms var(--ease-out), transform 600ms var(--ease-out);
}
[data-reveal].is-visible { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
}

/* Entrada tipo "pop" (escala + sube) para tarjetas destacadas — como la
   del Diagnóstico en Precio, que antes solo tenía el fade-up genérico. */
.card-pop[data-reveal] { transform: scale(0.92) translateY(18px); }
.card-pop[data-reveal].is-visible { transform: scale(1) translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .card-pop[data-reveal] { transform: none; }
}
[data-reveal-group] > * { transition-delay: calc(var(--i, 0) * 60ms); }

/* FAQ accordion — cada pregunta entra desde la derecha, en cascada
   (usa el --i que ya reparte [data-reveal-group] en site.js).
   overflow-x:hidden en el contenedor: antes de revelarse, cada tarjeta
   vive corrida 48px a la derecha de su posición final — en mobile, donde
   la tarjeta ya ocupa casi todo el ancho, ese corrimiento saca su borde
   derecho del viewport y genera scroll horizontal en toda la página
   (visible como una franja blanca al hacer swipe). El contenedor no
   participa de la animación (solo la tarjeta se mueve), así que puede
   recortar ese excedente sin afectar el diseño ni el movimiento en sí. */
#faq [data-reveal-group] { overflow-x: hidden; }
.faq[data-reveal] { transform: translateX(48px); }
.faq[data-reveal].is-visible { transform: translateX(0); }
@media (prefers-reduced-motion: reduce) {
  .faq[data-reveal] { transform: none; }
}
details.faq > summary { list-style: none; cursor: pointer; }
details.faq > summary::-webkit-details-marker { display: none; }
details.faq .chev { transition: transform 200ms var(--ease-out); }
details.faq[open] .chev { transform: rotate(180deg); }
details.faq .faq-body { overflow: hidden; }

/* Grupo en pastilla del nav (como el "Agency / Store" de djectstudio):
   fondo gris muy claro y sólido, sin blur, sin borde, sin sombra — flota
   solo, sin una barra que lo una al logo o al link de contacto. */
.nav-pill-group {
  background: var(--bg-soft);
  transition: background 260ms var(--ease-out), color 260ms var(--ease-out);
}
.nav-pill-item {
  display: inline-flex; align-items: center;
  padding: 10px 16px;
  border-radius: 999px;
  color: var(--ink-muted);
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.nav-pill-item:hover { color: var(--ink); }
/* Cuando el scroll pasa sobre una sección oscura, el nav se invierte —
   mismo gesto que djectstudio, para que siga siendo legible encima. */
header.is-on-dark .nav-pill-group { background: rgba(255,255,255,.12); color: #fff; }
header.is-on-dark .nav-pill-item { color: rgba(255,255,255,.7); }
header.is-on-dark .nav-pill-item:hover { color: #fff; }

/* "Agenda tu Diagnóstico" del nav: texto plano que se rellena en píldora
   azul al hover — igual que el "Let's talk" de djectstudio. */
.nav-cta {
  padding: 10px 18px;
  border-radius: 999px;
  color: var(--ink);
  background: transparent;
  transition: background 220ms var(--ease-out), color 220ms var(--ease-out);
}
.nav-cta:hover { background: var(--brand); color: #fff; }
header.is-on-dark .nav-cta { color: #fff; }
header.is-on-dark .nav-cta:hover { background: var(--brand); color: #fff; }

/* Vidrio esmerilado exactamente del tamaño del header — en djectstudio el
   blur cubre solo la franja del propio header, no una banda extra ni con
   degradado hacia abajo. */
.header-blur {
  position: fixed;
  top: 0; left: 0; right: 0;
  /* Ajustado al tamaño real del header en mobile (antes se pasaba de largo
     y alcanzaba a difuminar el logo y el botón de 3 líneas). */
  height: 60px;
  z-index: 40;
  pointer-events: none;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
@media (min-width: 640px) {
  .header-blur { height: 84px; }
}

/* Sección oscura ("Lo que nos hace diferentes") — el único quiebre de tema
   en la página, como el bloque oscuro de djectstudio. */
.section-dark {
  background: var(--ink);
  color: #fff;
  --ink-muted: rgba(255,255,255,.62);
  /* Más blanco que el .4 original — en el footer (reloj, ubicación,
     copyright, legales) se veía demasiado apagado/gris. */
  --ink-subtle: rgba(255,255,255,.7);
  --hair: rgba(255,255,255,.12);
  /* Idem: los contornos de los íconos del footer y las tarjetas con ícono
     de "Lo que nos hace diferentes" se veían casi invisibles con .22. */
  --hair-strong: rgba(255,255,255,.4);
}

/* Footer como tarjeta redondeada flotante, no a todo lo ancho — igual que
   el footer de djectstudio, que tiene radio en las 4 esquinas y margen
   respecto al borde de la ventana en vez de ser una franja completa. */
/* El margen lateral escala con el viewport (clamp) — un margen fijo de
   16px es visible en un laptop pero imperceptible en un monitor ancho,
   donde la tarjeta terminaba viéndose pegada a los bordes sin el aire que
   tiene en la referencia. */
/* Alto casi de una pantalla (un poco menos de 88vh — a esa altura llegaba
   a montarse sobre el blur del header) y contenido repartido con
   space-between: así la tarjeta llena el viewport como en la referencia,
   sin quedar corta (dejando ver el FAQ arriba) ni tan alta que se pase del
   blur. */
.footer-card {
  border-radius: 32px;
  overflow: hidden;
  margin: 0 clamp(16px, 4vw, 64px) clamp(16px, 3vw, 48px);
  min-height: 80vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 48px;
}
@media (max-width: 640px) {
  .footer-card { border-radius: 24px; margin: 0 12px 12px; min-height: auto; gap: 40px; }
}

/* Badge "Disponibles para tu próximo Growth Cycle" — como el "Available
   for your next project" de djectstudio: pastilla con un punto vivo. */
.footer-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(255,255,255,.08);
  font-size: 13px;
  font-weight: 600;
  color: rgba(255,255,255,.85);
}
.footer-badge-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--brand);
  flex-shrink: 0;
  position: relative;
}
.footer-badge-dot::before {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1.5px solid var(--brand);
  animation: live-dot-pulse 1.8s var(--ease-out) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .footer-badge-dot::before { animation: none; display: none; }
}

/* Titular del footer — tan grande como el titular del hero, igual que el
   "Your next project starts with a conversation." de djectstudio. */
.footer-headline {
  font-size: clamp(2rem, 5.5vw, 3.75rem);
  line-height: 1.05;
}

/* Botón de contorno (sin relleno) para el CTA del footer — como el "Start
   a project" de djectstudio: al hover se invierte a blanco sólido con
   texto azul, no solo se aclara un poco. */
.btn-outline-white {
  border: 2.5px solid rgba(255,255,255,.55);
  color: #fff;
  background: transparent;
  /* Lenta a propósito, de ida y de vuelta (misma transición sirve para
     :hover y para cuando se quita el cursor) — esa pausa es la que le da
     la sensación "premium" que se buscaba, no una respuesta inmediata. */
  transition: background 550ms var(--ease-out), border-color 550ms var(--ease-out), color 550ms var(--ease-out);
}
.btn-outline-white:hover { background: #fff; color: var(--brand); border-color: #fff; }

/* Botones de ícono del footer (correo, WhatsApp, redes) — mismo tratamiento
   circular con borde, ahora una sola clase reutilizada por los 4. */
.footer-icon-btn {
  width: 32px; height: 32px;
  border-radius: 999px;
  border: 1.5px solid var(--hair-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-subtle);
  transition: color 180ms var(--ease-out), border-color 180ms var(--ease-out);
}
.footer-icon-btn:hover { color: var(--brand); border-color: var(--brand); }


/* Botón flotante de WhatsApp */
.wa-float {
  position: fixed;
  right: 20px;
  bottom: 24px;
  z-index: 65;
  width: 66px;
  height: 66px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Blanco en vez de negro — el aro oscuro alrededor del ícono se veía
     como un contorno negro no intencional. */
  background: #fff;
  box-shadow: 0 10px 28px -8px rgba(10,10,15,.3);
  opacity: 0;
  transform: scale(0.9);
  transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out), box-shadow 200ms var(--ease-out);
}
.wa-float.is-shown { opacity: 1; transform: scale(1); }
.wa-float::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: 50%;
  background: #25D366;
  opacity: .35;
  animation: wa-pulse 2.4s var(--ease-out) infinite;
}
@media (hover: hover) and (pointer: fine) {
  .wa-float:hover { transform: scale(1.06); box-shadow: 0 14px 32px -8px rgba(10,10,15,.48); }
}
.wa-float:active { transform: scale(0.96); }
@media (max-width: 767px) {
  .wa-float { right: 16px; bottom: calc(88px + env(safe-area-inset-bottom)); width: 60px; height: 60px; }
}
@keyframes wa-pulse {
  0% { transform: scale(1); opacity: .35; }
  100% { transform: scale(1.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .wa-float::before { animation: none; display: none; }
  .wa-float { transition: opacity 200ms ease; }
}

/* Widget "kanban": al pasar el cursor (o mantener tocado en móvil), la
   tarjeta crece un poco y todas las tareas pasan a "Listo". */
.kanban-widget {
  transition: transform 220ms var(--ease-out), box-shadow 220ms var(--ease-out);
}
.kanban-widget:hover, .kanban-widget:active {
  transform: scale(1.03);
  box-shadow: 0 20px 44px -16px rgba(3,28,245,.3);
}
.kanban-badge { position: relative; display: inline-flex; }
.kanban-state {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  background: var(--bg-soft);
  color: var(--ink-subtle);
  transition: opacity 200ms ease;
}
.kanban-state-active { background: var(--brand-soft); color: var(--brand); }
.kanban-state-done {
  position: absolute;
  inset: 0;
  opacity: 0;
  justify-content: center;
  background: rgba(22,163,74,.12);
  color: #15803d;
}
.kanban-widget:hover .kanban-state:not(.kanban-state-done),
.kanban-widget:active .kanban-state:not(.kanban-state-done) { opacity: 0; }
.kanban-widget:hover .kanban-state-done,
.kanban-widget:active .kanban-state-done { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .kanban-widget, .kanban-state { transition: none; }
}

/* Tarjetas "Así de simple" del hero — cada paso en su propia tarjeta,
   con una animación distinta e ininterrumpida por icono. */
.step-card {
  transition: transform 240ms var(--ease-out), box-shadow 240ms var(--ease-out), border-color 240ms var(--ease-out);
}
.step-card:hover {
  transform: translateY(-5px);
  border-color: var(--hair-strong);
  box-shadow: var(--shadow-card-lg);
}
.step-icon-wrap {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--brand-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  transform: scale(0.6);
  opacity: 0;
  animation: step-icon-pop 500ms var(--ease-out) forwards;
  animation-delay: 200ms;
}
@keyframes step-icon-pop {
  60% { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
/* Ícono 1 — la lupa hace zoom, como si acercara el enfoque */
.step-icon-search { animation: step-search-zoom 1.8s ease-in-out infinite 900ms; transform-origin: 45% 45%; }
@keyframes step-search-zoom {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.35); }
}
/* Ícono 2 — el engrane gira, como un sistema en marcha */
.step-icon-gear { animation: step-gear-spin 5s linear infinite 700ms; transform-origin: 50% 50%; }
@keyframes step-gear-spin { to { transform: rotate(360deg); } }
/* Ícono 3 — las barras van creciendo y apareciendo en bucle, como un
   ecualizador — igual de continuo que la lupa y el engrane. */
.step-bars { align-items: flex-end; gap: 4px; background: none; }
.step-bar {
  width: 7px;
  border-radius: 3px 3px 0 0;
  background: var(--brand);
  transform-origin: bottom;
  animation: step-bar-grow 1.8s ease-in-out infinite;
}
.step-bar:nth-child(1) { animation-delay: 900ms; }
.step-bar:nth-child(2) { animation-delay: 1100ms; }
.step-bar:nth-child(3) { animation-delay: 1300ms; }
@keyframes step-bar-grow {
  0%, 100% { transform: scaleY(0.2); }
  50% { transform: scaleY(1); }
}
@media (prefers-reduced-motion: reduce) {
  .step-icon-wrap { animation: none; opacity: 1; transform: none; }
  .step-icon-search, .step-icon-gear, .step-bar { animation: none; }
  .step-bar { transform: scaleY(1); }
}

/* Flujo "Cada ciclo / Cada decisión / Cada resultado" — recuadros
   conectados por flechas que respiran, sugiriendo movimiento continuo. */
.flow-node {
  text-align: center;
  transition: transform 240ms var(--ease-out), border-color 240ms var(--ease-out), box-shadow 500ms var(--ease-out);
}
.flow-node[data-reveal] { transform: scale(0.9); }
.flow-node[data-reveal].is-visible {
  transform: scale(1);
  animation: flow-node-glow 700ms var(--ease-out);
}
@keyframes flow-node-glow {
  0% { box-shadow: 0 0 0 0 rgba(3,28,245,0); }
  45% { box-shadow: 0 0 0 8px rgba(3,28,245,.14); }
  100% { box-shadow: 0 0 0 0 rgba(3,28,245,0); }
}
.flow-node:hover { transform: translateY(-3px); border-color: var(--hair-strong); }
.flow-arrow-icon {
  color: var(--brand);
  animation: flow-arrow-drift 1.6s var(--ease-in-out) infinite;
}
@keyframes flow-arrow-drift {
  0%, 100% { transform: translateX(0); opacity: .55; }
  50% { transform: translateX(4px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .flow-arrow-icon { animation: none; opacity: 1; }
  .flow-node:hover { transform: none; }
  .flow-node[data-reveal].is-visible { animation: none; }
}

/* Tarjetas de "Cómo opera Trazen" — una barra de acento se dibuja
   de izquierda a derecha al revelarse cada tarjeta, en cascada. */
.principle-card {
  transition: transform 220ms var(--ease-out), border-color 220ms var(--ease-out);
}
.principle-card:hover { transform: translateY(-4px); border-color: var(--hair-strong); }
.principle-bar {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--brand);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 650ms var(--ease-out), filter 200ms var(--ease-out);
}
.principle-card.is-visible .principle-bar {
  transform: scaleX(1);
  transition-delay: calc(var(--i, 0) * 70ms + 200ms);
}
.principle-card:hover .principle-bar { filter: brightness(1.2); }
@media (prefers-reduced-motion: reduce) {
  .principle-card:hover { transform: none; }
  .principle-bar { transition: none; transform: scaleX(1); }
}

/* Checklist y barras animadas (usadas en "cómo trabajamos") */
.checklist-item {
  opacity: .4;
  transform: translateX(-6px);
  transition: opacity 450ms var(--ease-out), transform 450ms var(--ease-out);
}
.checklist-item.is-checked { opacity: 1; transform: translateX(0); }
.check-dot {
  width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0;
  border: 1.5px solid var(--hair-strong);
  position: relative;
  transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out);
}
.checklist-item.is-checked .check-dot { background: var(--brand); border-color: var(--brand); }
.check-dot::after {
  content: '';
  position: absolute; left: 4.5px; top: 1.5px;
  width: 4px; height: 8px;
  border-right: 1.6px solid #fff; border-bottom: 1.6px solid #fff;
  transform: rotate(45deg) scale(0);
  transition: transform 320ms var(--ease-out);
}
.checklist-item.is-checked .check-dot::after { transform: rotate(45deg) scale(1); }

.bar-fill { transform: scaleY(0); transform-origin: bottom; transition: transform 700ms var(--ease-out); }
[data-bars].is-animated .bar-fill { transform: scaleY(1); }

@media (prefers-reduced-motion: reduce) {
  .checklist-item, .check-dot, .check-dot::after, .bar-fill { transition: none; }
}

/* Punto "al día" del Reporte del mes — pulso de vida, como un indicador en vivo */
.live-dot { position: relative; }
.live-dot::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: 50%;
  background: inherit;
  opacity: .6;
  animation: live-dot-pulse 1.8s var(--ease-out) infinite;
}
@keyframes live-dot-pulse {
  0% { transform: scale(1); opacity: .6; }
  100% { transform: scale(2.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .live-dot::before { animation: none; display: none; }
}

/* Cookie banner — todo en CSS propio (ver nota en site.js): antes usaba
   clases de Tailwind (p-5, shadow-xl...) que el escáner nunca compiló por
   generarse desde un string de JS, dejando el banner sin relleno — el
   texto quedaba pegado al borde. */
.cookie-banner {
  position: fixed;
  left: 16px; right: 16px; bottom: 16px;
  z-index: 70;
  max-width: 560px;
  margin: 0 auto;
  padding: 22px;
  background: #fff;
  border: 1px solid var(--hair);
  border-radius: 20px;
  box-shadow: var(--shadow-card-lg);
  opacity: 0;
  transform: translateY(12px) scale(0.98);
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
  pointer-events: none;
}
.cookie-banner.is-shown { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.cookie-banner-row { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 16px; }
.cookie-banner-icon {
  width: 36px; height: 36px;
  border-radius: 10px;
  background: var(--brand-soft);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.cookie-banner-title { font-size: 14px; font-weight: 600; color: var(--ink); margin: 0 0 4px; }
.cookie-banner-text { font-size: 14px; line-height: 1.55; color: var(--ink-muted); margin: 0; }
.cookie-banner-link { color: var(--brand); text-decoration: underline; }
.cookie-banner-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.cookie-banner-btn { font-size: 14px; font-weight: 600; padding: 9px 18px; border-radius: 999px; }

/* Form field states */
.field-input {
  background: var(--bg-soft);
  color: var(--ink);
  border: 1px solid var(--hair-strong) !important;
  transition: border-color 140ms var(--ease-out), box-shadow 140ms var(--ease-out), background 140ms var(--ease-out);
}
.field-input::placeholder { color: var(--ink-subtle); }
.field-input:focus { background: #fff; }
.field-input[aria-invalid="true"] { border-color: var(--error) !important; }
.field-error {
  color: var(--error);
  font-size: 13px;
  margin-top: 6px;
  display: none;
  align-items: center;
  gap: 6px;
}
.field-error.is-shown { display: flex; }

/* Loading spinner */
.spinner {
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,.35);
  border-top-color: #fff;
  animation: spin 700ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 1400ms; } }

.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translate(-50%, 12px);
  opacity: 0;
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
  z-index: 80;
  pointer-events: none;
}
.toast.is-shown { opacity: 1; transform: translate(-50%, 0); }

/* Trama de puntos muy sutil detrás del hero — el único fondo decorativo,
   en vez del cosmos oscuro anterior. Se desvanece hacia los bordes. */
.grid-fade {
  background-image: radial-gradient(rgba(10,10,15,.12) 1px, transparent 1px);
  background-size: 28px 28px;
  -webkit-mask-image: radial-gradient(650px 420px at 50% 0%, #000 40%, transparent 85%);
  mask-image: radial-gradient(650px 420px at 50% 0%, #000 40%, transparent 85%);
}

/* Tamaño del titular del hero — fijado aquí en vez de clases arbitrarias de
   Tailwind (text-[2.85rem] etc.): el tailwind.css de este proyecto es un
   archivo estático sin pipeline de build, así que cualquier valor entre
   corchetes que no estuviera ya compilado ahí simplemente no existe y el
   h1 cae a su tamaño heredado (por eso se veía más chico que el subtítulo). */
.hero-headline { font-size: 2.85rem; }
@media (min-width: 640px) {
  .hero-headline { font-size: 4.25rem; }
}
@media (min-width: 1024px) {
  .hero-headline { font-size: 5rem; }
}
@media (max-width: 640px) {
  .hero-headline { font-size: 2.5rem !important; line-height: 1.05 !important; }
}

/* Banda "listo para empezar" al cierre de la lista numerada — la tarjeta
   negra "Ready to start" de djectstudio, como última fila de la lista. */
.what-cta-row {
  background: var(--ink);
  color: #fff;
  border-radius: 20px;
  padding: 32px;
  margin-top: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  transition: transform 220ms var(--ease-out), background 220ms var(--ease-out);
}
.what-cta-row:hover { transform: translateY(-3px); background: var(--brand); }
.what-cta-row:hover .what-cta-eyebrow { color: #fff; }
.what-cta-eyebrow { transition: color 220ms var(--ease-out); }
.what-cta-row:hover .what-cta-row-arrow { transform: rotate(45deg); background: rgba(255,255,255,.22); }
.what-cta-row-title {
  font-family: 'Inter', ui-sans-serif, sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-size: 1.5rem;
}
.what-cta-row-arrow {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
  transition: transform 220ms var(--ease-out), background 220ms var(--ease-out);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* Checklist estático del precio — check en círculo, como los planes de
   djectstudio (sin la animación de "voy marcando", esa es solo para el
   mockup de Kanban de "cómo trabajamos"). */
.price-check-item { display: flex; align-items: flex-start; gap: 10px; }
.price-check-icon {
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 1.5px solid var(--brand);
  color: var(--brand);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  margin-top: 1px;
}
.price-check-icon svg { width: 11px; height: 11px; }

/* Titular del hero: nitidez progresiva al cargar */
.blur-in {
  opacity: 0;
  filter: blur(10px);
  transform: translateY(6px);
  animation: blur-in 900ms var(--ease-out) forwards;
  animation-delay: var(--d, 0ms);
}
@media (prefers-reduced-motion: reduce) {
  .blur-in { opacity: 1; filter: none; transform: none; animation: none; }
}
@keyframes blur-in {
  to { opacity: 1; filter: blur(0); transform: translateY(0); }
}
