/* ===========================================================
   CROWBY — página de marca
   Laboratorio de inteligencia artificial. Modelos propios.

   Sistema tomado de las páginas de producto de OpenAI (dots)
   y de x.ai: una sola superficie negra continua, sin bandas
   alternadas, tipografía enorme en peso 500 (nunca 700),
   interletrado negativo, y un ritmo de aire metronómico:
   el mismo valor de padding en todas las secciones.
   Un solo acento de color.

   Orden:
     01 cimientos
     02 tipografía
     03 piezas
     04 barra
     05 portada
     06 secciones
     07 pilares
     08 modelo
     09 ruta
     11 misión
     12 cierre
     13 pie
     14 movimiento
     15 pantallas chicas
   =========================================================== */


/* ---------- 01 cimientos ---------- */

:root {
  /* superficie */
  --negro:        #000000;
  /* el panel tiene que notarse apenas: a 2% de diferencia no se ve nada */
  --panel:        #0e0f13;
  --panel-alto:   #16181f;

  /* tinta */
  --blanco:       #ffffff;
  --humo:         rgba(255, 255, 255, .64);
  --niebla:       rgba(255, 255, 255, .44);
  --ceniza:       rgba(255, 255, 255, .30);

  /* acento */
  --cobre:        #d97757;
  --cobre-claro:  #e8a98c;
  --cobre-hondo:  #c9643f;

  /* líneas */
  --linea:        rgba(255, 255, 255, .10);
  --linea-fuerte: rgba(255, 255, 255, .20);

  /* medidas */
  --ancho:        1200px;
  --prosa:        680px;
  --radio:        18px;
  --barra-alto:   64px;

  /* ritmo: un solo valor de aire para todas las secciones */
  --aire:         clamp(5rem, 9vw, 8rem);

  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
          Helvetica, Arial, sans-serif;
  --curva: cubic-bezier(0.22, 0.61, 0.36, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--barra-alto) + 24px);
  /* clip y no hidden: hidden en el body obliga overflow-y:auto, vuelve al
     body un contenedor con scroll propio y desarma la medición de la página */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--negro);
  color: var(--blanco);
  font-family: var(--sans);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg { display: block; max-width: 100%; height: auto; }

a { color: inherit; text-decoration: none; }

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

:focus-visible {
  outline: 2px solid var(--cobre-claro);
  outline-offset: 3px;
  border-radius: 4px;
}

.salto {
  position: absolute;
  left: 16px; top: -100px;
  z-index: 200;
  padding: 10px 16px;
  background: var(--blanco);
  color: var(--negro);
  border-radius: 10px;
  font-size: .875rem;
  font-weight: 500;
  transition: top .2s var(--curva);
}
.salto:focus { top: 16px; }


/* ---------- 02 tipografía ---------- */

h1, h2, h3, h4, blockquote, p { margin: 0; }

/* peso 500 en todo el display, como en las páginas de OpenAI */
h1, h2, h3, h4 { font-weight: 500; }

h1 {
  font-size: clamp(2.75rem, 7.4vw, 5rem);   /* ≈ 80px arriba */
  line-height: 1.04;
  letter-spacing: -0.032em;
  text-wrap: balance;
}

h2 {
  font-size: clamp(2.125rem, 5.4vw, 4rem);  /* ≈ 64px arriba */
  line-height: 1.08;
  letter-spacing: -0.028em;
  text-wrap: balance;
}

h3 {
  font-size: clamp(1.125rem, 1.9vw, 1.5rem);
  line-height: 1.25;
  letter-spacing: -0.018em;
}

/* párrafo de entrada: grande y en peso 500, como el lead de dots */
.entrada {
  font-size: clamp(1.1875rem, 2.4vw, 1.75rem);
  font-weight: 500;
  line-height: 1.34;
  letter-spacing: -0.018em;
  color: var(--humo);
}

.menuda { font-size: .875rem; line-height: 1.55; color: var(--niebla); }

/* etiqueta de sección */
.guia {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--niebla);
}
.guia::before {
  content: '';
  width: 22px; height: 1px;
  background: var(--cobre);
  flex: none;
}

/* una sola palabra puede llevar el acento */
.brillo {
  color: var(--cobre);
  background: linear-gradient(96deg, #e8a98c 0%, #d97757 48%, #c9643f 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}

em { font-style: normal; color: var(--blanco); }


/* ---------- 03 piezas ---------- */

.caja {
  width: 100%;
  max-width: var(--ancho);
  margin: 0 auto;
  /* El <meta> lleva viewport-fit=cover, que manda la página por debajo de
     la muesca y de las esquinas redondeadas del iPhone. Sin esto, acostado
     el texto se metía bajo la muesca. env() va siempre con su 0px de
     respaldo: sin respaldo, el navegador que no lo entiende tira toda la
     declaración y la página se queda sin canal lateral. */
  padding-left: calc(clamp(20px, 5vw, 48px) + env(safe-area-inset-left, 0px));
  padding-right: calc(clamp(20px, 5vw, 48px) + env(safe-area-inset-right, 0px));
}

/* botón principal: blanco sólido sobre negro, como "Crea tu dot" */
.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 50px;
  padding: 0 26px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--blanco);
  color: var(--negro);
  font-family: inherit;
  font-size: .9375rem;
  font-weight: 500;
  letter-spacing: -0.008em;
  cursor: pointer;
  transition: transform .2s var(--curva), background-color .2s var(--curva),
              opacity .2s var(--curva);
}
.boton:hover { background: #ebe9e6; transform: translateY(-1px); }
.boton:active { transform: translateY(0); }

.boton-linea {
  background: transparent;
  color: var(--blanco);
  border-color: var(--linea-fuerte);
}
.boton-linea:hover {
  background: rgba(255, 255, 255, .06);
  border-color: rgba(255, 255, 255, .34);
}

.boton-cobre { background: var(--cobre); color: #fff; }
.boton-cobre:hover { background: var(--cobre-hondo); }

.botonera {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}


/* ---------- 04 barra ---------- */

.barra {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--barra-alto);
  display: flex;
  align-items: center;
  background: rgba(0, 0, 0, .72);
  -webkit-backdrop-filter: blur(14px);
          backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--curva), background-color .25s var(--curva);
}
.barra[data-pegada='si'] {
  border-bottom-color: var(--linea);
  background: rgba(0, 0, 0, .86);
}

.barra .caja {
  display: flex;
  align-items: center;
  gap: 28px;
}

.marca { display: flex; align-items: center; flex: none; }
.marca img { height: 24px; width: auto; }

.menu {
  display: flex;
  align-items: center;
  gap: 26px;
  margin-left: auto;
  font-size: .875rem;
  font-weight: 450;
  color: var(--humo);
}
/* un enlace del menú no se parte nunca en dos líneas. Sin esto el renglón
   se rompía por dentro y la barra quedaba con enlaces de dos pisos: medido,
   «Qué es CROWBY» pasaba de 22px de alto a 45px y nadie lo había visto */
.menu a { white-space: nowrap; transition: color .18s var(--curva); }
.menu a:hover { color: var(--blanco); }

/* ---------- el desplegable de herramientas ----------

   Las otras cuatro cosas de la barra son secciones para LEER. Esta es la
   única que se puede USAR, y además no es una sino varias. Por eso abre la
   lista aquí mismo: mandar primero a una página índice para que ahí se
   escoja es un clic cobrado de más.
   De paso resuelve un problema de ancho: la palabra «gratis» ya no tiene
   que caber en la barra, porque ahora vive dentro de la lista, donde cada
   herramienta puede decir si es gratis por su cuenta. */

.menu-utiles { position: relative; display: flex; align-items: center; }

.menu-disparo {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  color: var(--blanco);
  background: none;
  border: 0;
  white-space: nowrap;
  cursor: pointer;
}

/* la puntita: dos bordes girados. Sin imagen y sin fuente de iconos */
.menu-punta {
  width: 6px; height: 6px;
  margin-top: -3px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  opacity: .62;
  transform: rotate(45deg);
  transition: transform .22s var(--curva), opacity .22s var(--curva);
}

