/* ==========================================================================
   Cabbage — componentes v5. Cortina de entrada, nav de píldoras, hero
   pineado con el panel que se pliega en medallón, y footer a sangre.
   ========================================================================== */

/* ==========================================================================
   CORTINA — un plano que se pliega hacia arriba y descubre la página.

   LA REGLA DEL COLOR: la cortina solo se percibe si CONTRASTA con lo que
   destapa. Las interiores son páginas claras (sprout, field, sea, bloom,
   paper), así que ahí el verde col es el que contrasta. La home es la
   excepción y va al revés (.curtain--light): su hero es un panel de ese
   mismo verde, y una cortina verde se plegaba sobre un fondo idéntico sin
   que se notara nada.

   Ojo si se toca: NO usar var(--page) en la regla genérica. Ese token se
   redefine por sección, y en presencia.html la cortina saldría exactamente
   del color de la página.
   ========================================================================== */
.curtain {
  position: fixed; inset: 0;
  z-index: 300;
  background: var(--dark);
  display: none;
  place-items: center; /* centra la marca de las interiores */
  /* Polígono, no inset: el navegador normaliza inset(0 0 0 0) a inset(0%)
     y GSAP ya no puede interpolarlo — el pliegue saltaría de golpe */
  clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
}
html.js .curtain { display: grid; }
body.is-done .curtain { display: none !important; }

/* La de la HOME, al revés: crema, para que el pliegue descubra el verde
   del hero y el barrido se vea. */
.curtain--light { background: var(--page); }

/* LA TARJETA DE MARCA: «Cabbage» un momento, y se va hacia arriba antes de
   que la página entre. Sobre el verde de las interiores va en crema; sobre
   la crema de la home, en tinta verde. */
.curtain__mark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 6vw, 5rem);
  color: var(--on-dark);
  letter-spacing: -0.02em;
}
.curtain--light .curtain__mark { color: var(--dark); }

@media (prefers-reduced-motion: reduce) {
  .curtain { display: none !important; }
}

/* ==========================================================================
   NAV — fija; sobre el hero habla en claro, sobre el papel en tinta.
   La marca pequeña solo aparece cuando el wordmark gigante ya no se ve.
   ========================================================================== */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  padding: var(--s5) var(--nav-inset);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
}

/* EL FONDO DE LA NAV. Sobre el hero no hace falta: el panel oscuro ya es
   sólido. En cualquier otro punto, el contenido pasa por DEBAJO de la nav al
   hacer scroll —un titular, el wordmark gigante del footer— y sin nada detrás
   de la marca y los huecos entre píldoras, ese contenido se lee a través de
   las letras. Una franja plana del color de la página lo evita. */
.nav::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--page);
  opacity: 0;
}
body:not(.over-hero) .nav::before { opacity: 1; }
body.over-dark .nav::before { background: var(--dark); }

.nav__mark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--page-ink);
  transition: opacity var(--t-base) var(--ease), transform var(--t-base) var(--ease),
              color var(--t-wash) var(--ease);
}
body.over-hero .nav__mark { opacity: 0; transform: translateY(-14px); pointer-events: none; }

/* min-width:0 rompe el mínimo por defecto de un flex item (que es el ancho
   de su contenido sin partir). Sin esto, en una pantalla estrecha el grupo
   entero se salía del nav en vez de encoger, y "menú" quedaba fuera de la
   pantalla, inalcanzable. */
.nav__menu { display: flex; align-items: center; gap: var(--s1); min-width: 0; }

.nav__links { display: flex; gap: var(--s1); }

/* Los botones de la nav: la píldora redonda de TODA la web —la misma de
   «.more», la del CTA final—, no las formas angulosas de la referencia.
   Aquella escala (hexágono → esquinas mordidas → romo → píldora) es su
   firma, no la de Cabbage: aquí la identidad es la letra Fredoka en bola,
   las tarjetas de esquina blanda y una sola forma redonda para todo botón.
   Mismo tipo, mismo peso y mismo tracking que «.more», para que se lean
   como la misma familia de botón en toda la página. */
