/* ============================================================
   LAYOUT — estructura propia del sitio.
   Los ajustes sobre el CSS que inyectan los módulos viven en overrides.css
   (cargado al final del <body>, §7.3).
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* deja aire bajo el nav superior al saltar a un ancla */
  scroll-padding-top: 96px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--dl-bg);
  color: var(--dl-ink);
  font-family: var(--dl-font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video, svg { max-width: 100%; }
a { color: inherit; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; top: -60px; left: 12px; z-index: 999;
  background: var(--dl-accent); color: var(--dl-on-accent); padding: 10px 16px;
  border-radius: 10px; font-weight: 700; text-decoration: none;
  transition: top .2s ease;
}
.skip-link:focus { top: 12px; }

:focus-visible {
  outline: 2px solid var(--dl-accent);
  outline-offset: 3px;
}

/* ---------------- Secciones ---------------- */

.section {
  position: relative;
  padding: var(--dl-section-y) var(--dl-gutter);
  max-width: var(--dl-maxw);
  margin-inline: auto;
}
/* #metodo monta su propia <section> a pantalla completa: sin padding propio */
.section--flush { padding: 0; max-width: none; }
/* dataCardsMenu se difiere con onIdle (§ arranque) para no competir por el
   hilo con el primer segundo de animación del hero: monta más tarde, y sin
   esto la sección colapsaría a la altura de sólo .metodo-head hasta que
   aparezca, empujando todo lo de abajo de golpe (CLS). Se reserva de
   entrada la misma altura mínima que el poster va a pedir. */
#metodo { min-height: 70vh; }
@media (min-width: 768px) {
  #metodo { min-height: 100vh; }
}

/* Encabezado propio de #metodo, antes del poster que inyecta dataCardsMenu */
.metodo-head {
  position: relative;
  max-width: var(--dl-maxw);
  margin-inline: auto;
  padding: var(--dl-section-y) var(--dl-gutter) clamp(24px, 4vw, 40px);
}
/* El poster de dataCardsMenu arranca en #221c15, más claro que el fondo del
   body: el encabezado hace la transición para que no quede un corte
   horizontal. A sangre, porque el encabezado sí está centrado en columna. */
.metodo-head::before {
  content: "";
  position: absolute;
  inset: 0;
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  background: linear-gradient(180deg, var(--dl-bg) 0%, #221c15 100%);
  z-index: -1;
  pointer-events: none;
}
.metodo-head .section-title { max-width: 18ch; }

.section-head { max-width: 640px; margin: 0 0 clamp(36px, 6vw, 64px); }
.section-title {
  font-family: var(--dl-font-display);
  font-size: clamp(2rem, 6vw, 3.4rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.02;
  margin: 0 0 14px;
}
.section-lede {
  margin: 0;
  color: var(--dl-ink-mute);
  font-size: clamp(1rem, 2.2vw, 1.15rem);
  max-width: 52ch;
}

/* Nota al pie de sección: contexto honesto, no reclamo. */
.section-note {
  margin: clamp(28px, 5vw, 44px) 0 0;
  max-width: 62ch;
  font-family: var(--dl-font-mono);
  font-size: 12px;
  line-height: 1.7;
  letter-spacing: .02em;
  color: var(--dl-ink-mute);
  border-left: 2px solid var(--dl-glass-border);
  padding-left: 14px;
}

/* ---------------- Marca ---------------- */

.brand-mark {
  position: fixed;
  top: 22px;
  left: var(--dl-gutter);
  z-index: 95;
  display: flex;
  color: var(--dl-ink);
  opacity: .92;
  transition: opacity .25s ease, transform .25s cubic-bezier(.22,1,.36,1);
}
.brand-mark:hover { opacity: 1; transform: translateY(-2px); }
.brand-mark svg { display: block; }
@media (max-width: 767px) {
  .brand-mark { top: 18px; left: 18px; }
  .brand-mark svg { width: 28px; height: 28px; }
}

.foot-lockup {
  width: clamp(200px, 40vw, 268px);
  height: auto;
  margin: 0 auto 18px;
  display: block;
  opacity: .9;
}

.foot-social {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 18px;
  font-family: var(--dl-font-mono);
  font-size: 12px;
  letter-spacing: .04em;
  color: var(--dl-ink-mute);
  text-decoration: none;
  transition: color .2s ease;
}
.foot-social:hover { color: var(--dl-accent-soft); }

/* ---------------- Nav ---------------- */

.nav-host {
  position: fixed;
  z-index: 90;
  left: 50%;
  transform: translateX(-50%);
  bottom: max(16px, env(safe-area-inset-bottom));
  display: flex;
  justify-content: center;
  max-width: calc(100vw - 24px);
}
@media (min-width: 768px) {
  .nav-host { bottom: auto; top: 18px; }
}

/* ---------------- Hero ---------------- */
/* Dos composiciones distintas por breakpoint, a propósito:
   - Móvil (<768px): titular real y centrado, libre, con el vidrio + la
     palabra "Crecimiento" (dibujada detrás del vidrio, dentro del canvas)
     en su propia caja compacta más abajo.
   - Escritorio (≥768px): la versión original — el titular completo se
     dibuja detrás del vidrio, a pantalla completa. El <h1> sigue en el DOM
     (accesibilidad/SEO) pero visualmente oculto, como antes. */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: clamp(16px, 3vw, 30px);
  /* móvil: el nav flota abajo, no arriba — poco aire arriba, más abajo
     para no chocar con la píldora fija */
  padding: clamp(36px, 6vh, 56px) 0 clamp(80px, 12vh, 106px);
  overflow: hidden;
  isolation: isolate;
}

.hero-headline {
  position: relative;
  z-index: 2;
  margin: 0;
  padding: 0 var(--dl-gutter);
  text-align: center;
}
.hero-line {
  display: block;
  font-family: var(--dl-font-display);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  line-height: .96;
  /* clamp en vez de vw/vh libres: con la escena + bajada + CTA compartiendo
     la misma pantalla, un titular sin techo se comía el resto. */
  font-size: clamp(1.9rem, 6.2vw, 3.8rem);
  white-space: nowrap;
  color: var(--dl-ink);
}

/* glassHeroScene monta aquí. La caja tiene alto explícito por CSS (nunca
   `auto`, salvo en escritorio donde estira dentro de la fila 1fr del grid,
   §4.2) y NO empieza oculta: ocupa su lugar desde el primer paint del HTML,
   no recién cuando main.js decide montar la escena. Si no hay soporte WebGL
   o el equipo es de gama muy baja, main.js simplemente no monta nada ahí:
   la caja queda vacía (mismo color que el fondo del hero, ver bgColor) en
   vez de colapsar — colapsarla después del primer paint es lo que generaba
   el salto de layout (CLS) que tenía antes esta sección. */
.hero-canvas {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 460px;
  height: clamp(150px, 22vh, 260px);
  overflow: hidden;
}

/* El titular (o, en móvil, la palabra) lo dibuja three.js a sangre: la
   banda inferior lo funde con el fondo y separa la escena de la zona de
   lectura. Sólo aplica cuando la escena montó. */
.hero.has-scene .hero-canvas::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 42%;
  background: linear-gradient(180deg,
    rgba(13, 11, 8, 0) 0%,
    rgba(13, 11, 8, 0.65) 45%,
    var(--dl-bg) 100%);
  z-index: 3;
  pointer-events: none;
}

.hero-overlay {
  position: relative;
  z-index: 2;
  padding: 0 var(--dl-gutter);
  max-width: var(--dl-maxw);
  margin-inline: auto;
  width: 100%;
  text-align: center;
}
.hero-sub {
  margin: 0 auto 28px;
  max-width: 46ch;
  font-size: clamp(1rem, 2.4vw, 1.25rem);
  line-height: 1.55;
  color: var(--dl-ink);
}
.hero-cta { display: flex; justify-content: center; }

@media (min-width: 768px) {
  .hero {
    display: grid;
    /* fila 1: la escena (dibuja el titular completo detrás) · fila 2: bajada + CTA */
    grid-template-rows: minmax(340px, 1fr) auto;
    justify-content: normal;
    align-items: stretch;
    gap: 0;
    padding: 78px 0 0;
  }
  /* El titular vuelve a vivir sólo en el canvas: el <h1> real se retira
     visualmente sin quitarlo del DOM (accesibilidad/SEO se conservan). */
  .hero-headline {
    position: absolute;
    width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .hero-canvas {
    width: auto;
    max-width: none;
    height: auto; /* estira dentro de la fila 1fr por el `align-items: stretch` de arriba */
  }
  .hero-overlay { padding: 0 var(--dl-gutter) clamp(72px, 10vh, 110px); }
}

/* ---------------- Presentación (foto) ---------------- */

/* Sección puente entre el hero y "¿Dónde estás hoy?": la foto recortada
   (fondo ya transparente, sin caja) se apoya en el piso de la sección, como
   si estuviera sentado a la altura del texto que viene después. `overflow:
   hidden` recorta el margen de la animación de entrada, no la foto en sí. */
.presentacion {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  height: clamp(280px, 52vw, 460px);
  overflow: hidden;
  padding: 0;
}
/* `<picture>` reserva su propia caja del tamaño intrínseco del <img> (el
   width/height del HTML), no del tamaño ya achicado por el CSS de abajo —
   eso corría la foto lejos del centro dentro de una caja invisible enorme.
   `display: contents` saca a `<picture>` de la ecuación: el flex centra
   directamente el <img>. */
.presentacion picture { display: contents; }
.presentacion-photo {
  display: block;
  height: 100%;
  width: auto;
  max-width: min(100%, 560px);
  object-fit: contain;
  object-position: bottom;
  /* Entra al llegar el scroll (JS agrega `.is-visible`, ver main.js) — sube
     y aparece, una sola vez, sin animación de scroll ni pin. */
  opacity: 0;
  transform: translateY(64px);
  transition: opacity .9s ease, transform 1s cubic-bezier(.16,1,.3,1);
}
.presentacion.is-visible .presentacion-photo {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .presentacion-photo { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ---------------- Botón WhatsApp ---------------- */

.btn-wa {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 26px;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: .01em;
  color: var(--dl-on-accent);
  background: var(--dl-accent);
  box-shadow: 0 14px 32px -14px rgba(0,0,0,.6);
  transition: transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s ease, background-color .2s ease;
}
.btn-wa:hover {
  transform: translateY(-3px);
  background: var(--dl-accent-soft);
  box-shadow: 0 18px 40px -14px rgba(0,0,0,.65);
}

.wa-float {
  position: fixed;
  right: 20px;
  bottom: 92px;           /* por encima del nav inferior en móvil (§5) */
  z-index: 95;
  width: 56px; height: 56px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  color: var(--dl-on-accent);
  background: var(--dl-accent);
  box-shadow: 0 0 0 1px rgba(244,241,234,.14),
              0 10px 26px -8px rgba(0,0,0,.55);
  transition: opacity .35s ease, transform .35s cubic-bezier(.22,1,.36,1), background-color .2s ease;
}
.wa-float[hidden] { display: none; }
/* estado oculto con más especificidad que [data-wa-pending], que también
   toca la opacidad mientras falte el número */
.wa-float:not(.is-visible) {
  opacity: 0;
  transform: translateY(14px) scale(.9);
  pointer-events: none;
}
.wa-float:hover { transform: translateY(-3px); }
@media (min-width: 768px) {
  .wa-float { bottom: 24px; right: 24px; }
}

/* Links de WhatsApp aún sin número configurado (§10) */
a[data-wa-pending]:not(.wa-float) { opacity: .55; cursor: not-allowed; }
.wa-float[data-wa-pending] { filter: saturate(.35); cursor: not-allowed; }

/* ---------------- Trabajos ---------------- */

.work-grid {
  display: grid;
  gap: 28px;
  grid-template-columns: repeat(6, 1fr);
  align-items: start;
}
[data-orient="landscape"] { grid-column: span 3; }   /* media 16:9   */
[data-orient="portrait"]  { grid-column: span 2; }   /* media 9:19.5 */

.work-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.work-type {
  font-family: var(--dl-font-mono);
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--dl-ink-mute);
}

.work-frame { position: relative; }

.work-frame--browser {
  border-radius: var(--dl-radius);
  overflow: hidden;
  border: 1px solid var(--dl-glass-border);
  background: #05070a;
}
.browser-bar {
  height: 28px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding-inline: 12px;
  background: rgba(255,255,255,.05);
  border-bottom: 1px solid var(--dl-glass-border);
}
.browser-bar span {
  width: 9px; height: 9px; border-radius: 50%;
  background: rgba(255,255,255,.22);
}

.work-frame--phone {
  border: 10px solid var(--dl-glass-border);
  border-radius: 34px;
  overflow: hidden;
  background: #000;
  max-width: 300px;
  margin-inline: auto;
}
.work-frame--phone .work-media { border-radius: 24px; }

.work-media {
  overflow: hidden;
  background: #000;
  position: relative;
}
[data-orient="landscape"] .work-media { aspect-ratio: 16 / 9; }
[data-orient="portrait"]  .work-media { aspect-ratio: 9 / 19.5; max-height: 560px; margin-inline: auto; }

.work-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* parallax suave con las vars que escribe neonGlass3DTilt (§4.4) */
  transform: translate3d(calc(var(--hx, 0px) * -0.4), calc(var(--hy, 0px) * -0.4), 0) scale(1.06);
  transition: transform .25s cubic-bezier(.22,1,.36,1);
}

.work-note {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--dl-ink-mute);
  max-width: 46ch;
}

.work-foot {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: flex-start;
}
.work-foot .ms-neoncard-button { text-decoration: none; }

/* ---------------- Formas de trabajar ---------------- */

.formas-host { display: block; }
.formas-stage { position: relative; max-width: 980px; margin-inline: auto; }

/* Hilo que une los cuatro nodos en el orden de lectura. Va detrás de las
   tarjetas (que son opacas), así que sólo asoma en los huecos del grid: se
   lee como un flujo continuo. El trazado lo calcula main.js §6 sobre la
   posición real de cada `.formas-node`, así que sirve igual para la pila de
   una columna que para la grilla 2x2. */
.formas-wire {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  overflow: visible;
  pointer-events: none;
}
.formas-wire-path {
  fill: none;
  stroke: color-mix(in srgb, var(--dl-accent) 55%, transparent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: var(--wire-len);
  stroke-dashoffset: var(--wire-len);
}
/* El avance lo escribe main.js §6 leyendo el scroll: la transición corta
   sólo suaviza el salto entre un frame y el siguiente. */
.formas-stage.is-wired .formas-wire-path {
  transition: stroke-dashoffset .12s linear;
}

.formas-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(22px, 4vw, 34px);
}
@media (min-width: 700px) {
  .formas-grid { grid-template-columns: 1fr 1fr; }
}

.formas-card {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  /* Casi opaca a propósito: el hilo pasa por detrás y sólo debe verse en
     los huecos, no cruzando el texto. */
  background:
    radial-gradient(120% 80% at 12% 0%, rgba(194,84,42,.10) 0%, transparent 58%),
    var(--dl-bg-elev);
  border: 1px solid var(--dl-glass-border);
  border-radius: 20px;
  --card-pad: clamp(26px, 4.4vw, 34px);
  padding: var(--card-pad);
  /* Entra apenas el usuario llega a la sección (JS agrega `.is-visible` vía
     IntersectionObserver, ver main.js §6) — nunca fija el scroll ni depende
     de un loop, sólo juega una vez por tarjeta. El recorrido es largo a
     propósito: con un desplazamiento corto el movimiento no se percibía. */
  opacity: 0;
  transform: translateY(46px) scale(.94);
  transition: opacity .7s ease, transform .8s cubic-bezier(.16,1,.3,1),
              border-color .35s ease, box-shadow .35s ease;
}
.formas-card.is-visible { opacity: 1; transform: translateY(0) scale(1); }

/* Barrido de luz que cruza la tarjeta una sola vez al entrar: es lo que
   hace que se lea como "se encendió", no como "apareció". */
.formas-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 38%,
    color-mix(in srgb, var(--dl-accent) 16%, transparent) 50%,
    transparent 62%);
  transform: translateX(-115%);
  opacity: 0;
}
.formas-card.is-visible::after {
  animation: formas-sweep 1.15s cubic-bezier(.4,0,.2,1) .12s both;
}
@keyframes formas-sweep {
  0%   { opacity: 0;  transform: translateX(-115%); }
  22%  { opacity: 1; }
  100% { opacity: 0;  transform: translateX(115%); }
}