.menu-lista {
  position: absolute;
  top: calc(100% + 15px);
  right: -14px;
  width: 320px;
  padding: 9px;
  display: grid;
  gap: 1px;
  text-align: left;
  background: var(--panel-alto);
  border: 1px solid var(--linea);
  border-radius: 15px;
  box-shadow: 0 26px 54px rgba(0, 0, 0, .6);
  /* cerrado de verdad: visibility y pointer-events, no solo opacidad. Un
     panel transparente pero todavía clicable le roba los clics a lo que
     tiene debajo, y eso no se ve nunca mirando la pantalla */
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(-7px);
  transition: opacity .2s var(--curva), transform .2s var(--curva),
              visibility .2s var(--curva);
}

/* puente invisible sobre los 15px de aire entre el botón y la lista: sin
   esto, al bajar el mouse se pasa por un hueco donde no hay nada que
   apuntar, el :hover se corta y la lista se cierra en la cara */
.menu-lista::before {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: -15px; height: 15px;
}

.menu-utiles[data-abierto='si'] .menu-lista {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
}
.menu-utiles[data-abierto='si'] .menu-punta {
  transform: rotate(-135deg);
  margin-top: 3px;
  opacity: 1;
}

/* con mouse se abre al pasar por encima — un clic para ver una lista es un
   clic de sobra. Con dedo no existe el "pasar por encima", así que ahí
   manda el data-abierto que pone el JS */
@media (hover: hover) and (pointer: fine) {
  .menu-utiles:hover .menu-lista,
  .menu-utiles:focus-within .menu-lista {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
  }
  .menu-utiles:hover .menu-punta,
  .menu-utiles:focus-within .menu-punta { transform: rotate(-135deg); margin-top: 3px; opacity: 1; }
}

/* --- las filas de la lista --- */

.menu-lista a,
.menu-pronto {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  align-items: start;
  gap: 11px;
  padding: 10px 11px;
  border-radius: 10px;
  font-size: .8125rem;
  line-height: 1.38;
  white-space: normal;    /* aquí sí puede haber dos renglones: hay ancho */
}
.menu-lista a { color: var(--blanco); }
.menu-lista a:hover { background: rgba(255, 255, 255, .055); }

/* la que estás viendo no se puede pulsar para ir a donde ya estás: se
   marca y se deja quieta */
.menu-lista a[aria-current='page'] {
  background: rgba(217, 119, 87, .10);
  cursor: default;
}

.util-cuerpo { display: grid; gap: 3px; min-width: 0; }

/* el icono: trazo de currentColor, así que hereda el color de la fila y no
   hay que repintarlo en cada estado */
.util-icono {
  width: 20px; height: 20px;
  margin-top: 1px;
  color: var(--cobre-claro);
  opacity: .85;
  transition: opacity .18s var(--curva), transform .18s var(--curva);
}
.menu-lista a:hover .util-icono { opacity: 1; transform: scale(1.06); }
.menu-pronto .util-icono { color: currentColor; opacity: .5; }

.menu-fila { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.menu-fila strong { font-weight: 500; }

.menu-sello {
  flex: none;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--cobre-claro);
  border: 1px solid rgba(217, 119, 87, .42);
  background: rgba(217, 119, 87, .10);
}

.menu-pie { color: var(--humo); font-size: .75rem; }

.menu-rotulo {
  margin: 9px 11px 3px;
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, var(--ceniza));
}

/* las que no existen todavía van en <span>, no en <a>: si no se puede
   pulsar, no se pinta como algo que se pulsa */
.menu-pronto {
  display: block;
  color: rgba(255, 255, 255, var(--niebla));
  cursor: default;
}

.menu-lista a.menu-todas {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 7px;
  padding-top: 13px;
  border-top: 1px solid var(--linea);
  border-radius: 0 0 9px 9px;
  color: var(--cobre-claro);
}
.menu-lista a.menu-todas::after {
  content: '→';
  transition: transform .2s var(--curva);
}
.menu-lista a.menu-todas:hover { background: rgba(217, 119, 87, .09); }
.menu-lista a.menu-todas:hover::after { transform: translateX(3px); }


/* --- la misma lista dentro del cajón del celular ---
   Aquí no se despliega nada: en el cajón hay sitio de sobra y esconder
   cuatro renglones detrás de otro toque no ahorra nada, solo lo estorba */

.cajon-utiles { margin-bottom: 18px; }
.cajon-rotulo {
  margin: 0 0 4px;
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, var(--ceniza));
}
.cajon-utiles a,
.cajon-utiles span.cajon-pronto {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 0;
  border-bottom: 1px solid var(--linea);
  font-size: .9375rem;
  font-weight: 450;
}
.cajon-utiles a { color: var(--blanco); }
.cajon-utiles span.cajon-pronto { color: rgba(255, 255, 255, var(--niebla)); }
/* el nombre se queda con todo el ancho que sobre y empuja el sello al
   borde derecho, que es donde se lee de un barrido */
.cajon-utiles .util-cuerpo { flex: 1; display: block; }
.cajon-utiles a.menu-todas {
  gap: 7px;
  color: var(--cobre-claro);
  border-bottom: 0;
}
.cajon-utiles a.menu-todas::after { content: '→'; }

.barra .boton { min-height: 38px; padding: 0 18px; font-size: .875rem; }

/* botón hamburguesa */
.hamburguesa {
  display: none;
  margin-left: auto;
  width: 40px; height: 40px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--linea);
  border-radius: 10px;
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.hamburguesa span {
  display: block;
  position: relative;
  width: 16px; height: 1.5px;
  background: var(--blanco);
  border-radius: 2px;
  transition: transform .22s var(--curva), opacity .18s var(--curva);
}
.hamburguesa span::before,
.hamburguesa span::after {
  content: '';
  position: absolute;
  left: 0;
  width: 16px; height: 1.5px;
  background: var(--blanco);
  border-radius: 2px;
  transition: transform .22s var(--curva);
}
.hamburguesa span::before { top: -5px; }
.hamburguesa span::after  { top: 5px; }

.hamburguesa[aria-expanded='true'] span { transform: rotate(45deg); }
.hamburguesa[aria-expanded='true'] span::before { transform: translateY(5px) rotate(-90deg); }
.hamburguesa[aria-expanded='true'] span::after  { opacity: 0; transform: scaleX(0); }

/* cajón móvil */
.cajon {
  position: fixed;
  inset: var(--barra-alto) 0 auto 0;
  z-index: 99;
  display: none;
  padding-top: 20px;
  /* el canal lateral suma la zona segura: con viewport-fit=cover, en un
     iPhone acostado la muesca se come este borde */
  padding-left: calc(clamp(20px, 5vw, 48px) + env(safe-area-inset-left, 0px));
  padding-right: calc(clamp(20px, 5vw, 48px) + env(safe-area-inset-right, 0px));
  padding-bottom: calc(28px + env(safe-area-inset-bottom, 0px));
  background: var(--negro);
  border-bottom: 1px solid var(--linea);

  /* medido: acostado el cajón medía 403px de alto en una ventana de 390 y
     no tenía scroll, así que el botón de pedir acceso quedaba fuera y no
     había forma de llegarle. Ahora se encoge y rueda por dentro.
     dvh y no vh porque en el celular la barra del navegador aparece y
     desaparece, y vh se queda con la medida vieja */
  max-height: calc(100vh - var(--barra-alto));
  max-height: calc(100dvh - var(--barra-alto));
  overflow-y: auto;
  /* que el rebote del cajón no arrastre la página de atrás */
  overscroll-behavior: contain;
}
.cajon[data-abierto='si'] { display: block; }
.cajon nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 18px;
}
.cajon nav a {
  padding: 13px 0;
  border-bottom: 1px solid var(--linea);
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: -0.016em;
}
.cajon .boton { width: 100%; }


/* ---------- 05 portada ---------- */

.portada {
  position: relative;
  padding-top: clamp(4.5rem, 9vw, 7rem);
  padding-bottom: var(--aire);
  overflow: hidden;
  text-align: center;
}