.nav__links a,
.nav__cta {
  /* relative + stacking context: el relleno que sube vive dentro, en z-index
     negativo, y overflow lo enmascara contra el borde de la píldora */
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding: 12px var(--s5);
  border-radius: var(--r-pill);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  /* Sin esto, en una pantalla muy estrecha "CUÉNTANOS TU PROYECTO" partía
     en varias líneas dentro de la píldora: con las puntas redondeadas a
     999px, un botón de dos o tres líneas deja de leerse como botón y pasa
     a ser un borrón ovalado con letras encima. */
  white-space: nowrap;
  /* El cristal esmerilado sigue integrando la píldora con lo que hay
     detrás; es independiente de la forma, así que se queda */
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  /* Sin will-change: promocionar a capa un elemento con texto lo rasteriza una
     vez y lo compone después — el texto sale ligeramente sucio. Ver la nota
     larga en «.more». */
  transition: background var(--t-micro) var(--ease), color var(--t-micro) var(--ease),
              transform 200ms var(--ease-pop);
}
.nav__links a:hover,
.nav__cta:hover { transform: translateY(-2px); }
.nav__links a:active,
.nav__cta:active { transform: translateY(0) scale(0.96); transition-duration: 90ms; }

@media (prefers-reduced-motion: reduce) {
  .nav__links a, .nav__cta { transition: background var(--t-micro) var(--ease), color var(--t-micro) var(--ease); }
  .nav__links a:hover, .nav__cta:hover,
  .nav__links a:active, .nav__cta:active { transform: none; }
}

.nav__links a { background: var(--pill-bg-2); }

/* La página en la que estás. En un sitio de una sola página esto sobraba;
   en uno de siete, es lo que te dice dónde te encuentras sin leer nada. */
.nav__links a[aria-current="page"] {
  background: var(--dark);
  color: var(--on-dark);
}

/* EL RELLENO QUE SUBE. El gesto de los enlaces de la referencia: una capa
   crema que entra desde abajo y llena la píldora. Va en z-index negativo
   para pintarse SOBRE el fondo translúcido de la píldora pero DEBAJO de las
   letras — por eso el <a> necesita su propio contexto de apilamiento. */
/* Sin transform aquí: la posición de reposo la fija GSAP con yPercent. Si el
   CSS también la declarase, GSAP leería esa translateY como un desplazamiento
   en píxeles y le SUMARÍA su yPercent — el relleno arrancaría al doble de
   distancia y entraría tarde. La capa solo existe con JS, así que basta con
   nacer oculta. */
.nav__base {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: #FDFBF4;
  visibility: hidden;
}

/* Cada letra por separado: es lo que permite la ola de color, letra a letra.
   inline-block para que se le pueda animar el color de una en una; pre para
   que los espacios no se colapsen al partir el texto. */
.char { display: inline-block; white-space: pre; }

/* Sobre CUALQUIER superficie oscura —el panel del hero o el footer— las
   píldoras hablan en claro. Antes solo miraba al hero, y al llegar al pie
   los enlaces desaparecían contra el verde. */
body.over-hero .nav__links a,
body.over-dark .nav__links a { background: rgba(242, 238, 224, 0.1); color: var(--on-dark); }
body.over-hero .nav__toggle,
body.over-dark .nav__toggle { background: rgba(242, 238, 224, 0.1); color: var(--on-dark); }
body.over-dark .nav__mark { color: var(--on-dark); }
body.over-dark .nav__links a[aria-current="page"] {
  background: rgba(242, 238, 224, 0.85);
  color: var(--dark);
}

/* Sin JS (o sin hover) el enlace sigue respondiendo: el relleno no existe,
   pero el fondo se aclara. Nunca un botón muerto. */
html:not(.js) .nav__links a:hover,
.nav__links a:hover { background: var(--pill-bg-3); }

/* LA CTA. Su degradado no está quieto: deriva despacio, en bucle. Es lo que
   hace que el botón parezca vivo sin que nadie lo toque. 180% de fondo para
   que haya recorrido que desplazar. */