/* Filo superior de luz: da el borde "encendido" de la referencia sin
   pintar toda la tarjeta de color. */
.formas-card::before {
  content: "";
  position: absolute;
  top: 0; left: 18%; right: 18%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--dl-accent-soft), transparent);
  opacity: .5;
  transition: opacity .35s ease, left .45s ease, right .45s ease;
}

@media (hover: hover) and (pointer: fine) {
  .formas-card:hover {
    border-color: color-mix(in srgb, var(--dl-accent) 45%, var(--dl-glass-border));
    box-shadow: 0 26px 50px -28px rgba(0,0,0,.75),
                0 0 0 1px color-mix(in srgb, var(--dl-accent) 18%, transparent);
  }
  .formas-card:hover::before { opacity: 1; left: 6%; right: 6%; }
  /* Se conserva la escala final de la entrada: sólo cambia el brillo, para
     que el hover no pelee con la transformación con la que quedó. */
  .formas-card.is-visible:hover .formas-num { opacity: .34; }
  .formas-card:hover .formas-chip {
    border-color: color-mix(in srgb, var(--dl-accent) 55%, transparent);
    background: color-mix(in srgb, var(--dl-accent) 18%, transparent);
  }
}

/* Número grande de fondo — la "carta" de la referencia. Decorativo: no se
   lee como contenido, sólo ancla visualmente el orden. */