/* auras: gradientes radiales, cero imágenes, cero peticiones */
.portada::before,
.portada::after {
  content: '';
  position: absolute;
  pointer-events: none;
  border-radius: 50%;
}
.portada::before {
  top: -460px; left: 50%;
  width: 1100px; height: 1100px;
  margin-left: -550px;
  background: radial-gradient(circle,
    rgba(217, 119, 87, .26) 0%,
    rgba(217, 119, 87, .07) 44%,
    rgba(217, 119, 87, 0) 68%);
}
.portada::after {
  bottom: -340px; right: -220px;
  width: 760px; height: 760px;
  background: radial-gradient(circle,
    rgba(232, 169, 140, .11) 0%,
    rgba(232, 169, 140, 0) 66%);
}
.portada .caja { position: relative; z-index: 1; }

/* la portada ya no lleva etiqueta encima del título: el cuervo se apoya
   directo sobre el h1. Las reglas que vestían esa etiqueta salieron de aquí
   porque quedaron sin dueño — es la única .portada de la página */

.portada h1 { max-width: 15ch; margin-inline: auto; }

.portada .entrada {
  max-width: 50ch;
  margin: 26px auto 0;
}

.portada .botonera {
  justify-content: center;
  margin-top: 38px;
}

.portada .menuda {
  margin-top: 20px;
  color: var(--ceniza);
}


/* ---------- 05b el retrato de Crowby-1 ---------- */

/* el aire de arriba estaba calculado para que la portada abriera con
   texto. Ahora abre con una cara, que ya trae su propio aire, así que
   se recorta: si no, el botón de pedir acceso se cae de la pantalla en
   un portátil. Va con :has() para que el valor viejo siga siendo el
   que vale si algún día no hay retrato */
.portada:has(.retrato) { padding-top: clamp(2.75rem, 5vw, 4.25rem); }

/* El título dice "te presentamos a Crowby-1". Presentar a alguien obliga
   a mostrarlo, así que el retrato abre la portada: se ve la cara, después
   se lee el nombre. Nada del texto de la portada se movió.

   Van tres capas anidadas porque tres cosas distintas quieren mover lo
   mismo, y transform es una sola propiedad que no se puede repartir:
     .retrato        la entrada de .sube
     .retrato-flota  el vaivén que nunca para
     .retrato-img    la mirada que sigue al puntero y el respingo del botón */
.retrato {
  /* cuánto dura el viaje. Está aquí arriba porque las capas de abajo y el
     vaivén de después lo leen de aquí: así el aterrizaje y el momento en
     que el cuervo empieza a respirar no se pueden desincronizar */
  --vuelo: 1.45s;
  --vuelo-espera: .12s;

  /* el 34vh no es capricho: en un portátil bajito el retrato empuja el
     botón fuera de la pantalla, así que en pantallas cortas se achica
     solo. Nunca baja de 150px porque por debajo de ahí el cuervo deja
     de leerse como cuervo */
  --retrato-ancho: clamp(150px, min(23vw, 34vh), 300px);

  position: relative;
  z-index: 1;
  width: var(--retrato-ancho);
  margin-inline: auto;
  /* el archivo trae ~20% de aire transparente por los cuatro lados.
     Esos márgenes negativos recortan píxeles vacíos, no aire de diseño:
     dejan al cuervo a la distancia que el texto de verdad se ve, no a
     la que mide el png */
  margin-top: calc(var(--retrato-ancho) * -0.14);
  margin-bottom: calc(var(--retrato-ancho) * -0.12);
  isolation: isolate;
}

/* la luz detrás del cuervo. No es decoración: el personaje es casi negro
   sobre fondo negro, así que sin un campo encendido atrás la silueta se
   perdería. El violeta es el mismo que el ilustrador le puso a las plumas,
   medido del propio dibujo, para que bicho y página compartan paleta */
.retrato-aura {
  position: absolute;
  inset: -28%;
  z-index: -1;
  border-radius: 50%;
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 46%,
      rgba(217, 119, 87, .42) 0%,
      rgba(217, 119, 87, .12) 40%,
      rgba(217, 119, 87, 0) 64%),
    radial-gradient(circle at 63% 34%,
      rgba(129, 112, 210, .24) 0%,
      rgba(129, 112, 210, 0) 52%);
}

/* Las tres capas del vuelo arrancan SIN transform a propósito. El estado
   base es el cuervo ya posado, no el cuervo en el aire: si el script no
   vive, si el navegador no anima o si el visitante pidió quietud, no hay
   nada que esperar y el bicho simplemente está en su sitio. El vuelo se
   añade encima, y es un regalo, nunca un requisito para verlo. */
.retrato-planeo,
.retrato-caida,
.retrato-flota { display: block; }

/* la picada y el frenazo giran alrededor del cuerpo, no del centro de la
   caja: así el cuervo cabecea como un ave y no como una rueda */
.retrato-caida { transform-origin: 50% 72%; }

.retrato-img {
  width: 100%;
  /* el borde de cobre de 1px es un contraluz: despega el negro del cuervo
     del negro del fondo sin tener que aclararle el cuerpo */
  /* medido: el cuerpo del cuervo es rgb(24,22,27). Contra el negro de la
     página eso da 1,17:1, o sea invisible, y el resplandor de atrás solo
     lo sube a 1,28:1. Lo que de verdad dibuja la silueta es este
     contraluz de cobre, que contra el cuerpo da 9:1. Van dos pasadas de
     1px porque una sola se pierde a este tamaño. */
  filter: drop-shadow(0 0 1px rgba(232, 169, 140, .62))
          drop-shadow(0 0 1px rgba(232, 169, 140, .62))
          drop-shadow(0 16px 28px rgba(217, 119, 87, .16));

  /* el dibujo no viene centrado dentro de su propio archivo: medido, la
     tinta queda 14,5 de 500px corrida a la izquierda. Se compensa aquí
     para que el cuervo caiga sobre el eje del título y no sobre el del png */
  --centrar: 2.9%;
  /* gira y crece desde el cuerpo, no desde el medio: así parece que
     voltea la cabeza y se levanta, en vez de rodar */
  transform-origin: 50% 72%;
  transform: translate(var(--centrar), 0)
             translate3d(var(--miraX, 0px), var(--miraY, 0px), 0)
             rotate(var(--miraG, 0deg))
             scale(var(--miraE, 1));
  transition: transform .5s var(--curva), filter .3s var(--curva);
  will-change: transform;
}

/* cuando el visitante va a pedir acceso, el cuervo se endereza y se
   enciende. Es la única reacción de la página que responde a una
   intención y no a un scroll */
.portada:has(.boton:hover) .retrato-img,
.portada:has(.boton:focus-visible) .retrato-img {
  --miraE: 1.045;
  filter: drop-shadow(0 0 1px rgba(232, 169, 140, .95))
          drop-shadow(0 0 1px rgba(232, 169, 140, .95))
          drop-shadow(0 16px 30px rgba(217, 119, 87, .3));
}


/* ---------- 06 secciones ---------- */

/* mismo aire arriba y abajo en todas: ritmo metronómico */
.seccion { padding-block: var(--aire); }

.seccion-panel {
  background: var(--panel);
  border-block: 1px solid var(--linea);
}

/* encabezado partido: el título a la izquierda y la entrada a la
   derecha, sentados sobre la misma línea de base. Así la sección usa
   todo el ancho en vez de dejar medio viewport vacío al lado de un
   título angosto, y cada sección abre con un filete que la anuncia. */
.encabezado-partido {
  display: grid;
  grid-template-columns: minmax(0, 1.06fr) minmax(0, .94fr);
  gap: clamp(20px, 5vw, 72px);
  align-items: end;
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--linea);
}
.encabezado-partido .guia {
  grid-column: 1 / -1;
  margin-bottom: clamp(1.5rem, 3.4vw, 2.75rem);
}
.encabezado-partido h2 { max-width: 19ch; }
.encabezado-partido .entrada {
  max-width: 40ch;
  padding-bottom: .35em;   /* alinea el bloque de texto con la base del título */
}