.nav__cta {
  border-radius: var(--r-pill);
  background: var(--grad-cta);
  background-size: 180% 180%;
  color: var(--dark);
  animation: grad-drift 10s ease infinite;
}

@keyframes grad-drift {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .nav__cta { animation: none; background-size: 100% 100%; }
}

.nav__toggle { display: none; }

@media (max-width: 880px) {
  .nav__links { display: none; }
  .nav__menu.is-open .nav__links {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: calc(100% + var(--s2));
    right: var(--nav-inset);
    background: var(--dark);
    padding: var(--s4);
    border-radius: var(--r-lg);
  }
  .nav__menu.is-open .nav__links a { color: var(--on-dark); background: rgba(242, 238, 224, 0.08); }
  .nav__toggle {
    display: block;
    padding: var(--s3) var(--s6);
    border-radius: var(--r-pill);
    background: var(--pill-bg-2);
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: -0.01em;
  }
  .nav__menu { position: relative; }
}

/* LA NAV COMPACTA. En un móvil, la barra tiene que meter la marca, el CTA y
   el botón de menú: medido, el conjunto con la etiqueta larga necesita 484 px
   de barra, y por debajo de eso el «Menú» se sale de la pantalla (a 320 px al
   CTA le quedan unos 70 px, en los que no cabe entero A NINGÚN cuerpo de letra
   razonable). Así que aquí la etiqueta se ACORTA a «Cuéntanos». Acortar no es
   recortar: unos puntos suspensivos («CUÉ…») dejan el botón roto, y partir en
   dos líneas deshace la píldora. El corte va en 560 y no en los 484 justos:
   un umbral al milímetro se rompe en cuanto la fuente monta un pelo distinta.

   Cómo: font-size 0 apaga el texto real y ::before pinta el corto. Parece un
   truco, pero es lo que hace que funcione en los dos mundos —el texto crudo
   del móvil y los <span> por letra que GSAP crea en el escritorio para la ola
   de color (ver splitChars en main.js), que un simple <span> en el HTML no
   sobreviviría—. Y el texto largo sigue en el DOM: el lector de pantalla
   anuncia «Cuéntanos tu proyecto» entero, y la etiqueta visible está contenida
   en la accesible, como pide la WCAG (2.5.3). */
@media (max-width: 560px) {
  /* La marca y el botón de menú ceden unos píxeles para que el CTA tenga
     sitio de verdad: si no, todo lo que falta se lo come él solo. */
  .nav__mark { font-size: 1.15rem; }
  .nav__toggle { padding: var(--s3) var(--s4); }

  .nav__cta { font-size: 0; padding: 12px var(--s4); }
  .nav__cta::before {
    content: "Cuéntanos";
    font-size: 0.6875rem;
    letter-spacing: -0.01em;
  }
}

/* ==========================================================================
   HERO — la pista mide varias pantallas; el hero queda pineado y el scroll
   conduce la animación: el texto cae y el panel verde se pliega en medallón.
   Sin JS o con movimiento reducido, la pista mide una pantalla y ya está.
   ========================================================================== */
.hero-track { height: 100svh; }
/* 160svh, medido sobre la referencia (su pista mide 1.5× la pantalla, no
   2.8×): con la pista más larga la misma animación tardaba casi el doble
   de scroll en completarse, y por eso se sentía más lenta al bajar. */
body.has-motion .hero-track { height: 160svh; }

/* En móvil el mismo tramo se recorre a base de swipes, no de rueda: 60svh
   de scroll "extra" antes de llegar al Proceso se sienten como un hueco
   largo entre la portada y "Tu empresa. Nuestro oficio.". Se acorta sin
   tocar el escritorio. */
@media (max-width: 880px) {
  body.has-motion .hero-track { height: 135svh; }
}

.hero {
  height: 100svh;
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  padding: 0 var(--margin) clamp(48px, 8vh, 80px);
}

/* El panel: el plano verde col que el scroll recorta en medallón. Parte
   del rectángulo de 8 puntos (--oct-rect) y se pliega en el OCTÓGONO de
   la referencia: mismos vértices, así que GSAP interpola sin saltos. */