.formas-num {
  position: absolute;
  top: clamp(10px, 2vw, 16px);
  right: clamp(16px, 3vw, 24px);
  z-index: -1;
  font-family: var(--dl-font-display);
  font-size: clamp(64px, 13vw, 104px);
  font-weight: 900;
  line-height: .82;
  letter-spacing: -.05em;
  background: linear-gradient(160deg, var(--dl-accent-soft), transparent 75%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  opacity: 0;
  pointer-events: none;
  /* Llega desde más grande y desplazado: el número es lo primero que se
     mueve, y de ahí baja la vista al ícono y a la frase. */
  transform: scale(1.3) translate(14px, -10px);
  transition: opacity .8s ease .05s,
              transform .9s cubic-bezier(.16,1,.3,1) .05s;
}
.formas-card.is-visible .formas-num {
  opacity: .2;
  transform: scale(1) translate(0, 0);
}

/* Nodo del hilo: es el punto que main.js mide para trazar la línea. Va
   adentro de la esquina superior izquierda —nunca sobre el borde— porque
   la tarjeta tiene `overflow: hidden` (lo necesita el barrido de luz) y
   cualquier cosa que sobresalga del borde queda cortada a la mitad. */
.formas-node {
  position: absolute;
  left: 16px;
  top: 16px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--dl-accent);
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--dl-accent) 16%, transparent),
              0 0 14px color-mix(in srgb, var(--dl-accent) 55%, transparent);
  transform: scale(0);
  transition: transform .5s cubic-bezier(.34,1.56,.64,1) .3s;
}
.formas-card.is-visible .formas-node { transform: scale(1); }