/* ---------- 07 pilares ---------- */

/* reja de tres columnas con filete arriba */
.pilares {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(28px, 4vw, 52px);
  margin-top: clamp(3rem, 6vw, 4.5rem);
}

.pilar {
  padding-top: 22px;
  border-top: 1px solid var(--linea-fuerte);
}
.pilar h3 { margin-bottom: 10px; }
.pilar p { color: var(--humo); font-size: .9375rem; line-height: 1.62; }

/* banda de remate: la frase que cierra una sección se lleva su propio
   aire y se centra, para que funcione como golpe y no como otro párrafo */
.remate-banda {
  margin-top: var(--aire);
  padding-top: clamp(2.5rem, 5vw, 4rem);
  border-top: 1px solid var(--linea);
  text-align: center;
}

.remate {
  font-size: clamp(1.625rem, 4.4vw, 3.25rem);
  font-weight: 500;
  line-height: 1.13;
  letter-spacing: -0.032em;
  max-width: 26ch;
  margin-inline: auto;
  color: var(--humo);
}
.remate em { color: var(--blanco); }


/* ---------- 08 modelo ---------- */

.modelo-malla {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1px, .2vw, 1px);
  margin-top: clamp(3rem, 6vw, 4.5rem);
  background: var(--linea);
  border: 1px solid var(--linea);
  border-radius: var(--radio);
  overflow: hidden;
}

.tarjeta {
  position: relative;
  background: var(--negro);
  padding: clamp(28px, 3.4vw, 46px);
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: background-color .3s var(--curva);
}
.tarjeta:hover { background: var(--panel-alto); }

.seccion-panel .tarjeta { background: var(--panel); }
.seccion-panel .tarjeta:hover { background: var(--panel-alto); }

/* luz de cobre en el borde de arriba al pasar el mouse. No se puede
   levantar la tarjeta: el enrejado son costuras de 1px y moverla
   rompería la línea */
.tarjeta::after {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%, rgba(217, 119, 87, .8) 50%, transparent 100%);
  opacity: 0;
  transition: opacity .3s var(--curva);
  pointer-events: none;
}
.tarjeta:hover::after { opacity: 1; }

/* el índice se separa del título con un filete corto */
.tarjeta-indice {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .14em;
  color: var(--cobre);
  font-variant-numeric: tabular-nums;
}
.tarjeta-indice::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--linea);
}
.tarjeta p { color: var(--humo); font-size: 1rem; line-height: 1.62; }


/* ---------- 08b lista de ideas (encabezado pegado) ---------- */

/* dos columnas: el encabezado se queda quieto a la izquierda mientras
   las ideas pasan a la derecha. Rompe la repetición de rejas de tres */
.lista-ideas {
  display: grid;
  grid-template-columns: minmax(0, .84fr) minmax(0, 1.16fr);
  gap: clamp(28px, 6vw, 84px);
}

.lista-ideas-cabeza {
  position: sticky;
  top: calc(var(--barra-alto) + clamp(2rem, 5vw, 4rem));
  align-self: start;
}
.lista-ideas-cabeza .guia { margin-bottom: 22px; }
.lista-ideas-cabeza h2 { max-width: 15ch; }
.lista-ideas-cabeza .entrada { max-width: 34ch; margin-top: 22px; }

.idea {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 22px;
  padding-block: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--linea);
}
.idea:last-child { border-bottom: 1px solid var(--linea); }

.idea-num {
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .14em;
  color: var(--cobre);
  padding-top: .5em;
  font-variant-numeric: tabular-nums;
}
.idea h3 { margin-bottom: 9px; }
.idea p { color: var(--humo); font-size: .9375rem; line-height: 1.62; }


/* ---------- 09 ruta (lo que viene) ---------- */

.ruta {
  margin-top: clamp(3rem, 6vw, 4.5rem);
  border-top: 1px solid var(--linea);
}

.ruta-fila {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr) auto;
  gap: clamp(20px, 3vw, 44px);
  align-items: baseline;
  padding-block: clamp(1.5rem, 3vw, 2.25rem);
  border-bottom: 1px solid var(--linea);
}

.ruta-nombre {
  font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.024em;
  transition: color .25s var(--curva);
}
/* se marca el nombre al pasar por la fila, sin tocar el fondo:
   un fondo tendría que sangrar fuera de la caja para verse bien */
.ruta-fila:hover .ruta-nombre { color: var(--cobre-claro); }

.ruta-que { color: var(--humo); font-size: 1rem; line-height: 1.6; }

/* sello de estado: texto, no semáforo de colores */
.ruta-estado {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: none;
  padding: 5px 13px;
  border: 1px solid var(--linea-fuerte);
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--niebla);
  white-space: nowrap;
}
.ruta-estado::before {
  content: '';
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
/* el que ya está corriendo se marca con el acento */
.ruta-estado[data-vivo='si'] {
  color: var(--cobre-claro);
  border-color: rgba(217, 119, 87, .42);
  background: rgba(217, 119, 87, .09);
}

.ruta-nota {
  margin-top: clamp(2rem, 4vw, 3rem);
  max-width: 54ch;
  font-size: .9375rem;
  line-height: 1.62;
  color: var(--ceniza);
}


/* ---------- 11 misión ---------- */

.mision { text-align: center; }
.mision .guia { margin-bottom: 28px; }

/* la misión es el clímax: es el h2 más grande de la página */
.mision h2 {
  font-size: clamp(2.375rem, 6.6vw, 4.75rem);
  line-height: 1.05;
  letter-spacing: -0.034em;
  max-width: 21ch;
  margin-inline: auto;
}

.mision .entrada {
  max-width: 44ch;
  margin: 28px auto 0;
}

.apuesta-remate {
  margin-top: clamp(3.5rem, 7vw, 5.5rem);
  padding-top: clamp(3rem, 5vw, 4rem);
  border-top: 1px solid var(--linea);
}

.apuesta-remate blockquote {
  font-size: clamp(1.625rem, 4.2vw, 3rem);
  font-weight: 500;
  line-height: 1.14;
  letter-spacing: -0.03em;
  max-width: 26ch;
  margin-inline: auto;
  color: var(--humo);
}
.apuesta-remate blockquote em { color: var(--blanco); }

.apuesta-remate .menuda {
  max-width: 52ch;
  margin: 26px auto 0;
  color: var(--ceniza);
}

.firma-eslogan {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  font-weight: 500;
  letter-spacing: .02em;
}


/* ---------- 12 cierre ---------- */

.cierre {
  position: relative;
  text-align: center;
  overflow: hidden;
  border-top: 1px solid var(--linea);
}
.cierre::before {
  content: '';
  position: absolute;
  bottom: -420px; left: 50%;
  width: 1000px; height: 1000px;
  margin-left: -500px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle,
    rgba(217, 119, 87, .20) 0%,
    rgba(217, 119, 87, 0) 66%);
}
.cierre .caja { position: relative; z-index: 1; }

.cierre h2 { max-width: 18ch; margin-inline: auto; }
.cierre .entrada { max-width: 44ch; margin: 24px auto 0; }
.cierre .botonera { justify-content: center; margin-top: 36px; }
.cierre .menuda { margin-top: 18px; color: var(--ceniza); }


/* ---------- 13 pie ---------- */

.pie {
  /* el aire de abajo suma la franja del indicador de inicio del iPhone,
     que si no se le monta encima a la última línea */
  padding-block: clamp(3.5rem, 6vw, 5rem)
                 calc(2rem + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--linea);
  background: var(--panel);
}

.pie-alto {
  display: grid;
  /* la marca y TRES columnas de enlaces. Eran dos hasta que entraron las
     herramientas: con tres hijos en una rejilla de tres, el cuarto se
     caía a una fila sola y se veía como un error */
  grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
  gap: clamp(32px, 5vw, 64px);
  padding-bottom: clamp(2.5rem, 4vw, 3.5rem);
  border-bottom: 1px solid var(--linea);
}

.pie-marca img { height: 26px; width: auto; }
.pie-marca p {
  margin-top: 18px;
  max-width: 34ch;
  font-size: .9375rem;
  line-height: 1.6;
  color: var(--humo);
}