.hero__visual {
  position: absolute;
  inset: 0;
  /* El verde col es la BASE; el lavado de color va encima, en ::after. */
  background: var(--dark);
  display: grid;
  place-items: center;
  clip-path: var(--oct-rect);
  will-change: clip-path;
}

/* EL LAVADO. El degradado de la casa en su mitad fría —verde y turquesa—,
   tendido enorme sobre el verde col y a un 12 %, con su mismo vaivén de 10 s.
   Antes reusaba el degradado completo del CTA (con ámbar y coral), pero esos
   dos tramos cálidos dejaban sobre el verde un poso marrón/oliva que no iba
   con el resto del sitio; en verde/turquesa el hero habla el mismo color que
   el hero/footer y los acentos. Deliberadamente NO es un resplandor difuso
   flotando por el fondo: eso es el recurso que pondría cualquiera. Aquí es el
   color que la marca ya habla, dicho muy bajito.

   Va en ::after y no como segunda capa de background para poder graduarlo
   con opacity (un background-layer no se puede atenuar por su cuenta). Al
   ser hijo, el clip-path del pliegue se lo lleva consigo al medallón. */
.hero__visual::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--grad-hero);
  background-size: 180% 180%;
  opacity: 0.12;
  animation: grad-drift 10s ease infinite;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .hero__visual::after { animation: none; background-size: 100% 100%; }
}

.hero__row {
  position: relative;
  width: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s6);
  container-type: inline-size;
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-word);
  line-height: 0.9;
  /* -0.04em era el ajuste para Fredoka: sus letras redondas dejan mucho
     hueco propio entre sí, así que necesitaban ese apriete para no verse
     desperdigadas. Sora ya nace más cerrada y geométrica — al tamaño del
     wordmark (hasta 336 px) ese mismo -0.04em son -13 px por letra, y la
     «bb» y la «ag» llegaban a tocarse. Con las letras de Sora, mucho menos
     apriete basta para que el bloque se lea compacto sin embarullarse. */
  letter-spacing: -0.01em;
  color: var(--on-dark);
  white-space: nowrap;
}

/* LA MÁQUINA DE ESCRIBIR. «Cabbage» se teclea de verdad con el TextPlugin de
   GSAP: el texto del nodo crece letra a letra (textContent real, no un ancho
   recortado), así que es tecleo de verdad y no un simple recorte que se
   revela. El cursor vive DENTRO de la caja, pegado a su borde derecho: como
   la caja es inline-block de ancho automático, sigue solo el borde del texto
   ya escrito sin ningún cálculo aparte. Oculta hasta que el JS la destapa a
   la vez que empieza a teclear —si no, el «Cabbage» completo del HTML
   parpadearía un instante antes de vaciarse—; sin JS o con movimiento
   reducido, nace ya visible. */
.wordmark__type {
  display: inline-block;
  position: relative;
  vertical-align: bottom;
  max-width: 100%;
}
html.js .wordmark__type { visibility: hidden; }
body.is-done .wordmark__type { visibility: visible; }

/* Una caja en línea VACÍA no genera línea y colapsa a 0 de alto — y el
   cursor, que se estira entre su top y su bottom, se quedaría en nada justo
   en el momento en que más se le ve: esperando, antes de la primera letra.
   El espacio de ancho cero le da caja y línea base sin ocupar un píxel. */
.wordmark__type::after { content: "\200B"; }

/* El cursor no parpadea: nace apagado, el JS lo enciende al empezar a
   teclear y lo funde cuando la palabra ya está entera. */
.wordmark__caret {
  position: absolute;
  top: 0.05em;
  bottom: 0.1em;
  right: 0;
  width: 0.05em;
  background: var(--on-dark);
  opacity: 0;
}

/* El ® colgado del hombro de la última letra, como en la referencia:
   pequeño, arriba, y sin arrastrar la línea base del wordmark. Vive FUERA
   de .wordmark__type (si no, al ser hermano tras una caja de ancho
   automático, flotaría pegado al cursor desde la primera letra en vez de
   esperar a que termine la palabra) y aparece con la última pulsación. */