.formas-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  margin: 0 0 18px;
  border-radius: 14px;
  border: 1px solid color-mix(in srgb, var(--dl-accent) 30%, transparent);
  background: color-mix(in srgb, var(--dl-accent) 10%, transparent);
  color: var(--dl-accent-soft);
  opacity: 0;
  transform: translateY(10px) rotate(-8deg);
  transition: opacity .5s ease .18s,
              transform .6s cubic-bezier(.34,1.56,.64,1) .18s,
              border-color .35s ease, background-color .35s ease;
}
.formas-card.is-visible .formas-chip {
  opacity: 1;
  transform: translateY(0) rotate(0);
}

/* El ícono se dibuja solo: el trazo entra como si alguien lo estuviera
   trazando, en vez de aparecer de golpe. El dasharray es aproximado —
   basta con que supere el largo real de cada trazo. */
.formas-icon { display: block; }
.formas-icon > * {
  stroke-dasharray: 90;
  stroke-dashoffset: 90;
}
.formas-card.is-visible .formas-icon > * {
  animation: formas-draw .85s cubic-bezier(.4,0,.2,1) .32s forwards;
}
.formas-card.is-visible .formas-icon > *:nth-child(2) { animation-delay: .46s; }
.formas-card.is-visible .formas-icon > *:nth-child(3) { animation-delay: .58s; }
@keyframes formas-draw { to { stroke-dashoffset: 0; } }