.pie-col h4 {
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ceniza);
  margin-bottom: 16px;
}
.pie-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.pie-col a {
  font-size: .9375rem;
  color: var(--humo);
  transition: color .18s var(--curva);
}
.pie-col a:hover { color: var(--blanco); }

.pie-bajo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding-top: 24px;
  font-size: .8125rem;
  color: var(--ceniza);
}
.pie-bajo p { color: inherit; }
.pie-eslogan { letter-spacing: .04em; }


/* ---------- 14 movimiento ---------- */

/* las posiciones de arranque solo existen si el script está vivo */
.js .sube {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .7s var(--curva), transform .7s var(--curva);
}
.js .sube[data-visto='si'] {
  opacity: 1;
  transform: none;
}

/* --- texto que entra palabra por palabra ---
   el display grande no aparece de golpe: cada palabra sube, se enfoca
   y aclara con un desfase corto. Es el gesto de ChatGPT escribiendo.
   Las palabras solo existen si el script las creó, así que sin js
   el texto se lee plano y completo. */
.js .palabra {
  display: inline-block;
  opacity: 0;
  transform: translateY(.4em);
  filter: blur(5px);
  transition: opacity .58s var(--curva),
              transform .58s var(--curva),
              filter .58s var(--curva);
}
.js [data-visto='si'] .palabra {
  opacity: 1;
  transform: none;
  filter: blur(0);
}

/* los trozos con degradado o con énfasis viajan enteros: partirlos
   reiniciaría el degradado en cada palabra. Y van en display:inline
   porque un inline-block de varias palabras no puede cortar de línea
   y se saldría de la pantalla en móvil */
.js .palabra-suelta {
  display: inline;
  transform: none;
  filter: blur(4px);
  transition: opacity .58s var(--curva), filter .58s var(--curva);
}
.js [data-visto='si'] .palabra-suelta { filter: blur(0); }

/* el elemento que anima sus palabras no se desvanece él mismo,
   si no la animación iría doble */
.js .sube.con-palabras,
.js .sube.con-palabras[data-visto='si'] {
  opacity: 1;
  transform: none;
}

/* --- trazos que se dibujan --- */

/* el filete que abre cada sección se traza de izquierda a derecha */
.encabezado-partido,
.remate-banda { position: relative; border-top-color: transparent; }

.encabezado-partido::before,
.remate-banda::before {
  content: '';
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  background: var(--linea);
}
.js .encabezado-partido::before,
.js .remate-banda::before {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.15s var(--curva);
}
.js .encabezado-partido[data-visto='si']::before,
.js .remate-banda[data-visto='si']::before { transform: scaleX(1); }

/* lo mismo en los pilares y en las ideas: la línea llega con el bloque */
.pilar, .idea { position: relative; border-top-color: transparent; }

.pilar::before,
.idea::before {
  content: '';
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  background: var(--linea-fuerte);
}
.idea::before { background: var(--linea); }

.js .pilar::before,
.js .idea::before {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .95s var(--curva);
}
.js .pilar[data-visto='si']::before,
.js .idea[data-visto='si']::before { transform: scaleX(1); }

/* la raya de la etiqueta de sección crece desde cero */
.js .guia::before {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .7s var(--curva) .12s;
}
.js .guia[data-visto='si']::before { transform: scaleX(1); }

/* --- rastro de lectura en la barra --- */
.barra-progreso {
  position: absolute;
  bottom: -1px; left: 0;
  width: 100%; height: 2px;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--cobre-hondo), var(--cobre-claro));
  opacity: 0;
  transition: opacity .35s var(--curva);
  pointer-events: none;
}
.barra[data-pegada='si'] .barra-progreso { opacity: 1; }

/* --- las auras respiran --- */
@keyframes respirar {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(1.07); opacity: .76; }
}
.portada::before { animation: respirar 23s ease-in-out infinite; }
.portada::after  { animation: respirar 29s ease-in-out infinite reverse; }
.cierre::before  { animation: respirar 26s ease-in-out infinite; }
.retrato-aura    { animation: respirar 17s ease-in-out infinite; }

/* --- el cuervo llega volando --- */

/* El dibujo es un png de una pieza: no hay alas aparte, así que no se
   puede animar un aleteo. El vuelo se cuenta entero con la trayectoria,
   el cabeceo y el estirón, que es justo como un animador le saca peso a
   un muñeco rígido.

   Y entra por la izquierda porque medí que la cabeza mira a la derecha:
   un bicho vuela hacia donde mira. Entrando por la derecha estaría
   volando de espaldas.

   El recorrido es el de un ave de presa posándose, en este orden:
   planeo largo y rasante, picada con la cabeza abajo, FRENAZO (echa el
   cuerpo atrás, se infla y pierde toda la velocidad de golpe — este es
   el gesto que lo hace leer como águila y no como un div deslizándose),
   se deja caer en el sitio, y se acomoda con dos sacudidas que se
   apagan. */

/* el eje horizontal va aparte del vertical a propósito: dos rectas con
   curvas de tiempo distintas dan una trayectoria curva. Con una sola
   animación el navegador interpola en línea recta y el vuelo se ve como
   un arrastre */
@keyframes planeo {
  0% {
    transform: translateX(-95%);
    opacity: 0;
    /* rasante y rápido: casi no frena en el primer tramo */
    animation-timing-function: cubic-bezier(.11, .61, .39, .93);
  }
  /* aparece temprano, ya en movimiento: nunca se ve quieto y transparente */
  14%  { opacity: 1; }
  58%  { transform: translateX(-27%);
         animation-timing-function: cubic-bezier(.2, .7, .18, 1); }
  /* aquí ya frenó: lo que queda es acomodarse */
  77%  { transform: translateX(-2.5%);
         animation-timing-function: ease-out; }
  89%  { transform: translateX(1.6%); }
  100% { transform: translateX(0); }
}

@keyframes aterrizaje {
  /* lejos, alto y picado. La cabeza está a la derecha, así que girar en
     positivo es bajar la cabeza: va en picada.
     El estirón horizontal (x mayor que y) es la vieja ley del dibujo
     animado: lo que va rápido se alarga en el sentido de la marcha */
  0% {
    transform: perspective(900px) translateY(-30%)
               rotateY(-16deg) rotateZ(11deg) scale(.66, .61);
    animation-timing-function: cubic-bezier(.3, .28, .6, .8);
  }
  52% {
    transform: perspective(900px) translateY(-14%)
               rotateY(-9deg) rotateZ(8deg) scale(.86, .83);
    animation-timing-function: cubic-bezier(.25, .6, .3, 1);
  }
  /* último tramo de la picada, ya encima del sitio */
  68% {
    transform: perspective(900px) translateY(-2%)
               rotateY(-3deg) rotateZ(4deg) scale(.98, .96);
    animation-timing-function: cubic-bezier(.36, 0, .5, 1);
  }
  /* EL FRENAZO. Echa el cuerpo atrás (giro negativo), se infla hacia
     arriba y rebota un poco para arriba perdiendo la velocidad */
  78% {
    transform: perspective(900px) translateY(-11%)
               rotateY(0deg) rotateZ(-9deg) scale(1.02, 1.08);
    animation-timing-function: cubic-bezier(.45, 0, .55, 1);
  }
  /* el golpe: se deja caer y se achata contra el sitio */
  90% {
    transform: translateY(3%) rotateZ(2.5deg) scale(1.06, .95);
    animation-timing-function: ease-in-out;
  }
  96%  { transform: translateY(-1.3%) rotateZ(-1deg) scale(.99, 1.01); }
  100% { transform: translateY(0) rotateZ(0deg) scale(1, 1); }
}

/* la luz de atrás no está antes que el cuervo: se prende con el golpe */
@keyframes brote {
  0%   { opacity: 0; transform: scale(.5); }
  60%  { opacity: .22; transform: scale(.78);
         animation-timing-function: cubic-bezier(.3, 0, .4, 1); }
  /* el fogonazo del aterrizaje */
  90%  { opacity: 1; transform: scale(1.16); }
  100% { opacity: 1; transform: scale(1); }
}