html.js .wordmark__r { opacity: 0; }
body.is-done .wordmark__r { opacity: 1; }
.wordmark__r {
  /* inline-block para que acepte la escala del sello (un inline no la
     acepta: transform no se aplica a cajas en línea). */
  display: inline-block;
  font-size: 0.11em;
  vertical-align: super;
  letter-spacing: 0;
  margin-left: 0.04em;
}

/* LA PISTA DE SCROLL. Vive en la franja libre que queda entre el pie del
   wordmark y el borde de la pantalla, pegada al margen derecho para no
   pelearse con el wordmark (que ocupa toda la esquina izquierda). El color
   va rebajado con alfa y NO con opacity: [data-hero-in] ya usa opacity para
   entrar, y las dos se pisarían. */
.hero__cue {
  position: absolute;
  right: var(--margin);
  bottom: clamp(14px, 2.4vh, 26px);
  display: flex;
  align-items: center;
  gap: 10px;
  text-transform: uppercase;
  color: rgb(242 238 224 / 0.6);
  pointer-events: none;
}

/* El raíl, con un tramo encendido que lo recorre hacia abajo: dice «hay
   más» sin dibujar una flecha ni pedir permiso. */
.hero__cue-line {
  position: relative;
  display: block;
  width: 1px;
  height: 26px;
  background: rgb(242 238 224 / 0.22);
  overflow: hidden;
}
.hero__cue-line::after {
  content: '';
  position: absolute;
  left: 0;
  width: 1px;
  height: 9px;
  background: var(--on-dark);
  animation: cue-baja 1.9s ease-in-out infinite;
}
@keyframes cue-baja {
  0%   { top: -9px; }
  60%  { top: 26px; }
  100% { top: 26px; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__cue-line::after { animation: none; top: 8px; }
}

/* Se mantiene también en columna: el hero sigue pineado igual que en
   escritorio (el primer scroll no baja la página, la pliega en el
   medallón), y sin este aviso ese gesto se lee como que la web se ha
   quedado colgada — más aún para quien no está acostumbrado a este tipo
   de scroll. El padding-bottom del propio .hero (clamp 48-80px) ya le
   reserva sitio de sobra aunque la frase pase arriba en columna. */

.hero__thesis {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 1rem + 1.4vw, 2rem);
  line-height: 1.16;
  letter-spacing: -0.01em;
  max-width: 11em;
  /* El wordmark no cede espacio (es nowrap, su ancho lo fija --fs-word) y
     en flexbox eso significa que TODO el apriete cae en el otro hijo: sin
     un mínimo propio, la tesis se deja exprimir hasta una columna de una
     palabra por línea, que lee roto en vez de compuesto. min-width le pone
     un suelo — nunca baja de un bloque de 2-3 palabras por renglón. */
  min-width: min(12em, 24vw);
  padding-bottom: 0.5em;
  color: var(--on-dark);
}

@media (max-width: 720px) {
  .hero__row { flex-direction: column; align-items: flex-start; }
  .hero__thesis { padding-bottom: 0; order: -1; }
  /* 21vw del VIEWPORT (no del hueco real, ya angosto en columna) se pasaba
     del propio .hero__row en los móviles más estrechos y el "Cabbage" se
     leía sin la "e" — el mismo fallo que el del wordmark del footer, y la
     misma cura: cqw del propio contenedor en vez de vw de la pantalla. */
  .wordmark { font-size: clamp(3.4rem, 19cqw, 7rem); }
}

/* ==========================================================================
   Etiqueta doble de sección — «LO QUE / HACEMOS»
   ========================================================================== */