/* La frase de auto-identificación es lo primero que tiene que leer la
   persona: es la que la hace reconocerse antes de saber cómo se llama el
   servicio. Va tratada como cita —comilla de acento, tinta clara, un punto
   más grande que el cuerpo— para que gane el primer golpe de vista frente
   al <h3>. No lleva la fuente display de los números: son un carácter
   decorativo suelto, una frase entera en ese estilo compite con el título
   y se lee peor en móvil. */
.formas-hook {
  position: relative;
  margin: 0 0 14px !important;
  padding-left: 20px;
  font-size: clamp(1.02rem, 2.4vw, 1.12rem);
  font-style: italic;
  line-height: 1.45;
  color: var(--dl-ink);
  /* Se revela con una máscara que corre de izquierda a derecha, como si se
     estuviera escribiendo: es mucho más notorio que un fade y refuerza que
     ésta es la línea que hay que leer primero. */
  opacity: 0;
  clip-path: inset(0 100% 0 0);
  transition: opacity .3s ease .34s,
              clip-path .85s cubic-bezier(.4,0,.2,1) .34s;
}
.formas-card.is-visible .formas-hook {
  opacity: 1;
  clip-path: inset(0 0 0 0);
}

/* Segunda etapa: el detalle del servicio. Sólo cambia opacidad y posición
   —nunca `display`— para que la tarjeta mida siempre lo mismo y no haya
   salto de layout entre una etapa y la otra. */