/* el vuelo solo arranca cuando el script avisa que la portada está a la
   vista, igual que todo lo demás que entra en esta página */
.js .retrato[data-visto='si'] .retrato-planeo {
  animation: planeo var(--vuelo) var(--vuelo-espera) both;
}
.js .retrato[data-visto='si'] .retrato-caida {
  animation: aterrizaje var(--vuelo) var(--vuelo-espera) both;
}
.js .retrato[data-visto='si'] .retrato-aura {
  /* las dos en la misma lista: brote manda mientras dura el vuelo y
     respirar entra justo cuando aquella acaba, las dos en scale(1) y
     opacidad 1, así que el relevo no se nota */
  animation:
    brote var(--vuelo) var(--vuelo-espera) both,
    respirar 17s ease-in-out calc(var(--vuelo) + var(--vuelo-espera)) infinite;
}

/* el retrato no se desvanece él mismo: su entrada es el vuelo.
   Mismo arreglo que .sube.con-palabras, que tampoco se desvanece porque
   sus palabras ya entran una por una */
.js .retrato.sube,
.js .retrato.sube[data-visto='si'] {
  opacity: 1;
  transform: none;
}

/* --- el cuervo flota --- */
/* lento y de poco recorrido: tiene que leerse como que está vivo, no
   como que se está columpiando. Empieza cuando el vuelo termina: estar
   posado y respirando es lo que viene después de aterrizar */
@keyframes flotar {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -9px, 0); }
}
.retrato-flota {
  animation: flotar 6.5s ease-in-out
             calc(var(--vuelo) + var(--vuelo-espera)) infinite;
}