.duotag {
  display: inline-flex;
  align-items: center;
  text-transform: uppercase;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.duotag span {
  padding: var(--s2) var(--s5);
  clip-path: var(--hex);
  background: #FDFBF4;
  color: var(--ink);
}
/* Las dos puntas se solapan: encajan como dos piezas, no como dos píldoras */
.duotag span + span {
  background: var(--pill-bg-2);
  color: var(--page-ink);
  margin-left: -14px;
  transition: color var(--t-wash) var(--ease);
}

/* ==========================================================================
   Secciones centradas — el titular gigante es el contenido
   ========================================================================== */
.stage {
  padding: clamp(96px, 14vh, 140px) var(--margin);
  text-align: center;
}

.stage__inner {
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  justify-items: center;
  gap: var(--s6);
}

/* La sección del proceso no se rige por el ancho de lectura: su fila de
   fichas ocupa el 96 % de la pantalla, como en la referencia. El titular y
   el texto siguen midiendo lo suyo (17ch, 34rem), así que solo se ensancha
   el contenedor.

   Sin `grid-template-columns` explícito, la columna única se dimensiona al
   contenido: si un hijo (.steps) es más ancho que el hueco disponible, la
   pista crece para caber ENTERA y se ancla al borde de inicio, así que el
   sobrante se desborda solo hacia la derecha — la fila queda descuadrada
   respecto al titular de arriba, que sí está centrado. Fijar la pista al
   100 % del contenedor hace que ese sobrante se reparta a partes iguales a
   los dos lados, que es como se centra algo más ancho que su caja. */
.stage--wide .stage__inner {
  max-width: none;
  grid-template-columns: minmax(0, 1fr);
}

.stage h2 { max-width: 17ch; }
.stage .lead { margin: 0 auto; }

/* El titular a dos versos: cada frase manda en su propia línea, no la parte
   el ancho máximo. Es como respira el de la referencia. */
.stage h2.h2--verses,
.stage h1.h2--verses { max-width: none; }
.h2--verses span { display: block; }

/* ==========================================================================
   Botón «cuéntanos» — píldora clara con el anillo-flecha
   ========================================================================== */
/* NADA DE will-change AQUÍ. Lo puse en su día creyendo que curaba el borrón
   del primer fotograma, y era justo al revés: will-change promociona el botón
   a una capa de composición PERMANENTE, y una capa se rasteriza una vez y
   luego se compone. Sobre un elemento con TEXTO y con clip-path, eso es
   exactamente el «blur raro» — las letras y el borde del octógono se pintan a
   una resolución y se recomponen a otra. Un translate simple lo sabe hacer
   Chrome nítido sin ayuda: la ayuda era el problema. */
.more {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--s4);
  padding: var(--s2) var(--s2) var(--s2) var(--s6);
  border-radius: var(--r-pill);
  background: #FDFBF4;
  color: var(--ink);
  font-weight: 600;
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  box-shadow: var(--card-shadow);
  transition: transform 220ms var(--ease-pop), box-shadow 220ms var(--ease);
}

/* EL FOCO VIVE IGUAL QUE EL RATÓN. Estaba todo colgado de :hover, así que
   quien navega con teclado solo recibía el recuadro del sistema: llegaba a
   un botón muerto. Cada estado de aquí abajo se declara para los dos. */
.more:hover,
.more:focus-visible {
  transform: translateY(-3px);
  /* La sombra, teñida de verde col y no de negro puro. Estos botones caen
     sobre lavados de color (menta, ámbar, turquesa) y un negro neutro los
     ensucia de gris; con el verde de la marca la sombra pertenece a la
     paleta en vez de estar puesta encima. */
  box-shadow: 0 16px 30px -12px rgb(43 67 33 / 0.42);
}
/* La pulsación: se hunde entero. Es el único scale de todo el botón, dura 90 ms
   y no cae sobre el octógono recortado, así que no hay nada que reescalar. */
.more:active { transform: translateY(-1px) scale(0.97); transition-duration: 90ms; }

/* UN SOLO GESTO, NO DOS. Antes subía la píldora por un lado y la flecha
   hacía lo suyo por otro. Ahora el texto se aparta un pelín hacia la
   izquierda mientras la flecha sale por la derecha: el movimiento tiene una
   dirección común y se lee como una sola cosa. Son 2 px — si se nota, es
   que es demasiado. */
.more__label {
  display: inline-block;
  transition: transform 220ms var(--ease);
}
.more:hover .more__label,
.more:focus-visible .more__label { transform: translateX(-2px); }