.formas-body > * {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .6s ease, transform .7s cubic-bezier(.16,1,.3,1);
}
.formas-card.is-open .formas-body > * { opacity: 1; transform: translateY(0); }
.formas-card.is-open .formas-body > *:nth-child(2) { transition-delay: .09s; }
.formas-card.is-open .formas-body > *:nth-child(3) { transition-delay: .18s; }
.formas-card.is-open .formas-body > *:nth-child(4) { transition-delay: .27s; }

/* Los ítems entran uno detrás de otro dentro de la lista, no todos juntos:
   se lee como una enumeración que se va armando. */
.formas-list li {
  opacity: 0;
  transform: translateX(-10px);
  transition: opacity .5s ease, transform .55s cubic-bezier(.16,1,.3,1);
}
.formas-card.is-open .formas-list li { opacity: 1; transform: translateX(0); }
.formas-card.is-open .formas-list li:nth-child(1) { transition-delay: .26s; }
.formas-card.is-open .formas-list li:nth-child(2) { transition-delay: .36s; }
.formas-card.is-open .formas-list li:nth-child(3) { transition-delay: .46s; }
.formas-card.is-open .formas-list li:nth-child(4) { transition-delay: .56s; }

/* El check se dibuja al llegar su ítem, en vez de estar ya puesto. */
.formas-list li::before {
  transform: rotate(-45deg) scale(0);
  transition: transform .45s cubic-bezier(.34,1.56,.64,1);
}
.formas-card.is-open .formas-list li::before { transform: rotate(-45deg) scale(1); }
.formas-card.is-open .formas-list li:nth-child(1)::before { transition-delay: .34s; }
.formas-card.is-open .formas-list li:nth-child(2)::before { transition-delay: .44s; }
.formas-card.is-open .formas-list li:nth-child(3)::before { transition-delay: .54s; }
.formas-card.is-open .formas-list li:nth-child(4)::before { transition-delay: .64s; }

/* Con movimiento reducido no hay entrada de nada: todo llega ya puesto.
   main.js aplica `is-visible`/`is-open` de una sola vez en ese caso, así que
   acá sólo hay que neutralizar transformaciones, máscaras y animaciones. */