@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .sube,
  .js .sube[data-visto='si'],
  .js .palabra,
  .js [data-visto='si'] .palabra,
  .js .palabra-suelta {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }
  /* los trazos se quedan puestos, sin dibujarse */
  .js .encabezado-partido::before,
  .js .remate-banda::before,
  .js .pilar::before,
  .js .idea::before,
  .js .guia::before {
    transform: scaleX(1) !important;
    transition: none !important;
  }

  /* los gestos del celular aparecen ya hechos: el pilar levantado, la
     tarjeta encendida, el corchete abierto, la vía recorrida y la raya de
     la misión puesta. Está todo, pero nada se dibuja al pasar */
  .js .pilar::after,
  .js .idea::after,
  .js .idea .idea-num,
  .js .tarjeta::after,
  .js .tarjeta-indice::after,
  .js .ruta-nombre::before,
  .js .apuesta-remate::before,
  .js .apuesta-remate::after {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .js .ruta-fila::before {
    clip-path: none !important;
    transition: none !important;
  }
  /* el punto de la parada viva deja de latir: es movimiento sin
     información nueva, y aquí sobra */
  .ruta-fila:has(.ruta-estado[data-vivo='si']) .ruta-nombre::before {
    animation: none !important;
    box-shadow: none !important;
  }
  .barra-progreso { display: none; }
  .boton:hover, .boton:active { transform: none; }
  /* el cuervo se queda quieto y de frente: ni flota, ni mira, ni respinga.
     El script tampoco le pone la mirada, pero esto lo deja clavado
     aunque el visitante cambie la preferencia con la página abierta */
  /* se queda la corrección de centrado, que no es movimiento sino encuadre */
  .retrato-img {
    transform: translate(var(--centrar), 0) !important;
    transition: none !important;
  }
  *, *::before, *::after {
    animation: none !important;
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}


/* ---------- 15 pantallas chicas ---------- */

@media (max-width: 1040px) {
  /* La franja incómoda: de 881px (donde aparece el menú de escritorio)
     hasta aquí. A 881px no caben el logo, cinco enlaces, el botón y 88px de
     canal lateral — medido, faltaban 74px.
     Medido a 881px: el logo, los cinco enlaces, el botón y los dos huecos
     de 28px piden 807px y la caja solo tiene 793. Se desborda 14px y el
     botón se mete en el canal lateral.
     Se probó bajando el canal lateral de 44 a 24px, que regala 40px de
     golpe, y se descartó: el logo dejaba de alinearse con el título de la
     página de abajo y eso sí se nota. Se paga donde no se ve — el hueco
     entre enlaces, de 26 a 18px. Con eso pide 775px y sobran 17. */
  .menu { gap: 18px; }

  .pilares { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* la marca se pone sola arriba y las tres columnas de enlaces quedan en
     una fila debajo: con dos columnas la tercera se quedaba huérfana */
  .pie-alto { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .pie-marca { grid-column: 1 / -1; }
}

@media (max-width: 880px) {
  .menu,
  .barra > .caja > .boton { display: none; }
  .hamburguesa { display: inline-flex; }

  .modelo-malla { grid-template-columns: 1fr; }

  /* el encabezado partido se vuelve a apilar y suelta la línea de base */
  .encabezado-partido {
    grid-template-columns: 1fr;
    align-items: start;
    gap: clamp(18px, 3vw, 26px);
  }
  .encabezado-partido h2,
  .encabezado-partido .entrada { max-width: 42ch; }
  .encabezado-partido .entrada { padding-bottom: 0; }

  /* el encabezado pegado se despega: en una columna no tiene contra qué quedarse */
  .lista-ideas { grid-template-columns: 1fr; gap: clamp(2.5rem, 6vw, 3.5rem); }
  .lista-ideas-cabeza { position: static; }
  .lista-ideas-cabeza h2,
  .lista-ideas-cabeza .entrada { max-width: 42ch; }

  /* la ruta pasa a dos líneas: nombre + sello arriba, descripción debajo.
     la colocación va explícita, si no el flujo manda el sello a su propia fila */
  .ruta-fila {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 10px 20px;
    align-items: center;
  }
  .ruta-nombre { grid-column: 1; grid-row: 1; }
  .ruta-estado { grid-column: 2; grid-row: 1; }
  .ruta-que    { grid-column: 1 / -1; grid-row: 2; }

  .portada h1 { max-width: none; }
}

@media (max-width: 560px) {
  :root { --radio: 14px; }

  .pilares { grid-template-columns: 1fr; }

  .idea { grid-template-columns: 1fr; gap: 8px; }
  .idea-num { padding-top: 0; }

  /* se deshace la colocación explícita del corte de 880,
     si no el sello sigue reclamando una segunda columna */
  .ruta-fila { grid-template-columns: 1fr; align-items: start; }
  .ruta-nombre,
  .ruta-que,
  .ruta-estado { grid-column: auto; grid-row: auto; }
  .ruta-estado { justify-self: start; order: 1; }

  .botonera { flex-direction: column; align-items: stretch; }
  .botonera .boton { width: 100%; }

  .pie-alto { grid-template-columns: 1fr; }
  .pie-bajo { flex-direction: column; align-items: flex-start; }

  /* las etiquetas de 12px con letra muy espaciada se leen mal en un
     celular. Suben a 13px, que es el piso real de legibilidad */
  .guia,
  .tarjeta-indice,
  .idea-num,
  .ruta-estado,
  .pie-col h4 { font-size: .8125rem; }
}


/* ---------- 15b dedos, no punteros ---------- */

/* Va por (pointer: coarse) y no por ancho de pantalla: el problema no es
   que la pantalla sea chica, es que el dedo es gordo. Así no se toca
   absolutamente nada del diseño de escritorio.
   La medida mínima es 44px (Apple) y 48px (Android); todo lo de aquí
   estaba por debajo y medido. */
@media (pointer: coarse) {

  /* medido 40x40: por debajo de las dos guías, y es el botón más
     importante de la página en celular */
  .hamburguesa { width: 46px; height: 46px; }

  /* medido 146x24: el logo es un enlace a la portada y no se podía
     tocar bien. Crece la zona, no el dibujo */
  .marca { min-height: 46px; }

  /* medido 18px de alto: tres enlaces seguidos a 18px son tres
     oportunidades de pulsar el que no era. El hueco de la lista pasa a
     cero porque ahora el aire lo pone el propio enlace */
  .pie-col ul { gap: 0; }
  .pie-col a { display: inline-block; padding-block: 13px; }

  /* medido 42px, a dos de la raya */
  .salto { padding: 12px 16px; }

  /* sin hover en una pantalla táctil, el botón no daba ninguna señal de
     haber sido pulsado. Se usa opacidad y no transform a propósito: no es
     movimiento, así que no pelea con la preferencia de quietud */
  .boton:active { opacity: .82; }
  .cajon nav a:active,
  .pie-col a:active { color: var(--blanco); }

  /* el destello gris que Safari y Chrome pintan solos encima del toque
     se quita: ya hay señal propia arriba */
  a, button { -webkit-tap-highlight-color: transparent; }
}


/* ---------- 15c cada sección se mueve como lo que es ----------

   En el celular estas cinco secciones se leen de una en una, casi a
   pantalla por bloque. En esa condición una lista plana no se siente como
   un recorrido: se siente como un formulario.

   La tentación fácil era ponerle a las cuatro listas el mismo riel con
   puntos. Eso no es diseño, es una plantilla: cuando el mismo adorno
   aparece cuatro veces seguidas deja de significar y pasa a ser ruido.
   Así que cada sección lleva un gesto sacado de lo que la sección ES, y
   los cinco gestos no comparten eje ni dirección:

     pilares   un pilar se LEVANTA         vertical    de abajo a arriba
     tarjetas  un sistema se ENCIENDE      horizontal  de izquierda a derecha
     ideas     un corchete se ABRE         vertical    desde el centro
     ruta      una vía se RECORRE          vertical    de arriba a abajo
     misión    una raya se ABRE del eje    horizontal  desde el centro

   Lo único compartido es el "vas por aquí": la parada que está en el
   centro de la pantalla se enciende un poco. Un solo mecanismo, cuatro
   expresiones distintas, ninguna igual a otra.

   Nada de esto toca el escritorio: allí ya hay hover y hay dos o tres
   columnas, y un riel vertical en una grilla no describiría nada. */


/* --- el número que dice cuánto está "viva" una parada ---
   Hay que registrarla para poder interpolarla: una variable sin registrar
   no se puede animar, salta de 0 a 1 de golpe. */
@property --viva {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}


/* --- pilares: un pilar se levanta ---
   Solo a una columna. Entre 561 y 1040 son dos columnas, y una franja de
   cobre a la izquierda de cada tarjeta no describiría nada ahí.

   No llevan hilo ni puntos a propósito: son tres cimientos en paralelo,
   no tres pasos. Un hilo que los une diría que hay un orden, y mentiría.
   Lo que llevan es un apoyo vertical que crece de abajo hacia arriba,
   fuerte abajo y disuelto arriba, como lo que sostiene algo. */

@media (max-width: 560px) {
  .pilar { padding-left: 20px; }
  /* la raya de arriba arranca donde arranca el texto, no antes */
  .pilar::before { left: 20px; }

  .pilar::after {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: linear-gradient(to top,
      var(--cobre) 0%,
      rgba(217, 119, 87, .55) 55%,
      rgba(217, 119, 87, .14) 100%);
    transform-origin: 50% 100%;
    pointer-events: none;
  }

  .js .pilar::after {
    transform: scaleY(0);
    transition: transform .9s var(--curva) .12s;
  }
  .js .pilar[data-visto='si']::after { transform: scaleY(1); }

  /* el pilar entra desde más abajo que el resto de la página: 26px en vez
     de 16, porque lo que se está contando es que algo se levanta */
  .js .pilar.sube { transform: translate3d(0, 26px, 0); }
  /* obligatorio: .js .pilar.sube empata en especificidad con
     .js .sube[data-visto='si'] y va después, así que sin esta línea el
     pilar entraría y nunca se asentaría */
  .js .pilar.sube[data-visto='si'] { transform: none; }

  /* al tocar, el apoyo se enciende: el degradado se aplana a cobre macizo
     y suelta un halo. No engorda a propósito — el ancho ya lo gobierna el
     desplazamiento más abajo, y si el toque también lo tocara las dos
     señales se pelearían: medido, al tocar bajaba de 4px a 3px, o sea que
     tocar APAGABA. Cada señal en su propio canal.
     No abre nada y no esconde nada. */
  .pilar[data-foco='si']::after {
    background: var(--cobre);
    box-shadow: 0 0 12px rgba(217, 119, 87, .55);
  }
}


@media (max-width: 880px) {

  /* --- tarjetas del modelo: un sistema se enciende ---
     La tarjeta no se puede mover: son cuatro cajas pegadas por costuras de
     1px, y moverlas abre grietas. Así que lo que se mueve es la LUZ.
     Entra por el borde de arriba a la izquierda y lo recorre; detrás va la
     rayita del índice, que se enciende con medio paso de retraso. Leído
     seguido parece un circuito que toma corriente.

     Se reaprovecha .tarjeta::after, que en escritorio es el filete del
     hover: en una pantalla táctil no hay hover, así que ese pseudo está
     libre y no hace falta inventar otro. */

  .tarjeta::after {
    inset: 0 0 auto 0;
    height: 1px;
    opacity: 1;
    background: linear-gradient(90deg,
      rgba(232, 169, 140, .95) 0%,
      rgba(217, 119, 87, .45) 58%,
      rgba(217, 119, 87, 0) 100%);
    transform-origin: left center;
    transition: none;
  }
  .js .tarjeta::after {
    transform: scaleX(0);
    transition: transform .95s var(--curva);
  }
  .js .tarjeta[data-visto='si']::after { transform: scaleX(1); }

  .tarjeta-indice::after {
    background: linear-gradient(90deg,
      var(--cobre) 0%,
      rgba(217, 119, 87, .10) 100%);
    transform-origin: left center;
  }
  .js .tarjeta-indice::after {
    transform: scaleX(0);
    transition: transform 1.05s var(--curva) .2s;
  }
  .js .tarjeta[data-visto='si'] .tarjeta-indice::after { transform: scaleX(1); }

  /* al tocar aparece un canto de cobre pegado al borde izquierdo. Crece en
     ancho, no en alto: así no hay que acertarle a la altura de la caja */
  .tarjeta::before {
    content: '';
    position: absolute;
    inset: 0 auto 0 0;
    width: 2px;
    background: var(--cobre);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform .22s var(--curva);
    pointer-events: none;
  }
  .tarjeta[data-foco='si']::before { transform: scaleX(1); }


  /* --- ideas: un corchete se abre ---
     Las tres ideas no son pasos ni cimientos: son tres cosas que la misma
     frase de arriba agrupa. El signo de agrupar es un corchete, así que
     cada idea lleva uno y se abre desde su centro hacia los dos extremos.
     Es el único gesto de la página que se mueve hacia afuera desde el
     medio en vertical, por eso no se confunde con ningún otro. */

  .idea { padding-left: 22px; }
  .idea::before { left: 22px; }

  .idea::after {
    content: '';
    position: absolute;
    left: 0;
    top: 18px;
    bottom: 18px;
    width: 9px;
    border: 1px solid var(--cobre);
    border-right: 0;
    pointer-events: none;
  }
  .js .idea::after {
    opacity: 0;
    transform: scaleY(.16);
    transition: transform .85s var(--curva) .1s,
                opacity .5s var(--curva) .1s;
  }
  .js .idea[data-visto='si']::after { opacity: 1; transform: scaleY(1); }

  /* el número entra por el hueco que el corchete acaba de abrir */
  .js .idea .idea-num {
    opacity: 0;
    transform: translateX(-12px);
    transition: opacity .55s var(--curva) .18s,
                transform .55s var(--curva) .18s;
  }
  .js .idea[data-visto='si'] .idea-num { opacity: 1; transform: none; }

  .idea[data-foco='si'] h3 { color: var(--cobre-claro); }


  /* --- ruta: una vía se recorre ---
     Esta sí es la única sección que merece vía con paradas, porque es la
     única donde el orden es el dato.

     Y la vía dice la verdad: de los cuatro, uno está en entrenamiento y
     tres no existen todavía. El tramo del que está vivo va en cobre
     continuo con el punto lleno y latiendo; los demás van en gris
     punteado con el punto hueco y quieto. La línea punteada no es adorno,
     es la información: eso todavía no está construido. */

  .ruta { position: relative; }
  .ruta-fila { position: relative; padding-left: 26px; }

  /* las rayas de la lista se repintan como fondo en vez de borde para que
     puedan arrancar en la sangría: un border-top no se puede recortar por
     la izquierda */
  .ruta,
  .ruta-fila {
    background-image: linear-gradient(var(--linea), var(--linea));
    background-repeat: no-repeat;
    background-size: calc(100% - 26px) 1px;
  }
  .ruta      { border-top-color: transparent;    background-position: 26px 0; }
  .ruta-fila { border-bottom-color: transparent; background-position: 26px 100%; }

  .ruta-fila::before {
    content: '';
    position: absolute;
    left: 5px;
    top: 0;
    bottom: 0;
    border-left: 1px dashed var(--linea-fuerte);
    pointer-events: none;
  }
  .ruta-fila:has(.ruta-estado[data-vivo='si'])::before {
    border-left-style: solid;
    border-left-color: var(--cobre);
  }

  /* la parada va colgada del NOMBRE, no de la fila.
     Intenté primero ponerla en la fila con un desfase calculado, y quedaba
     clavada hasta 560 y 3.5px alta de 561 a 880: el interlineado de
     .ruta-nombre no es fijo, pasa de 24px a 31px, así que ningún número
     escrito a mano lo puede seguir. Colgada del nombre, top:50% es el
     centro del renglón por definición y se ajusta solo a cualquier
     tamaño de letra que venga después.
     Y el -26px la devuelve al borde izquierdo de la fila, que es
     exactamente la sangría que acabamos de poner. */
  .ruta-nombre { position: relative; }

  .ruta-nombre::before {
    content: '';
    position: absolute;
    left: -26px;
    top: 50%;
    margin-top: -5.5px;
    width: 11px;
    height: 11px;
    box-sizing: border-box;
    border-radius: 50%;
    border: 1px solid var(--linea-fuerte);
    /* --panel y no --negro: esta sección va sobre panel, y un punto negro
       encima del panel se vería como un agujero */
    background: var(--panel);
    pointer-events: none;
  }
  .ruta-fila:has(.ruta-estado[data-vivo='si']) .ruta-nombre::before {
    border-color: var(--cobre);
    background: var(--cobre);
    animation: latido 2.9s ease-out infinite;
  }

  /* el tramo se dibuja de arriba hacia abajo, y el punto aparece cuando el
     tramo ya llegó */
  .js .ruta-fila::before {
    clip-path: inset(0 0 100% 0);
    transition: clip-path .95s var(--curva);
  }
  .js .ruta-fila[data-visto='si']::before { clip-path: inset(0 0 0 0); }

  .js .ruta-nombre::before {
    transform: scale(0);
    transition: transform .5s var(--curva) .3s;
  }
  .js .ruta-fila[data-visto='si'] .ruta-nombre::before { transform: scale(1); }

  /* la fila entra en diagonal, acercándose a su parada */
  .js .ruta-fila.sube { transform: translate3d(-14px, 10px, 0); }
  .js .ruta-fila.sube[data-visto='si'] { transform: none; }

  .ruta-fila[data-foco='si'] .ruta-nombre { color: var(--cobre-claro); }
}


/* el latido del punto vivo: un halo que sale y se apaga. No cambia de
   tamaño el punto, así que no mueve nada de alrededor */
@keyframes latido {
  0%        { box-shadow: 0 0 0 0 rgba(217, 119, 87, .5); }
  70%, 100% { box-shadow: 0 0 0 9px rgba(217, 119, 87, 0); }
}


/* --- misión: una raya se abre desde el eje ---
   Aquí no hay lista, así que no hay riel ni puntos que poner: sería
   ponerle aparato de lista a algo que no es una lista. La sección está
   centrada, y lo que cierra la página es una frase.

   Entonces la raya que separa esa frase se abre desde el centro hacia los
   dos lados, y en el centro queda un punto encendido. Es la única raya de
   la página que no se dibuja de izquierda a derecha, y eso la vuelve el
   final y no otro paso más.

   Queda dentro del tope de 880px como los demás: lo que se pidió fue el
   celular, y en escritorio esa raya ya está bien como está. Subirla a
   escritorio es un cambio aparte, no un efecto colateral de este. */

@media (max-width: 880px) {
  .apuesta-remate { position: relative; border-top-color: transparent; }

  .apuesta-remate::after {
    content: '';
    position: absolute;
    top: -1px;
    left: 0;
    right: 0;
    height: 1px;
    background: linear-gradient(90deg,
      rgba(217, 119, 87, 0) 0%,
      var(--linea) 20%,
      rgba(232, 169, 140, .6) 50%,
      var(--linea) 80%,
      rgba(217, 119, 87, 0) 100%);
    transform-origin: center;
    pointer-events: none;
  }
  .js .apuesta-remate::after {
    transform: scaleX(0);
    transition: transform 1.15s var(--curva);
  }
  .js .apuesta-remate:has(blockquote[data-visto='si'])::after { transform: scaleX(1); }

  .apuesta-remate::before {
    content: '';
    position: absolute;
    top: -4px;
    left: 50%;
    width: 9px;
    height: 9px;
    margin-left: -4.5px;
    border-radius: 50%;
    background: var(--cobre-claro);
    /* el anillo negro recorta la raya por debajo del punto, así el punto se
       lee encima y no empalmado */
    box-shadow: 0 0 0 5px var(--negro), 0 0 16px rgba(217, 119, 87, .55);
    pointer-events: none;
  }
  .js .apuesta-remate::before {
    transform: scale(0);
    transition: transform .55s var(--curva);
  }
  .js .apuesta-remate:has(blockquote[data-visto='si'])::before { transform: scale(1); }
}


/* ---------- 15d "vas por aquí" ----------

   Un solo mecanismo: la parada que está en el centro de la pantalla sube
   --viva de 0 a 1 y al salir vuelve a 0. Lo calcula el navegador contra el
   scroll, no un escucha en JavaScript, así que no se puede atascar ni
   hacer tropezar el desplazamiento.

   Pero cada sección lo gasta en algo distinto: el pilar engorda, la
   tarjeta suelta brillo por el borde, el corchete de la idea se satura y
   el punto de la ruta hace aura. Mismo mecanismo, cuatro lecturas. Eso es
   lo que lo salva de ser el mismo adorno repetido.

   Va dentro de @supports: donde no exista, las secciones quedan tal cual
   ya están, que ya funcionan solas. */

@supports (animation-timeline: view()) {

  @media (max-width: 560px) {
    .pilar {
      animation: parada-viva linear both;
      animation-timeline: view();
      animation-range: entry 35% exit 65%;
    }
    .pilar::after { width: calc(2px + var(--viva) * 2px); }
  }

  @media (max-width: 880px) {
    .tarjeta,
    .idea,
    .ruta-fila {
      animation: parada-viva linear both;
      animation-timeline: view();
      animation-range: entry 35% exit 65%;
    }

    .tarjeta::after {
      box-shadow: 0 0 calc(var(--viva) * 11px)
        rgb(217 119 87 / calc(var(--viva) * .85));
    }

    .idea::after {
      border-color: color-mix(in srgb,
        var(--cobre) calc(42% + var(--viva) * 58%), transparent);
    }

    /* el punto vivo queda fuera: ya late solo, y su animación pisaría este
       box-shadow de todos modos. Marcarlo dos veces no lo marca más */
    .ruta-fila:not(:has(.ruta-estado[data-vivo='si'])) .ruta-nombre::before {
      box-shadow: 0 0 calc(var(--viva) * 13px)
        rgb(217 119 87 / calc(var(--viva) * .55));
    }
  }

  @keyframes parada-viva {
    0%, 100% { --viva: 0; }
    44%, 56% { --viva: 1; }
  }
}