/* EL OCTÓGONO YA NO GIRA. Giraba 16°, y un octógono girado deja de apoyarse en
   su lado plano: se lee torcido dentro de una píldora que es perfectamente
   recta, que es la sensación de «descentrado». Además, rotar un clip-path
   dentelle el borde. Ahora se queda quieto y firme, y lo que se mueve es lo
   de dentro — que es donde tiene sentido que pase algo. */
.more__ring {
  width: 34px;
  aspect-ratio: 1;
  clip-path: var(--oct);
  background: var(--dark);
  display: grid;
  place-items: center;
  overflow: hidden;              /* la flecha que sale se corta en el borde */
  transition: background 220ms var(--ease);
}
.more:hover .more__ring,
.more:focus-visible .more__ring { background: var(--live); }
.more:active .more__ring { background: var(--live); }

/* LA FLECHA SE INVIERTE, NO SE LAVA. El anillo se ilumina a --live, y sobre
   ese verde la flecha crema se quedaba en 1,77:1 —por debajo del 3:1 que
   piden los iconos— o sea que DESAPARECÍA justo en el momento de mayor
   atención. Pasándola a tinta oscura sube a 6,56:1, y de paso el estado
   deja de ser un lavado para ser una inversión: oscuro sobre claro donde
   antes había claro sobre oscuro. Se lee como decidido, no como un
   accidente de color. */
.more:hover .more__ring svg,
.more:focus-visible .more__ring svg,
.more:active .more__ring svg { color: var(--dark); }

/* EL PLAY, CENTRADO DE VERDAD. Estaba centrado por caja —y por eso se veía
   torcido—: el triángulo llena su caja de 12 unidades, pero su masa no está en
   el medio. Su centroide cae en 4,33 de 12, o sea 1,67 a la izquierda del
   centro geométrico. Al ojo no le importa la caja, le importa el peso. Un
   pelín a la derecha (left) y ya se ve en su sitio.

   Va en `left` y no en transform: transform lo necesita entera la animación. */
.more__ring svg {
  width: 10px;
  color: var(--on-dark);
  position: relative;
  left: 1px;
}

/* LA FLECHA QUE SE VA Y VUELVE. El gesto satisfactorio: al pasar el ratón, la
   flecha sale disparada por el borde derecho del octógono y entra otra nueva
   por la izquierda, ya lista para el siguiente. Es un solo elemento haciendo
   el papel de dos — el salto al otro lado ocurre fuera de plano, y por eso no
   se ve el truco.

   DOS COSAS QUE LA HACÍAN PASTOSA, y las dos por el mismo malentendido:

   1. La curva iba en el atajo (`600ms var(--ease)`), y una
      animation-timing-function se aplica A CADA TRAMO, no a la animación
      entera. Como --ease es un ease-OUT, la SALIDA también frenaba: la
      flecha decelaraba justo cuando tenía que estar saliendo disparada.
      Ahora cada tramo lleva su curva: acelera al irse, frena al volver.
      Eso es lo que hace un movimiento continuo y no dos trompicones.

   2. Se desvanecía con opacity durante todo el viaje, así que iba medio
      translúcida de ida y de vuelta. Sobraba: el octógono YA la recorta
      (clip-path + overflow), y un corte limpio en el borde se lee mucho
      mejor que un fantasma. Al quitar el fundido hay que alejarla más
      —24 px y −26 px— para que salga del recorte de verdad: con los 18 px
      de antes asomaba un pico, que el fundido tapaba. */
.more:hover .more__ring svg,
.more:focus-visible .more__ring svg {
  animation: more-arrow 600ms both;
}
/* El color de la flecha NO puede ir dentro de la animación: los keyframes
   ganan a cualquier regla mientras corren, así que la inversión a tinta
   oscura se quedaría fuera durante los 600 ms. Por eso se anima solo el
   transform y el color se deja a la transición. */