@media (prefers-reduced-motion: reduce) {
  .formas-card,
  .formas-card .formas-num,
  .formas-card .formas-chip,
  .formas-card .formas-node,
  .formas-card .formas-hook,
  .formas-body > *,
  .formas-list li {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .formas-card .formas-num { opacity: .2 !important; }
  .formas-card::after { display: none; }
  .formas-icon > * { stroke-dashoffset: 0 !important; animation: none !important; }
  .formas-list li::before { transform: rotate(-45deg) !important; }
  .formas-wire-path { transition: none !important; }
}
.formas-hook::before {
  content: "\201C";
  position: absolute;
  left: 0;
  top: -.1em;
  font-family: var(--dl-font-display);
  font-size: 1.6em;
  font-style: normal;
  line-height: 1;
  color: var(--dl-accent-soft);
}
.formas-card h3 {
  margin: 0 0 6px;
  font-family: var(--dl-font-display);
  font-size: clamp(1.1rem, 2.6vw, 1.35rem);
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--dl-ink);
}
.formas-lema {
  margin: 0 0 18px !important;
  font-family: var(--dl-font-mono);
  font-size: 12px;
  letter-spacing: .06em;
  text-transform: uppercase;
  /* --dl-accent puro da 3.9:1 a este tamaño sobre el panel oscuro; la
     variante clara sí pasa AA */
  color: var(--dl-accent-soft);
}
.formas-card p { margin: 0 0 12px; line-height: 1.65; }
.formas-card p:last-child { margin-bottom: 0; }

.formas-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 12px;
}
.formas-list li {
  position: relative;
  padding-left: 26px;
  line-height: 1.55;
  color: var(--dl-ink);
}
.formas-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 14px;
  height: 8px;
  border-left: 2px solid var(--dl-accent-soft);
  border-bottom: 2px solid var(--dl-accent-soft);
  transform: rotate(-45deg);
}
.formas-close {
  margin: 18px 0 0 !important;
  padding-top: 16px;
  border-top: 1px solid var(--dl-glass-border);
  font-style: italic;
  color: var(--dl-ink-mute);
}

/* ---------------- Sobre mí ---------------- */

/* bentoDataHero no trae foto (§4.6): la agrega el propio HTML como hermano
   fijo, antes de que el módulo monte su contenido (ver index.html). Circular
   a propósito: la foto original tiene fondo gris liso, y recortarla en
   círculo evita tener que enmascarar ese fondo por CSS para que se funda
   con el fondo oscuro del sitio. */
.sobre-photo {
  display: block;
  width: clamp(120px, 22vw, 168px);
  height: clamp(120px, 22vw, 168px);
  margin: 0 auto clamp(20px, 4vw, 28px);
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid color-mix(in srgb, var(--dl-accent) 45%, transparent);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--dl-accent) 8%, transparent),
              0 20px 40px -20px rgba(0,0,0,.7);
}

/* ---------------- Contacto ---------------- */

.contact-parent { display: flex; justify-content: center; }
.contact-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  max-width: 680px;
}
.contact-card h2 {
  margin: 0;
  font-family: var(--dl-font-display);
  font-size: clamp(1.5rem, 4.4vw, 2.3rem);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.08;
  color: var(--dl-ink);
}
.contact-card > p {
  margin: 0;
  color: var(--dl-ink-mute);
  max-width: 46ch;
}
.contact-hint {
  margin: 0 !important;
  font-family: var(--dl-font-mono);
  font-size: 12.5px;
  line-height: 1.7;
  letter-spacing: .02em;
  color: var(--dl-ink);
  border-left: 2px solid var(--dl-accent);
  padding-left: 14px;
  max-width: 52ch;
}
.contact-card .ms-neoncard-button { text-decoration: none; margin-top: 6px; }
.contact-alt { font-size: 14px; }
.contact-alt a { color: var(--dl-accent-soft); text-decoration: underline; }

/* ---------------- Footer ---------------- */

.site-foot {
  padding: 48px var(--dl-gutter) calc(120px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--dl-glass-border);
  text-align: center;
}
.site-foot p {
  margin: 0;
  font-family: var(--dl-font-mono);
  font-size: 12px;
  letter-spacing: .06em;
  color: var(--dl-ink-mute);
  text-transform: uppercase;
}
@media (min-width: 768px) {
  .site-foot { padding-bottom: 56px; }
}

/* ---------------- Responsive ---------------- */

@media (max-width: 860px) {
  .work-grid { grid-template-columns: 1fr; gap: 36px; }
  [data-orient="landscape"], [data-orient="portrait"] { grid-column: span 1; }
}

/* Sin puntero fino no hay tilt: el scale(1.06) del parallax sólo recortaría
   el video sin dar nada a cambio. */
@media (hover: none) {
  .work-media video { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .work-media video { transform: none; transition: none; }
  .btn-wa:hover, .wa-float:hover { transform: none; }
}