.more__ring svg { transition: color 220ms var(--ease); }
@keyframes more-arrow {
  /* Se va acelerando */
  0%   { transform: translateX(0); animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.35); }
  46%  { transform: translateX(24px); }
  /* El cambio de lado: un fotograma, y fuera del octógono */
  47%  { transform: translateX(-26px); animation-timing-function: cubic-bezier(0.16, 0.9, 0.3, 1); }
  /* Vuelve frenando hasta clavarse en el centro */
  100% { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
  .more,
  .more__ring,
  .more__label { transition: none; }
  .more:hover .more__ring svg,
  .more:focus-visible .more__ring svg { animation: none; }
  .more:hover .more__label,
  .more:focus-visible .more__label { transform: none; }
  /* El COLOR sí se mantiene: no es decoración, es lo que hace legible la
     flecha sobre el anillo encendido. */
}

/* ==========================================================================
   FOOTER — verde col profundo, enlaces enormes y la marca a sangre
   ========================================================================== */
/* El footer NO recorta: si lo hiciera se comería los octógonos que asoman
   por su borde. El recorte vive en .footer__markwrap, que es el único que
   lo necesita (la marca a sangre). */
.footer {
  position: relative;
  background: var(--dark);
  color: var(--on-dark);
  padding: var(--s10) var(--margin) 0;
}

/* Los octógonos de colores clavados en el borde superior del footer: el
   remate de la referencia. Cada uno sube media altura, así que la mitad
   queda sobre la sección anterior y la mitad sobre el verde. */
.footer__studs {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 0;
  display: flex;
  align-items: flex-start; /* si no, el alto 0 del padre los aplasta */
  justify-content: center;
  gap: clamp(40px, 12vw, 180px);
  pointer-events: none;
}
.footer__stud {
  width: clamp(64px, 8vw, 104px);
  aspect-ratio: 1;
  flex: none;
  clip-path: var(--oct);
  transform: translateY(-50%);
}
.footer__stud:nth-child(1) { background: var(--g4); }
.footer__stud:nth-child(2) { background: var(--g5); }
.footer__stud:nth-child(3) { background: var(--g1); }
.footer__stud:nth-child(4) { background: var(--g2); }
.footer__stud:nth-child(5) { background: var(--g3); }

@media (max-width: 720px) {
  .footer__stud:nth-child(n+4) { display: none; }
}

.footer__grid {
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr minmax(280px, 440px);
  gap: var(--s8);
}

.footer__nav a {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 3.2rem);
  line-height: 1.18;
  letter-spacing: -0.02em;
  transition: opacity var(--t-micro) var(--ease);
}
.footer__nav a:hover { opacity: 0.6; }

.footer__talk p {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.35rem;
  line-height: 1.3;
  margin-bottom: var(--s5);
  max-width: 18em;
}

.footer__talk a.link {
  display: inline-block;
  color: var(--on-dark);
  border-bottom: 1px solid rgba(242, 238, 224, 0.4);
  transition: border-color var(--t-micro) var(--ease);
}
.footer__talk a.link:hover { border-color: var(--on-dark); }

.footer__talk dl { display: grid; gap: var(--s4); }
.footer__talk dt { color: var(--on-dark-muted); margin-bottom: 2px; }

.footer__legal {
  max-width: var(--max);
  margin: var(--s9) auto 0;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s4);
  color: var(--on-dark-muted);
}

/* La marca cierra la página: enorme, a sangre, recortada por abajo. El
   recorte es de este envoltorio, no del footer (ver arriba).
   El tamaño se mide en cqw —del propio envoltorio, no del viewport— para
   que "Cabbage" quepa siempre entero de lado a lado: con vw, en pantallas
   donde el margen del footer pesa más (o el ancho de letra del woff cargado
   difiere), el nowrap se pasaba del envoltorio y el overflow:hidden se
   comía un pellizco de cada extremo —la "C" inicial y, más visible, la
   "e" final—. Al ser relativo al propio contenedor, el ancho disponible
   ya lo conoce el propio cálculo del tamaño: nunca se pasa. */
.footer__markwrap { overflow: hidden; container-type: inline-size; position: relative; }

.footer__mark {
  display: block;
  text-align: center;
  margin-top: var(--s6);
  font-size: min(19cqw, 22rem);
  line-height: 0.9;
  transform: translateY(10%);
}

@media (max-width: 860px) {
  .footer__grid { grid-template-columns: 1fr; }
}
