/* ============================================================
   inicio.css — solo la landing.

   Se apoya en base.css (colores, tipografia, botones) y en app.css
   (la barra y las tarjetas dibujadas). Aca vive nada mas lo que no
   se usa en ninguna otra pantalla: el heroe, las columnas y los
   pasos. Ni un color escrito a mano.
   ============================================================ */


/* ============================================================
   LA ESCALA — semana 9.

   ---- POR QUE EXISTE ----

   Joel pidio "que se vea como una web de 40 mil dolares" y puso a
   Stripe de ejemplo. Lo que separa una pagina cara de una barata
   NO son las animaciones: son cuatro cosas aburridas, y dos viven
   en este bloque.

   1. UNA ESCALA ESTRICTA. Antes esta hoja tenia nueve tamanios de
      letra distintos —3.1, 2, 1.08, 1, .92, .88, .82, .78— casi
      todos elegidos a ojo para su seccion. Cuando cada bloque trae
      su propio tamanio, la pagina se lee como hecha por partes
      aunque cada parte este bien. Ahora son SEIS pasos y todo usa
      uno de ellos. Si algo necesita un tamanio que no esta aca, la
      pregunta correcta es cual de los seis le corresponde.

   2. EL AIRE. Los tramos pasaron de 3,5rem de respiro a 6, y las
      cajas de 1,5 a 2. Es lo mas barato que existe —no pesa un
      byte, no anima nada— y es probablemente la mitad de la
      diferencia con las paginas que Joel mando de referencia.

   Las otras dos son el centrado alternado, mas abajo, y usar
   poquisimos colores muy repetidos, que esta piel ya hacia.

   ---- POR QUE AQUI Y NO EN base.css ----

   Porque base.css la carga saldo.html, la pantalla de los 8
   segundos, y estos tokens son de la landing. El dia que la app
   quiera la misma escala, se suben a base.css y se borran de aca;
   hoy seria hacerle pagar bytes a la pantalla que no puede.
   ============================================================ */
.lienzo {
  --t-etiqueta: .75rem;                        /* mayusculas chicas */
  /* --t-chico se mudo a base.css el 2026-08-17, con el mismo valor.
     No es que la landing dejara de usarlo: lo usa `.pie`, que vive en
     base.css desde que lo cargan tres paginas, y ahi la variable no
     existia. Se movio en vez de duplicarse. Ver el porque completo en
     el bloque de tokens de base.css. */
  --t-cuerpo:   1rem;                          /* parrafos */
  --t-bajada:   1.125rem;                      /* la frase que explica */
  --t-titulo:   clamp(1.8rem, 3.6vw, 2.5rem);  /* titulos de seccion */
  --t-heroe:    clamp(2.4rem, 5.2vw, 3.6rem);  /* solo el h1 */
  /* Las CIFRAS grandes: el 6,7% contra el 80%, y el precio. Es el
     mismo tipo de elemento —un numero que se lee de lejos— y antes
     tenia dos tamanios distintos (2,4 y 2,2) sin ninguna razon. */
  --t-cifra:    2.5rem;

  --aire-tramo: 6rem;   /* respiro vertical de cada banda */
  --aire-caja:  2rem;   /* relleno de las cajas */

  /* ---- EL FONDO DE LA PAGINA, GUARDADO ----

     Las bandas claras redefinen `--fondo` para su propia paleta, asi
     que adentro de una de ellas ya no hay forma de nombrar el color
     del que vienen — y la costura necesita exactamente ese.

     Se guarda aca, en `.lienzo`, que no lleva `data-tema` y por lo
     tanto ve la paleta oscura. Las variables se heredan como valor
     ya computado, asi que las bandas de adentro reciben el color
     resuelto y no la variable: redefinir `--fondo` mas abajo no lo
     toca. Es la misma mecanica de la herencia que hizo falta
     entender para el `color` de los titulos.

     Y no es un hex escrito: si base.css cambia el fondo otra vez,
     esto lo sigue solo. */
  --fondo-pagina: var(--fondo);

  /* ---- POR QUE EL LIENZO RECORTA DE LADO ----

     Las costuras entre bandas se extienden con `left/right` en
     -100vmax para llegar de borde a borde. Eso, solo, agrega 1231 px
     de scroll horizontal — medido.

     Y NO alcanza con el `clip-path` que ya usan las bandas, que es
     justo lo que se aprendio el mismo dia arreglando el pendiente
     23: **`clip-path` recorta lo que se PINTA, no lo que se puede
     desplazar.** El unico que quita el scroll es un `overflow`.

     Va `clip` y no `hidden` a proposito: `hidden` crea un contenedor
     de desplazamiento —cualquier `scrollIntoView` de adentro
     empezaria a mover esta caja en vez de la pagina— y ademas
     convierte al elemento en bloque contenedor de los `position:
     fixed`, que aca son las cuatro capas del fondo. `clip` recorta y
     nada mas.

     Va en `.lienzo` y no en el `<body>` por esa misma razon: en el
     body dejaria las capas fijas ancladas a el en vez de a la
     ventana.

     ---- Y POR QUE NO VA EN `.lienzo`, QUE FUE EL PRIMER INTENTO ----

     El lienzo tiene `max-width: 76rem`, asi que recorta en 1216 px
     y no en el borde de la pantalla. Con el clip puesto ahi, las
     bandas dejaban **24 px de fondo oscuro a cada lado** en cuanto
     la ventana era mas ancha que el lienzo: justo lo que el
     box-shadow venia a evitar.

     Va en el `<html>`, que siempre mide lo que mide la ventana. Se
     puede escribir aca porque `inicio.css` la carga UNICAMENTE
     index.html; en base.css afectaria a las diez pantallas. */

  /* (la regla vive fuera de este bloque, justo abajo) */

  /* ---- EL UNICO COLOR ESCRITO EN ESTA HOJA, y por que ----

     Arriba dice "ni un color escrito a mano" y sigue siendo la
     regla: los colores viven en base.css. Esta es la excepcion y va
     razonada.

     Es lo que la tarjeta del heroe deja en el piso. No es el color
     de ninguna superficie: es una mancha que se corre cuando la
     tarjeta se inclina, o sea que tiene que ir DENTRO de un
     degradado, y los dos tokens de sombra que existen —--sombra y
     --sombra-alta— son listas de box-shadow, no colores: no se
     pueden meter en un radial-gradient.

     No sube a base.css por lo mismo que la escala de arriba: esa
     hoja la carga saldo.html, que no tiene ningun heroe.

     ---- Y EN OSCURO NO ES UNA SOMBRA, ES UN HALO ----

     Esto se probo antes de escribirlo. Una sombra negra sobre un
     fondo #080a18 no se ve: no hay a donde oscurecer. Por eso en
     oscuro el piso es morado y ACLARA en vez de oscurecer, que es
     exactamente lo que ya hace --sombra-alta en base.css
     —rgba(80,60,220,.32)— y por la misma razon. En claro si es una
     sombra de verdad, y lleva el morado de la piel adentro porque
     un gris neutro sobre blanco se ve sucio.

     Van dos perillas y no un color con alfa: el degradado usa el
     mismo color en dos opacidades, y con el alfa pegado al color no
     se podrian mover juntas. El formato "r g b" suelto —sin coma y
     sin rgb()— es lo que permite escribirlo dentro de un rgb() con
     el alfa aparte. */
  --piso-tarjeta: 120 86 255;
  --piso-fuerza: .78;

  /* El canto del plastico, o sea su grosor visto de lado. Estos dos
     NO tienen variante clara y no es un olvido: la tarjeta es una
     fotografia, no cambia con el tema, y su canto tampoco puede.

     Son dos y no uno porque el canto no es negro plano: la luz cae
     desde el frente, asi que el filo de adelante la recibe y el de
     atras no. Sin ese degradado el grosor se ve como una tira de
     cartulina pegada. */
  --canto-oscuro: #05060f;
  --canto-claro:  #322a5e;

  /* ---- EL NARANJA DE MARCA, que hasta hoy no era una variable ----

     #ff6b35, el que eligio Joel. La regla decia expresamente que no
     se guardara como variable "porque una variable invita a
     usarla", y eso valia mientras el unico sitio seguro fuera el
     heroe. Desde hoy los botones de la landing son naranjas, asi
     que la variable existe — pero vive en la hoja que la app NO
     carga. El naranja no puede llegar a un chip del dashboard
     aunque alguien lo escriba ahi. La proteccion pasa de ser una
     nota mental a ser la arquitectura.

     La tinta que va encima es casi negra y no blanca: con blanco el
     contraste es 2,85 y con esta, 6,76. */
  --naranja: #ff6b35;
  --sobre-naranja: #2b0d02;

  /* Lo que se escapa por la punta del boton. Naranja tambien, y en
     crudo por lo mismo que --piso: el halo lo usa en dos
     opacidades. */
  --luz-boton: 255 138 74;
}

/* ---- EL RECORTE LATERAL DE LA PAGINA ----

   Lo piden las costuras entre bandas, que se extienden con -100vmax
   para llegar de borde a borde. `clip-path` no sirve: recorta lo que
   se PINTA y no lo que se puede desplazar — la leccion del pendiente
   23, el mismo dia.

   ---- POR QUE HACEN FALTA LAS DOS LINEAS ----

   Ponerlo solo en `html` no hace nada, y se midio: seguian los 1231
   px de scroll. El overflow del elemento raiz **se propaga al
   viewport**, asi que el `<html>` deja de recortar el mismo y le
   pasa el encargo a la ventana, que es justamente la que se estaba
   desbordando.

   La forma de que el `<body>` recorte de verdad es darle al `<html>`
   un overflow que NO sea visible, porque ahi se corta la propagacion
   y cada uno vuelve a recortar lo suyo. `overflow-y: scroll` sirve y
   ademas evita el salto horizontal de la pagina cuando una vista
   pasa de necesitar barra a no necesitarla.

   Va `clip` y no `hidden`: `hidden` convierte al body en un
   contenedor de desplazamiento y cualquier `scrollIntoView` de
   adentro moveria esa caja en vez de la pagina. `clip` recorta y
   nada mas. Ninguno de los dos crea bloque contenedor para los
   `position: fixed`, asi que las cuatro capas del fondo siguen
   ancladas a la ventana — verificado, no supuesto.

   Y va en `inicio.css`, que carga UNICAMENTE index.html: en
   base.css afectaria a las diez pantallas. */
html { overflow-y: scroll; }
body { overflow-x: clip; }

/* En claro cambian LAS DOS: el color pasa a ser oscuro y la fuerza
   baja, porque sobre blanco la misma opacidad seria una mancha. */
:root[data-tema="claro"] .lienzo {
  --piso-tarjeta: 46 34 104;
  --piso-fuerza: .30;
}


/* ============================================================
   EL FONDO, BAJADO A CASI NEGRO — semana 9, segunda pasada

   Joel: "lo que no me gusta tanto es el fondo degradado con esos
   colores como moradito y verde. Hagamoslo mas parecido a Huly,
   que es casi negro".

   Las tres manchas de la malla viven en app.css y las comparten el
   dashboard y el presupuesto, donde nadie se quejo. Por eso el
   ajuste va AQUI y no alla: inicio.css la carga una sola pagina,
   asi que esto oscurece la landing y no toca la app. Es el mismo
   corte de siempre, usado al derecho.

   No se apagan del todo (.06 y no 0) porque el fondo negro puro
   deja la pagina sin ninguna profundidad, y porque lo que va a
   llenar ese sitio es la imagen que se descubre con el mouse, que
   todavia no existe. Cuando exista, este numero es la perilla para
   que la malla no le compita.

   El codigo NO se borra, se baja: es la misma decision que la
   semana 9 tomo con --reticula-fuerza y la opacidad de .fondo.

   Los dos selectores son de una sola clase, igual que los de
   app.css, y ganan por estar en la hoja que se carga despues. No
   hace falta scope: esta hoja SOLO la carga index.html, asi que un
   `.fondo` pelado aca ya significa "el fondo de la landing".
   ============================================================ */
.fondo { opacity: .06; }


/* ============================================================
   LA CAPA QUE SE DESCUBRE CON EL MOUSE — semana 9

   Es el efecto de huly.io que Joel trajo en la semana 9 y que
   estuvo esperando a que existiera la imagen. La imagen la generó
   él con GPT a partir de capturas del dashboard: fragmentos de la
   app en una retícula gris sobre negro, sin una gota de color.

   ---- COMO FUNCIONA, en una frase ----

   La imagen esta SIEMPRE ahi, entera y quieta. Lo que se mueve es
   una mascara circular; la mascara no dibuja, solo decide que
   pedazo de la imagen se ve. Dos variables de CSS y un script que
   las escribe en pointermove.

   ---- POR QUE NO SE VE MAS QUE UN POCO ----

   La opacidad es .5 y el centro de la mascara no llega a negro
   pleno. Es a proposito: esto tiene que leerse como que hay algo
   detras, no como una segunda pagina. El dia que se quiera mas
   fuerte, son estos dos numeros.

   ---- EL ORDEN DE LAS CUATRO CAPAS DEL FONDO ----

   z -4  .reveladora   la retícula del dashboard (esta)
   z -3  svg.fondo     las manchas de color, hoy en .06
   z -2  body::before  la retícula fina, hoy apagada
   z -1  .particulas   los puntos

   saldo.html no recibe ninguna de las tres primeras, y ahora
   tampoco esta: vive en la hoja que esa pantalla no carga.

   ---- LA IMAGEN, y por que hay dos declaraciones ----

   image-set() elige AVIF donde se pueda y WebP donde no, que es la
   regla de imagenes del proyecto. Pero image-set con type() no
   existe en navegadores viejos, y una declaracion que el navegador
   no entiende se tira ENTERA: quedaria sin fondo. Por eso arriba va
   la version simple, que cualquiera entiende, y abajo la buena, que
   la pisa donde se pueda.
   ============================================================ */
.reveladora {
  position: fixed;
  inset: 0;
  z-index: -4;
  pointer-events: none;

  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  background-image: url('../img/fondo-grid.webp');
  background-image: image-set(
    url('../img/fondo-grid.avif') type('image/avif'),
    url('../img/fondo-grid.webp') type('image/webp'));

  /* ---- LA OPACIDAD DEPENDE DEL RADIO, no solo de la imagen ----

     Con el radio de 60rem esto estuvo en .28, y el numero salio de
     medir: la reticula nueva tiene brillo medio 17,2 sobre 255
     contra 12,5 de la anterior —1,38 veces mas clara— asi que
     .38 / 1,38 daba .275. La cuenta estaba bien y el resultado se
     veia mal igual.

     Lo que faltaba en la cuenta era el AREA. Una mancha que cubre
     la pantalla entera al 28% es un velo permanente; la misma
     imagen en un charco de 272px puede ir al 48% y sigue siendo un
     descubrimiento, porque el resto de la pagina queda limpio. Al
     achicar el radio se libero presupuesto para que lo poco que se
     ve, se vea de verdad.

     Las dos perillas van juntas: si algun dia se agranda el radio,
     esto tiene que bajar.

     ---- Y BAJO, el 2026-08-16 ----

     Al quitar la mascara el "radio" paso a ser la pantalla entera,
     asi que la advertencia de arriba se cobro de una: con .48 sobre
     toda la superficie el grid dejaba de ser profundidad y competia
     con el titular. .12 es lo que hace que se note que hay algo
     detras sin que ninguna linea del fondo pelee con una letra. */
  opacity: .22;

  /* ---- LOS AROS Y EL RADIO SON EL MISMO PROBLEMA ----

     Van tres intentos y los dos primeros fallaron por lo mismo, con
     el diagnostico al reves.

     Primero: tres paradas y 28rem. Joel vio aros. Culpe al escalon
     del medio —que si dibuja un borde— y lo saque, pero de paso
     agrande el radio a 60rem creyendo que una pendiente mas suave
     los mataria. **Fue peor y por dos motivos a la vez:** con 960px
     de radio el grid se veia en toda la pantalla, o sea que dejo de
     ser un descubrimiento; y los aros siguieron ahi.

     Segundo, el diagnostico bien hecho: se apago la mascara entera
     y **los aros desaparecieron**, o sea que no eran de la imagen ni
     del AVIF. Son BANDEO del degradado. El alfa tiene 256 escalones
     y nada mas: repartidos en 960px, cada escalon dura casi cuatro
     pixeles y se ve como un anillo. Repartidos en 272px dura uno
     solo y desaparece. **El radio chico no es lo contrario de
     arreglar los aros: es lo que los arregla.** Y es ademas lo que
     Joel queria — "que solo se descubra la parte donde este pasando
     el mouse".

     Las nueve paradas son una curva suave de verdad (smoothstep,
     3t²-2t³) y no una recta. Importa en las dos puntas: una recta
     llega al borde con pendiente constante y ahi el ojo ve el
     contorno del circulo. Esta llega con pendiente cero por los dos
     lados, asi que no hay donde agarrarse.

     El -webkit- sigue haciendo falta: Safari monta mask-image sin
     prefijo hace tiempo, pero -webkit-mask-image es lo que entienden
     las versiones que todavia circulan, y es una linea. */
  /* ---- LA MASCARA VUELVE, Y AHORA SI SIN AROS ----

     Historia corta: se probaron cuatro radios y curvas, Joel vio los
     aros en todas, se quito entera — y entonces el grid quedo
     visible en toda la pagina, que era peor. Su correccion:
     "tienes que dejar el background #121212 como estaba, para poder
     revelar el grid con el mouse".

     Lo que faltaba entender es que **el bandeo no depende de la
     curva sino del RANGO de opacidad que la curva recorre.** El alfa
     tiene 256 escalones. Con el grid al 48%, la mascara tenia que
     bajar de .48 a 0 y cada escalon era un salto grande: se veia el
     anillo. Con el grid al 16%, el mismo degradado recorre un tercio
     del rango, los escalones son tres veces mas finos y no hay nada
     que ver.

     O sea que las dos perillas que la hoja ya decia que van juntas
     —radio y opacidad— eran las correctas, pero al reves de como se
     movieron: el arreglo no era achicar el radio para poder subir la
     opacidad, era BAJAR LA OPACIDAD para poder agrandar el radio.

     ---- EL RADIO ES CHICO A PROPOSITO, corregido el 2026-08-16 ----

     Se probo con 34rem y Joel: "no quiero que se vea nada saliendo
     del mouse. Ningun aro de luz. Nada. Y haz el tamano de
     revelacion mas pequeno, apenas pegado al radio del mouse."

     6rem son 96 px: poco mas que el cursor. Y eso, ademas de ser lo
     pedido, es lo que TERMINA de matar el bandeo — en 96 px el
     degradado tiene un pixel por cada escalon de alfa que recorre,
     asi que no hay ninguna franja lo bastante ancha como para
     leerse como anillo. Un radio grande reparte los mismos 256
     escalones en mil pixeles y ahi cada uno mide cuatro.

     Con el radio chico la reticula sube a .22: en un area pequena
     hace falta un poco mas para que se note que hay algo, y el
     rango sigue siendo la mitad del .48 que producia los aros.

     Las dos perillas van juntas, por tercera vez: radio y opacidad.
     Si alguna vez se agranda el radio, la opacidad TIENE que bajar. */
  --luz-x: 50%;
  --luz-y: 32%;
  --luz: radial-gradient(6rem circle at var(--luz-x) var(--luz-y),
    rgba(0,0,0,1)    0%,
    rgba(0,0,0,.957) 12.5%,
    rgba(0,0,0,.844) 25%,
    rgba(0,0,0,.684) 37.5%,
    rgba(0,0,0,.5)   50%,
    rgba(0,0,0,.316) 62.5%,
    rgba(0,0,0,.156) 75%,
    rgba(0,0,0,.043) 87.5%,
    transparent      100%);
  -webkit-mask-image: var(--luz);
          mask-image: var(--luz);
}

/* En el tema claro la reticula es gris muy oscuro sobre un fondo
   casi blanco: se veria como una mancha sucia en vez de una
   profundidad. Se apaga. El efecto es de la piel oscura. */
:root[data-tema="claro"] .reveladora { display: none; }

/* ---- EL TITULO NO SE TOCA ----

   Joel, mirando huly.io: "el humo y la aparicion del grid oculto
   nunca toca el titulo ni el texto del Hero. Por eso sirve que el
   fondo sea oscuro, para poder jugar alrededor con los elementos."

   La linterna es una capa fija que cubre la pantalla entera, asi
   que al pasar el cursor por el titulo la reticula se encendia
   justo detras de las letras. No las tapaba —son blancas sobre gris
   oscuro— pero le quitaba al titular el unico sitio limpio que
   tiene.

   Se resuelve con una mancha del color del fondo debajo del bloque
   de texto: la reticula sigue existiendo ahi, apagada por encima.
   Va con el token --fondo y no con un negro escrito, asi que
   acompaña a la piel.

   z-index -1 la deja por encima de las cuatro capas del fondo
   —que van de -4 a -1— y por debajo del texto, que no lleva
   ninguno.

   ---- POR QUE NO SE DERRAMA A LA DERECHA ----

   El derrame era simetrico —`inset: -3rem -4rem`— y eso costo dos
   bugs de desborde horizontal, uno en telefono y otro entre 721 y
   799 px. Los dos se habian tapado con una media query, y la
   segunda aparecio justamente porque la primera movio el bug al
   tramo de al lado en vez de resolverlo.

   La causa se midio y era una sola: en el tramo de UNA columna el
   bloque de texto ocupa el ancho entero del lienzo, asi que las
   4rem de la derecha caen FUERA de la pantalla y estiran el
   documento 40 px. Un desborde horizontal no rompe nada visible
   —por eso llevaba dias sin que nadie lo viera— y se siente como
   que la pagina se arrastra de lado.

   Y lo que lo vuelve gratis de arreglar: ese derrame derecho NO
   PINTA NADA. El degradado se apaga en el 76% de su radio y el
   borde derecho de la caja cae en el 91,7%, o sea que esas 4rem
   son area transparente. Se estaban pagando 40 px de scroll por
   pixeles que no se dibujan.

   Por eso la derecha va en 0 y la izquierda conserva sus 4rem: ahi
   SI hay mancha —el centro del degradado esta al 37% del ancho— y
   un derrame hacia la izquierda no estira el documento, porque en
   lectura de izquierda a derecha el navegador no genera scroll
   hacia atras.

   Los dos numeros del degradado estan compensados para que la
   mancha quede donde estaba: al angostarse la caja 4rem, el radio
   sube de 72% a 78% y el centro de 34% a 37%. En pantalla es la
   misma mancha; lo que cambio es que ya no sobra caja a la derecha.

   NO LLEVA MEDIA QUERY, y esa es la mitad del arreglo. Verificado
   sin desborde en 23 anchos de 320 a 1920 px con esta sola regla.
   Un breakpoint aca solo mueve el problema al ancho siguiente, que
   es exactamente lo que ya paso dos veces.

   ---- VUELVE A DERRAMARSE A LA DERECHA, y no es una regresion ----

   El parrafo de arriba es de esta misma semana y sigue siendo
   cierto: el derrame derecho estiraba el documento 40 px. Lo que
   cambio es que ahora el `<body>` lleva `overflow-x: clip` —lo
   pidieron las bandas alternas— asi que el desborde ya no puede
   ocurrir. El motivo para recortarla desaparecio; la mancha vuelve
   a ser simetrica y mas grande.

   ---- EL BORDE SE VEIA, Y ERA POR LAS PARADAS ----

   Joel: "se nota como un cuadro negro cuando uno pasa el mouse por
   debajo y se revela el grid".

   La causa NO era el tamano sino la forma del degradado: iba de
   solido a transparente en DOS paradas, o sea con una rampa recta.
   Una rampa recta cambia de pendiente de golpe en los dos extremos
   y el ojo lee ese quiebre como un contorno — la reticula aparece
   de golpe en vez de asomar.

   Es exactamente lo que paso con los aros de la linterna en la
   semana 9, y se arregla igual: **nueve paradas siguiendo un
   smoothstep de verdad (3t²−2t³)**, que llega al borde con pendiente
   CERO. Sin quiebre no hay contorno que ver, por mas que la mancha
   sea grande.

   El nucleo solido llega hasta el 52%, que es lo que cubre el
   bloque de texto entero; de ahi al 100% es puro desvanecido. */
/* ---- LA MANCHA DEL TITULO SE QUITO el 2026-08-16 ----

   Existia para apagar la reticula justo detras del titular. Se le
   probaron tres formas —dos paradas, nueve con smoothstep, y mas o
   menos radio— y Joel las vio todas: "se nota como un cuadro negro",
   y con el degradado suave, "se nota el aro y el cuadrado".

   El problema de fondo es que **una mancha del color del fondo
   encima de una textura siempre tiene un borde**: por suave que sea
   la rampa, hay un sitio donde la textura reaparece, y el ojo lo
   encuentra. Achicarlo lo vuelve un aro; agrandarlo, un cuadro.

   Se quita entera. Como ademas se apago la linterna (mas abajo), la
   reticula ya no se enciende debajo del texto y no hay nada que
   tapar. Si algun dia vuelve a hacer falta, la salida NO es otra
   mancha: es bajarle la opacidad a la reticula en la zona del
   heroe, o recortar la imagen. */
.heroe > div:first-child { position: relative; }

/* Sin mouse no hay linterna que mover, asi que la mascara se cambia
   por un velo grande y quieto anclado arriba, que es donde
   igualmente estaria la atencion. Se prefiere eso a esconderla:
   apagada del todo, el telefono se queda con un negro plano.

   Lo mismo con prefers-reduced-motion, y por otro motivo: una
   mancha de luz persiguiendo al cursor es movimiento aunque no se
   desplace ningun elemento. */
@media (hover: none), (prefers-reduced-motion: reduce) {
  /* Sin cursor no hay nada que perseguir. Se deja un velo grande y
     quieto anclado arriba, que es donde igual esta la atencion: sin
     el, el telefono se queda con un negro plano. */
  .reveladora {
    opacity: .13;
    -webkit-mask-image: radial-gradient(130% 72% at 50% 10%,
      rgba(0,0,0,.9), transparent 82%);
            mask-image: radial-gradient(130% 72% at 50% 10%,
      rgba(0,0,0,.9), transparent 82%);
  }
}

/* Las particulas tambien: sobre un fondo casi negro los puntitos
   pasan a ser lo mas claro de la pantalla, que es al reves de lo
   que tienen que ser. */
.particulas { opacity: .55; }

/* ---- Y SE MUEVEN MAS RAPIDO, solo en la landing ----

   Las de app.css van a 110s y 170s por vuelta, o sea 0,38 px/s: la
   semana 8 midio que eso esta POR DEBAJO del umbral en que el ojo
   detecta movimiento, y ahi estaba bien —en el dashboard el fondo
   no tiene que llamar la atencion mientras alguien lee cifras.

   Aca son lo unico que hay sobre el #121212, y Joel las pidio
   "flotantes que se muevan". A un tercio del tiempo se notan sin
   distraer. Se toca solo en esta hoja: la aplicacion sigue con su
   ritmo lento. */
.particulas::before { animation-duration: 34s; }
.particulas::after  { animation-duration: 52s; }

/* La malla de colores tambien se apaga: con el grid fuera, lo unico
   que queda sobre el #121212 son las particulas, que es lo que se
   pidio. A .06 ya era casi invisible; dejarla encendida solo suma
   una capa que nadie ve y que el navegador igual dibuja. */
.lienzo ~ svg.fondo, svg.fondo { opacity: 0; }


/* ---- El heroe ---- */
/* El heroe es la excepcion al centrado, y a proposito: es lo unico
   de la pagina con dos columnas de verdad —el texto y el mazo— asi
   que centrarlo dejaria las tarjetas flotando sin apoyo. Que abra
   alineado a la izquierda y todo lo demas vaya centrado ES la
   alternancia que Joel vio en Stripe sin saber como se llamaba. */
.heroe {
  display: grid;
  /* El min() de adentro es un arreglo, no adorno. Un minmax(21rem, 1fr)
     pelado no puede bajar de 21rem NUNCA, ni cuando la
     pantalla mide menos: en un telefono de 320px la columna seguia
     midiendo 336 y el titulo, la bajada y los botones se salian 32
     pixeles por la derecha. La pagina se podia arrastrar de lado y
     nada se veia roto. Con min(21rem, 100%) la columna se rinde
     cuando no hay sitio. Medido a 320px: 352 de documento contra
     320 de pantalla antes, iguales despues. */
  grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr));
  gap: 3.5rem;
  align-items: center;
  padding: 5.5rem 0 4.5rem;
}

.heroe h1 {
  font-size: var(--t-heroe);
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: 1.06;
}

/* ---- LAS DOS PALABRAS CON DEGRADADO ----

   "Tarjetas" e "ingresos", que son las dos mitades del producto.
   Pedido de Joel el 2026-08-16.

   El degradado recorre LA PALABRA de izquierda a derecha, que es lo
   que él pidió. Va del morado al naranja: son los dos colores de la
   marca y el recorrido entre ellos pasa por tonos que existen en la
   paleta, no por un gris muerto en el medio.

   ---- POR QUE `inline-block` Y NO A SECAS ----

   Un `background-clip: text` sobre un elemento en línea que se parte
   en dos renglones pinta el degradado ENTERO en cada pedazo, así que
   la palabra saldría con dos veces el mismo recorrido. Acá no puede
   partirse —las dos van con &nbsp; alrededor— pero `inline-block` lo
   garantiza en vez de confiar en el marcado.

   ---- Y POR QUE HAY UN `color` DEBAJO ----

   Si algún navegador no aplicara `background-clip: text`, el
   `color: transparent` dejaría el titular INVISIBLE. La declaración
   de `color` va antes y `@supports` es lo único que la pisa: sin
   soporte, la palabra sale en `--acento` y se lee. Un fallo de
   estilo no puede borrar el titular de la página. */
.realce {
  display: inline-block;
  color: var(--acento);
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
  .realce {
    background-image: linear-gradient(100deg, var(--acento) 8%, var(--naranja) 92%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

/* La seccion de cierre. El `overflow: hidden` se queda aunque el
   campo de rayos que lo necesitaba se borro el 2026-08-22: sigue
   conteniendo el sangrado de la banda. */
.cierre { position: relative; overflow: hidden; }

.cierre > * { position: relative; }

/* La frase que de verdad explica el producto. Mas grande que un
   parrafo normal porque mucha gente lee solo el titulo y esto. */
/* La bajada es corta: se equilibra como un titulo, no como un
   parrafo. Con pretty solo se arregla el ultimo renglon; con
   balance quedan los dos del mismo largo. */
.bajada { text-wrap: balance; margin-top: 1.35rem; font-size: var(--t-bajada);
          color: var(--suave); max-width: 34rem; line-height: 1.6; }

.acciones { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2.25rem; }
.acciones > * { margin-top: 0; width: auto; padding: .9rem 1.6rem; }


/* ============================================================
   LOS BOTONES DE LA LANDING — semana 9, segunda pasada

   Joel, despues de mirar huly.io: que no crezcan, y que el
   primario tenga "esa luz neon siguiendo el mouse".

   ---- POR QUE SE VA EL CRECIMIENTO ----

   No porque estuviera mal hecho: el 3% de escala y los 3px de
   subida se midieron en la semana 9 y arreglaron la sensacion de
   interruptor. Se va porque ahora hay algo mejor en el mismo sitio.
   Una luz que sigue al cursor contesta CONTINUO —dice donde esta el
   dedo, cuadro a cuadro— y un crecimiento contesta una sola vez, al
   entrar. Las dos juntas es una respuesta de mas.

   ---- POR QUE A TODOS LOS PRIMARIOS Y NO SOLO AL DEL HEROE ----

   Joel pidio "esos dos botones del Hero". Se aplica a los cuatro
   "Crear mi cuenta" de la pagina porque son EL MISMO BOTON, y este
   proyecto ya tiene la regla escrita desde la semana 6, cuando los
   paneles de utilizacion adoptaron el hover de las columnas: una
   caja no puede reaccionar de dos maneras distintas segun donde
   este. Que el del heroe se ilumine y el de precios crezca es
   exactamente eso.

   Va en inicio.css y no en base.css, asi que ni el dashboard ni
   saldo.html se enteran: alla los botones siguen creciendo, y ahi
   si esta bien, porque en una pantalla de trabajo el boton tiene
   que contestar rapido y no lucirse.

   ---- EL BOTON PASA A SER NARANJA, y la regla del naranja no se
        rompe ----

   La regla dice: el naranja de marca vive UNICAMENTE en la
   decoracion del heroe, nunca en un chip, un estado ni una cifra,
   porque esta a cuatro grados de matiz de --cat-deuda y adentro de
   la app ese color significa deuda.

   Un boton no es ninguna de esas tres cosas. Un chip, un estado y
   una cifra son DATOS: dicen algo sobre la plata de la persona. Un
   boton es un control, y ningun usuario va a leer "esto es deuda"
   en el sitio donde dice "Crear mi cuenta". Lo que la regla protege
   es que el naranja no signifique dos cosas a la vez adentro de la
   aplicacion.

   Y por eso la variable vive AQUI y no en base.css. La regla decia
   que no se guardara como variable "porque una variable invita a
   usarla" — el problema real no era la variable sino donde. En esta
   hoja, que solo carga index.html, el naranja no puede llegar a un
   chip del dashboard ni aunque alguien lo escriba: la app no carga
   este archivo. La regla queda mejor cuidada por la arquitectura
   que por la memoria de quien programa.

   ---- Y POR QUE EL TEXTO ES OSCURO Y NO BLANCO ----

   Se midio antes de ponerlo. #ff6b35 con letra blanca da 2,85 de
   contraste, muy por debajo del minimo de 4,5. Con la tinta oscura
   da 6,76. Es la misma razon por la que el boton de Huly es una
   pastilla clara con letra casi negra y no al reves.
   ============================================================ */
.lienzo .principal:hover,
.lienzo .principal:active,
.lienzo .secundario:hover,
.lienzo .secundario:active { transform: none; }

/* El secundario deja de hacer absolutamente nada, por pedido
   expreso: "Ver como funciona" es la salida de escape, no la
   accion. Que las dos brillen igual es no haber elegido. Se le deja
   el cursor y el foco del teclado, que no son adorno. */
.lienzo .secundario:hover { border-color: var(--linea); box-shadow: none; }

/* ---- EL BOTON NARANJA ---- */
.lienzo .principal {
  position: relative;
  background: var(--naranja);
  color: var(--sobre-naranja);
  border-color: transparent;

  /* --bx y --by son la posicion del mouse DENTRO del boton, en
     porcentaje. --borde va de 0 en el centro a 1 en las puntas y es
     lo unico que decide cuanta luz sale hacia afuera. Las escribe
     js/inicio.js; en reposo la luz queda centrada y encerrada, que
     es donde la deja quien llega con el teclado. */
  --bx: 50%;
  --by: 50%;
  --borde: 0;
}

/* ---- LA LUZ, QUE VIVE ADENTRO ----

   Joel, mirando huly.io de nuevo: "la luz corre por el boton pero
   se queda... es como que siempre estuviera ahi y se mueve cuando
   el mouse lo mueve, pero esta encerrada en el boton".

   Tenia razon y la primera version estaba mal: yo habia hecho una
   mancha grande que salia por el borde y acompañaba al cursor
   siempre, o sea un foco pegado al mouse. Lo de Huly es otra cosa:
   la luz esta DENTRO del plastico, como si el boton fuera un tubo
   encendido por dentro, y lo unico que se ve por fuera es lo que se
   escapa por la punta cuando la luz llega al final.

   Por eso ahora son dos capas con dos reglas distintas:
   el reflejo de adentro sigue al cursor SIEMPRE;
   el derrame de afuera depende solo de --borde. */
.lienzo .principal::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(7rem circle at var(--bx) var(--by),
    rgba(255,252,244,.95), rgba(255,240,214,.45) 38%, transparent 72%);
  opacity: 0;
  transition: opacity .28s cubic-bezier(.2,.7,.3,1);
}

/* ---- LO QUE SE ESCAPA POR LA PUNTA ----

   Un halo pegado al contorno del boton, sin desplazamiento propio:
   no persigue al cursor, solo sube y baja de intensidad segun
   --borde. Con el mouse en el centro vale 0 y no hay nada afuera;
   en las puntas vale 1 y ahi se ve el reborde caliente.

   Va con box-shadow y no con un elemento aparte a proposito. La
   version anterior era un degradado suelto que se movia con
   left: var(--bx), y ese movimiento era justamente el error: hacia
   que la luz de afuera fuera un objeto propio en vez de un
   desborde. Un box-shadow no se puede despegar del boton ni
   queriendo, que es exactamente la garantia que hacia falta.

   Que este solo en las puntas y no todo alrededor sale gratis: la
   sombra abraza una pastilla, asi que en los lados largos queda un
   pelo y en las curvas de las puntas se acumula. Es la forma del
   boton haciendo el trabajo. */
.lienzo .principal::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    0 0 1.4rem .1rem rgb(var(--luz-boton) / .85),
    0 0 3.2rem .3rem rgb(var(--luz-boton) / .45);
  opacity: 0;
  transition: opacity .18s linear;
}

.lienzo .principal:hover::before,
.lienzo .principal:focus-visible::before { opacity: 1; }

/* El derrame no se prende con el hover sino con --borde, que ya
   vale 0 mientras nadie toque el boton. Asi no hay dos condiciones
   que puedan contradecirse: la luz de afuera ES la distancia al
   centro, y nada mas. */
.lienzo .principal:hover::after { opacity: var(--borde); }

/* El texto tiene que quedar sobre el reflejo. Va con un <span>
   adentro del boton y no con un z-index sobre el ::before, porque
   un z-index positivo ahi lo sacaria de la caja del boton y el
   derrame de afuera dejaria de quedar detras. */
.lienzo .principal > span { position: relative; }

/* El texto chico debajo de los botones: dice lo que la gente esta
   por preguntarse antes de tocar. */
.letra-chica { margin-top: 1.25rem; color: var(--suave); font-size: var(--t-chico); }

/* ============================================================
   LA TARJETA 3D DEL HEROE — semana 9

   Reemplazo del mazo de dos tarjetas dibujadas con CSS que estuvo
   aca desde la semana 5.

   ---- POR QUE TIENE GROSOR, y por que eso NO era una regla ----

   La primera version eran DOS caras, o sea un plano. Joel reporto
   que al girar "la imagen desaparece un momento", y sospecho que
   habia una regla vieja del proyecto prohibiendo el 3D de verdad.
   No la hay: era geometria. Un plano visto de canto tiene ancho
   cero, asi que a 90 grados no habia nada que dibujar. Un naipe de
   verdad tampoco desaparece, y el motivo es que TIENE GROSOR.

   Entonces ahora son SEIS caras: frente, reverso y los cuatro
   cantos. A 90 grados se ve el canto, y no hay un solo angulo de
   los 360 en el que la tarjeta no este. Ese es el cambio entero.

   Y por eso el reverso se queda aunque no diga nada util. Sin el,
   al pasar los 90 grados se veria el frente al reves —espejado—,
   que es peor que una cara aburrida.

   ---- LAS CAPAS ----

   .plastico          da la perspectiva. No rota.
   .plastico-onda-y   contenedores, y nada mas: quedaron vacios el
   .plastico-onda-x   2026-08-21. Ver abajo.
   .plastico-cuerpo   TODA la rotacion: el vaiven y el mouse
   .plastico-cara     la piel: frente y reverso
   .plastico-nucleo   las catorce laminas del grosor

   ---- ESTO DECIA OTRA COSA HASTA EL 2026-08-21 ----

   Decia que las tres primeras estaban separadas "porque cada una
   hace una rotacion y un elemento tiene un solo transform. Escritas
   juntas se borran entre si". El hecho es cierto y la conclusion
   resulto cara: separarlas en capas arregla el choque de transforms
   **y mete tres capas animadas dentro del preserve-3d**, que es
   justo lo que rompe el 3D de los hijos. En Safari eso partia la
   tarjeta en dos con un corte diagonal.

   Hoy las tres rotaciones viven en .plastico-cuerpo y se suman como
   angulos —no como transforms— gracias a @property. El choque que
   obligaba a separarlas ya no existe, asi que las capas tampoco
   hacen falta.

   Las dos .plastico-onda-* se dejaron en el marcado: vacias no
   cuestan nada y son el camino de vuelta si @property fallara.

   Y esa separacion resuelve dos cosas de una: las dos ondas cruzadas
   dibujan el ocho sin muestrear ninguna curva, y el vaiven NUNCA SE
   DETIENE, ni siquiera mientras el mouse manda. Todo se suma.

   ---- POR QUE EL VAIVEN ES CSS Y NO JAVASCRIPT ----

   Es un bucle que no para nunca, que es justo lo que este proyecto
   evita: un requestAnimationFrame corriendo siempre es bateria que
   alguien paga. Un @keyframes no es un bucle: lo interpola el
   compositor, no hay JavaScript despertandose, y el navegador lo
   suspende solo cuando la pestana no se ve. Sale gratis.

   El recorrido es una Lissajous de 1:2 —el eje Y hace un ciclo
   mientras el X hace dos— que es la forma matematica del simbolo
   del infinito. Los diecisiete pasos de abajo son esa curva
   muestreada; no estan elegidos a ojo.

   ---- NADA DE filter NI DE mix-blend-mode AQUI ADENTRO ----

   Las dos cosas crean su propia capa de dibujo y aplanan el
   contexto 3D: las caras se pintan encimadas y las de atras salen
   espejadas. Paso de verdad en la semana 5 con el backdrop-filter
   del boton de girar. Por eso el brillo es un degradado plano y el
   halo del piso es un elemento aparte, fuera de la cadena 3D, en
   vez de un drop-shadow.
   ============================================================ */

.plastico {
  /* El ancho manda TODO lo demas, y aca eso es literal: el alto, el
     grosor y la distancia a la que se planta cada canto salen de
     esta cuenta. Por eso no puede llevar un `min(..., 100%)`
     encima: un porcentaje del contenedor no se puede meter en un
     translateZ, que exige una longitud de verdad. El tope contra el
     ancho de la pantalla se pone aca adentro, con vw, que si sirve
     en calc. */
  --ancho: min(clamp(15rem, 32vw, 25rem), 100vw - 2.5rem);
  --alto: calc(var(--ancho) / 1.5852);   /* 1200 x 757, las imagenes */

  /* ---- EL GROSOR VA EXAGERADO, Y SE MIDIO ----

     Una tarjeta real mide 0,76 mm sobre 85,6 mm de ancho: 0,9%.
     Puesto asi, a 90 grados el canto es una raya de 4 pixeles, y
     una raya de 4 pixeles no se lee como "la estoy viendo de
     canto", se lee como que la tarjeta desaparecio —que es
     exactamente lo que Joel pidio que no pasara—.

     En 2,8% el canto mide 11 px y ahi si se ve un objeto de perfil,
     con su degradado de luz. De frente no cuesta nada: los cantos
     no se ven, asi que la exageracion no se paga en el angulo en
     que la tarjeta pasa mas tiempo. */
  --grosor: calc(var(--ancho) * .028);

  /* Los angulos del mouse. Los escribe js/inicio.js. En cero la
     tarjeta queda como la deje el vaiven, que es lo que pasa sin
     JavaScript y con prefers-reduced-motion. */
  --ry: 0deg;
  --rx: 0deg;
  --gx: 0;      /* la posicion cruda, solo para el halo del piso */

  position: relative;
  justify-self: center;
  width: var(--ancho);
  height: var(--alto);

  /* La perspectiva va en el contenedor y no en la tarjeta, igual
     que .escena en app.css. 1100px y no 1600: aca la tarjeta es
     mucho mas grande y con la perspectiva del dashboard el giro se
     ve casi ortografico, o sea de dibujo tecnico. */
  perspective: 1100px;
}

/* ---- EL VAIVEN, que no para nunca ----

   Existe por un problema que no es de gusto: si la tarjeta esta
   quieta, nadie sabe que reacciona al mouse. Un objeto que ya se
   esta moviendo pide que lo toquen.

   ---- POR QUE SON DOS CAPAS Y NO UN SOLO @keyframes ----

   La primera version era UNA animacion con diecisiete pasos: la
   curva del ocho muestreada punto por punto. Joel la vio y dijo
   "se mueve por tramos chiquitos, como tic, tic, tic".

   Tenia razon y la causa es aritmetica. Entre dos pasos el
   navegador interpola en LINEA RECTA, o sea a velocidad constante;
   en cada paso esa velocidad cambia de golpe. Diecisiete pasos son
   dieciseis saltitos de velocidad por vuelta, y aunque cada uno sea
   chico, el ojo lee la cadena entera como un traqueteo. Muestrear
   mas fino lo disimula pero no lo arregla: el problema no es la
   cantidad de puntos, es que la curva este hecha de rectas.

   La salida es no muestrear nada. Un ocho es una figura de
   Lissajous, o sea DOS oscilaciones simples cruzadas: el eje Y hace
   una y el eje X hace dos en el mismo tiempo. Escritas por
   separado, cada una es un ida y vuelta entre dos angulos, sin
   ningun punto intermedio que interpolar.

   `alternate` mas una curva simetrica de tipo ease-in-out da
   exactamente una sinusoide: velocidad cero en las puntas —donde un
   cambio brusco seria invisible porque no hay velocidad que
   cambiar— y maxima al cruzar el centro. Cero saltos, y de paso
   dieciseis renglones menos.

   El costo es una capa mas de anidamiento, y es inevitable: las dos
   oscilaciones usan transform y un elemento tiene uno solo.

   ---- LA VELOCIDAD ----

   El eje Y tarda 4,5s en ir de una punta a la otra, o sea 9s por
   ciclo completo, que es lo mismo que la version anterior: recorre
   30 grados y la tarjeta cambia 126px de ancho proyectado, muy por
   encima del umbral en que el ojo detecta movimiento. El eje X va
   al doble de rapido, y esa razon de 2 a 1 ES lo que dibuja el
   ocho. */
/* ---- ACA NO VA `will-change`, Y COSTO ENCONTRARLO ----

   Se lo puse para asegurar que la animacion corriera en el
   compositor, razonando que will-change: transform no aplana el 3D
   —y es cierto, no lo aplana—. Pero rompe otra cosa: le da a la
   capa su propio contexto de composicion, y a partir de ahi el
   `backface-visibility` de las caras se evalua contra la rotacion
   de esa capa en vez de contra la rotacion acumulada de todas.

   Consecuencia: pasados los 90 grados el navegador decidia que la
   cara de ATRAS tambien miraba para atras, y la tapaba. La tarjeta
   se quedaba en el aire, con las laminas del nucleo dibujando un
   rectangulo vacio.

   Y no se veia probando de a poco: hasta los 90 grados todo estaba
   perfecto. Solo aparece del otro lado.

   Es exactamente la familia del bug del backdrop-filter de la
   semana 5: **cualquier cosa que le de a un elemento de la cadena
   3D su propia capa de dibujo rompe el 3D de sus hijos.** La lista
   ya tenia filter, opacity, mask y overflow. Ahora tiene una mas, y
   esta es la traicionera, porque `will-change` se pone justamente
   creyendo que se esta ayudando.

   No hace falta igual: la animacion es una rotacion pura y los
   navegadores la componen solos. Se midio despues de sacarlo.

   ============================================================
   ---- Y LA LISTA LE FALTABA UNA MAS: LA ANIMACION MISMA ----

   El 2026-08-21, con Safari. El parrafo de arriba termina diciendo
   que no hace falta will-change porque "los navegadores la componen
   solos" — y componerla sola ES promover la capa. O sea que la
   pagina venia haciendo por su cuenta exactamente lo que ese
   comentario habia aprendido a no pedir.

   Sintoma: media tarjeta se volvia morado liso, con un corte en
   diagonal recta, moviendo el mouse rapido. Solo en Safari, solo un
   frame, y solo con el mouse — girando sola no pasa nunca, porque
   ahi no hay que recomponer.

   Habia TRES capas con transform animado anidadas dentro del
   preserve-3d: onda-y, onda-x y cuerpo. Ahora es UNA. Los dos
   vaivenes dejaron de ser capas y pasaron a ser dos angulos que se
   suman al del mouse en un solo transform.

   ---- POR QUE HACE FALTA @property ----

   Una custom property normal no interpola: pasaria de -23deg a 7deg
   de golpe. Registrada como <angle>, si. Eso es lo que permite tener
   el vaiven y el mouse en el mismo transform, que es lo que antes
   obligaba a separarlos en capas —un elemento tiene un solo
   `transform`, y el segundo le pisaba el primero—.

   Los valores tambien van declarados abajo como propiedades
   normales: sin soporte de @property el vaiven salta entre sus dos
   extremos en vez de romperse. Safari lo tiene desde la 16.4.

   ---- SI HAY QUE VOLVER ATRAS ----

   Las dos capas .plastico-onda-* siguen en el HTML y en el CSS, sin
   transform y sin animacion: asi no se promueven. Devolverles las
   dos lineas de `animation` y los keyframes al formato viejo
   restaura el montaje anterior sin tocar el marcado.
   ============================================================ */
@property --onda-y { syntax: "<angle>"; inherits: false; initial-value: -23deg; }
@property --onda-x { syntax: "<angle>"; inherits: false; initial-value: -1deg; }
/* Estas dos las escribe js/inicio.js sobre .plastico, asi que heredan
   hacia el cuerpo. Registrarlas es lo que permite TRANSICIONARLAS: la
   transicion se mudo del `transform` a los angulos, para que el mouse
   y el vaiven dejen de pelearse por la misma propiedad. */
@property --rx { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@property --ry { syntax: "<angle>"; inherits: true; initial-value: 0deg; }

/* Quedan como contenedores y nada mas. Sin transform y sin animacion
   NO se promueven a capa, que es justamente el arreglo. */
.plastico-onda-y,
.plastico-onda-x {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

/* Los angulos estan corridos hacia un lado a proposito: el centro
   del vaiven no es cero. Una tarjeta que pasa por el frente
   perfectamente plana se lee como una imagen pegada justo en el
   instante en que mas se la mira. */
@keyframes onda-y { from { --onda-y: -23deg; } to { --onda-y: 7deg; } }
@keyframes onda-x { from { --onda-x: -1deg; }  to { --onda-x: 11deg; } }

/* ---- LA ROTACION DEL MOUSE ----

   rotateX PRIMERO y rotateY despues, y el orden se nota: al reves,
   la inclinacion se aplicaria sobre el eje ya girado y la tarjeta
   cabecearia de costado al pasar de los 90 grados. Asi el giro es
   un plato giratorio con el eje vertical quieto, que es como uno
   espera que se comporte un objeto sobre una mesa. */
.plastico-cuerpo {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;

  /* El vaiven vive AQUI desde el 2026-08-21, en la misma capa que la
     rotacion del mouse. Los dos angulos se suman en un solo
     transform; antes eran dos capas mas, y cada capa animada se
     promueve y rompe el 3D de los hijos. Ver el bloque de arriba. */
  animation: onda-y 4.5s  cubic-bezier(.37,0,.63,1) infinite alternate,
             onda-x 2.25s cubic-bezier(.37,0,.63,1) infinite alternate;

  /* El cinturon para quien no tenga @property: sin registro estas
     dos no interpolan, pero al menos resuelven y la tarjeta se
     dibuja. El vaiven ahi salta entre sus extremos en vez de correr. */
  --onda-y: -23deg;
  --onda-x: -1deg;

  transform: rotateX(calc(var(--rx) + var(--onda-x)))
             rotateY(calc(var(--ry) + var(--onda-y)));
}

/* ---- LA TRANSICION VIVE EN LOS ANGULOS, NO EN EL TRANSFORM ----

   Estaba en `.plastico-cuerpo { transition: transform }` y se mudo
   aqui el 2026-08-21. La razon es la misma que colapso las capas: en
   el cuerpo ahora corre la animacion del vaiven, y animacion y
   transicion sobre la MISMA propiedad no se suman —la animacion
   gana—, asi que el seguimiento del mouse habria dejado de verse.

   Transicionando --rx y --ry, que son angulos registrados, cada cosa
   modifica lo suyo: la animacion mueve --onda-*, la transicion mueve
   --r*, y el transform los suma. Va sobre `.plastico`, que es donde
   js/inicio.js las escribe.

   Corto mientras el mouse manda: mas largo se siente pegajoso,
   porque el objetivo cambia sesenta veces por segundo y la tarjeta
   nunca lo alcanza. */
.plastico {
  transition: --rx .18s cubic-bezier(.2,.7,.3,1),
              --ry .18s cubic-bezier(.2,.7,.3,1);
}

/* Al salir el mouse la tarjeta vuelve sola y despacio, y ahi si se
   la ve girar por su cuenta desde donde haya quedado. Esos 0,9s son
   donde se nota si el objeto tiene peso. */
.plastico.volviendo,
.plastico.volviendo .plastico-piso {
  transition-duration: .9s;
  transition-timing-function: cubic-bezier(.16,.9,.28,1);
}

/* ---- LAS SEIS CARAS ----

   backface-visibility: hidden en las seis. En un solido cerrado eso
   no es un apaño: es lo que hace que en cada instante se dibujen
   solo las tres caras que miran hacia uno, que es exactamente lo
   que pasa con un objeto de verdad. */
.plastico-cara {
  position: absolute;
  backface-visibility: hidden;
}

/* ---- LAS ESQUINAS ----

   Vienen dibujadas DENTRO de las imagenes (radio de 40px sobre 1200
   de ancho, medido en el canal alfa), asi que el brillo tiene que
   recortarse igual o se le ve la punta cuadrada asomando.

   Va en porcentaje con dos valores —horizontal / vertical— y no en
   pixeles: 3,33% del ancho y 5,28% del alto dan el MISMO radio en
   pixeles mientras la proporcion sea 1,5852, o sea que la esquina
   sigue siendo un cuarto de circulo en cualquier tamano de
   pantalla. */
.plastico-frente,
.plastico-reverso,
.plastico-brillo { border-radius: 3.33% / 5.28%; }

.plastico-frente,
.plastico-reverso { inset: 0; }
.plastico-frente  { transform: translateZ(calc(var(--grosor) / 2)); }
.plastico-reverso { transform: rotateY(180deg) translateZ(calc(var(--grosor) / 2)); }

.plastico-cara img { display: block; width: 100%; height: 100%; }

/* ============================================================
   EL NUCLEO: EL GROSOR, HECHO DE LAMINAS

   ---- POR QUE NO SON CUATRO TIRAS ----

   La primera version tenia cuatro tiras planas —arriba, abajo,
   izquierda, derecha— y Joel encontro el agujero: "el grosor que le
   pusiste es recto, pero la tarjeta en las esquinas es curva,
   entonces se ve ese hueco en las esquinas".

   Exacto. Cuatro rectangulos planos se cruzan en angulo recto, y
   las caras tienen las esquinas redondeadas: en cada esquina queda
   un pedazo de canto que nadie tapa y se ve a traves de la tarjeta.
   No hay forma de arreglarlo con tiras: haria falta una superficie
   CURVA, y en CSS todo plano es plano.

   ---- LO QUE SI FUNCIONA ----

   Se corta el grosor en laminas, como un pan de molde: catorce
   copias del mismo rectangulo redondeado, apiladas en el eje Z de
   una punta a la otra del grosor. Cada lamina tiene LA MISMA curva
   que las caras, asi que la esquina queda cubierta por definicion y
   no hay nada que calzar.

   Catorce salen de una cuenta: el grosor son 11px, asi que quedan a
   0,85px una de otra. Vistas de canto se leen como una franja
   solida. Con la mitad se verian rayas.

   ---- VAN LLENAS, Y ANTES ERAN ANILLOS ----

   Primero fueron anillos —solo el borde— razonando que el relleno
   no se ve nunca: de frente lo tapa una cara, de atras la otra, y
   de canto solo se mira el perimetro. **Falso, y Joel lo vio:** "la
   tarjeta por su lado mas angosto se ve como que estuviera vacia,
   entonces se desaparece".

   El razonamiento fallaba en el caso limite. De canto, la lamina
   entera —borde Y relleno— se aplasta contra la misma franja de
   pixeles: el interior transparente cae encima del borde opaco y
   gana la transparencia. Catorce laminas casi transparentes apiladas
   siguen dejando ver el fondo. El canto no estaba hueco por las
   esquinas: estaba hueco por dentro.

   Llenas, cada lamina aporta pixeles opacos en toda su proyeccion y
   el canto queda solido. El precio es catorce rectangulos pintados
   por cuadro en vez de catorce contornos, y se paga: el hueco era
   justo el angulo que Joel queria arreglar desde el principio.

   ---- Y POR QUE NO LLEVAN backface-visibility ----

   Las caras se apagan cuando miran para el otro lado porque son la
   piel del objeto. Una lamina del nucleo se ve por los dos lados,
   igual que la miga del pan. Por eso no usan la clase .plastico-cara.
   ============================================================ */
.plastico-nucleo {
  position: absolute;
  inset: 0;
  border-radius: 3.33% / 5.28%;

  /* El color va de oscuro atras a claro adelante, no claro en el
     medio: la luz de esta escena cae desde el frente, asi que el
     filo de adelante es el que la recibe. --i lo escribe el HTML,
     de 0 (atras) a 13 (adelante), y con eso una sola regla dibuja
     el degradado entero del canto. */
  background: color-mix(in srgb,
    var(--canto-claro) calc(var(--i) * 100% / 13), var(--canto-oscuro));

  /* ---- LAS LAMINAS VAN ESTRICTAMENTE ADENTRO ----

     La cuenta era (i / 13 - .5), que reparte las catorce entre
     -grosor/2 y +grosor/2: o sea que la primera y la ultima quedan
     EXACTAMENTE en el mismo plano que las caras. Mientras eran
     contornos no molestaba; llenas, la lamina de adelante empata en
     Z con la cara de adelante, gana por venir despues en el
     documento, y la tarjeta se ve como un rectangulo morado liso.

     Con (i + .5) / 14 - .5 las catorce caen en el interior, a media
     ranura de cada cara. La diferencia es medio pixel y es la que
     decide si se ve la imagen o no. */
  transform: translateZ(calc(((var(--i) + .5) / 14 - .5) * var(--grosor)));
}

/* ---- EL BRILLO QUE SE DESPLAZA ----

   Una mancha de luz que se mueve por la superficie con el mouse. Es
   lo que separa un objeto de una foto de un objeto: la imagen trae
   su propio reflejo pintado y fijo, y un reflejo fijo es lo que
   delata que no hay nada ahi.

   Blanco plano y sin mezcla de capas, por lo dicho arriba. El
   plastico es oscuro en los dos temas —es una foto, no cambia con
   la piel— asi que un blanco al 26% alcanza y no se pasa. */
.plastico-brillo {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(42% 62% at
    calc(50% + var(--gx) * 42%) 38%,
    rgba(255,255,255,.26), rgba(255,255,255,.07) 42%, transparent 70%);
}

/* El reverso esta dado vuelta, asi que su izquierda es la derecha
   de la pantalla. Sin invertir el signo, el brillo se iria para el
   lado contrario al que va el mouse. Se invierte la CUENTA y no con
   un scaleX, que seria un transform mas adentro del contexto 3D. */
.plastico-reverso .plastico-brillo {
  background: radial-gradient(42% 62% at
    calc(50% - var(--gx) * 42%) 38%,
    rgba(255,255,255,.26), rgba(255,255,255,.07) 42%, transparent 70%);
}

/* ---- LO QUE LA TARJETA DEJA EN EL PISO ----

   Va FUERA del cuerpo, o sea fuera de la cadena 3D, y las dos cosas
   importan. Si fuera un drop-shadow de la tarjeta aplanaria el 3D;
   si fuera un box-shadow de una cara, giraria con ella, que es
   justo lo que una sombra no hace.

   Es un degradado y no un blur(): un filtro se recalcula en cada
   cuadro mientras la mancha se mueve; un radial-gradient se dibuja
   una vez y despues solo se traslada.

   La medida se ajusto mirando. El primer intento era una elipse
   chica pegada al borde de abajo y no se veia nada: el centro del
   degradado quedaba TAPADO por la tarjeta y solo asomaba la cola. */
.plastico-piso {
  position: absolute;
  left: -12%; right: -12%;
  top: 6%; bottom: -26%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(50% 50% at 50% 62%,
    rgb(var(--piso-tarjeta) / var(--piso-fuerza)),
    rgb(var(--piso-tarjeta) / calc(var(--piso-fuerza) * .36)) 45%,
    transparent 72%);
  transform: translate3d(calc(var(--gx) * -5%), 0, 0);
  transition: transform .18s cubic-bezier(.2,.7,.3,1);
}

/* Con menos movimiento el bloque de base.css deja las animaciones
   en 0,001ms y una sola vuelta, o sea que las dos ondas terminan de
   inmediato: la tarjeta quedaria de frente y perfectamente plana,
   como una imagen pegada. Se le devuelve a mano el angulo de reposo.

   Desde el 2026-08-21 se le da a los ANGULOS y no a las capas, que
   es donde vive el vaiven ahora. Los dos valores son los mismos de
   antes; lo que cambio es quien los recibe. */
@media (prefers-reduced-motion: reduce) {
  .plastico-cuerpo {
    --onda-y: -8deg;
    --onda-x: 5deg;
  }
}

/* ---- Bloques de contenido ----

   ---- POR QUE SE LLAMA .banda Y NO .tramo ----

   Se llamaba .tramo hasta la semana 9. El problema: en app.css
   .tramo es OTRA cosa —el nombre del tramo del semaforo, ese
   "Alto" que va debajo del numero grande— y lleva
   text-transform: uppercase. La landing carga las dos hojas, asi
   que desde que .tramo entro a app.css (semana 6, con la meta
   escalonada) TODA la pagina de inicio se estaba dibujando en
   mayusculas, y de paso heredando letter-spacing.

   No lo vio nadie porque nada se rompio: la pagina seguia
   entera, solo gritando. La leccion, que ya esta en CLAUDE.md
   con otras palabras: un archivo se ve bien solo cuando se mira
   con las hojas que de verdad va a cargar.

   El que se renombro fue este y no el de app.css porque "tramo"
   alla es una palabra del producto —los cuatro tramos de la
   regla 4— y ademas la escribe js/pintar.js. Aca era solo una
   franja de fondo, y banda es lo que es.

   ---- POR QUE LAS BANDAS Y POR QUE NO SON BLANCAS ----

   Una pagina larga de un solo color se lee como una sola cosa muy
   larga y cuesta ver donde termina un tema y empieza el otro. Las
   bandas alternadas resuelven eso.

   Lo que NO se puede es alternar oscuro y blanco: toda la piel esta
   armada para letra clara sobre fondo oscuro, y una banda blanca
   obligaria a invertir el texto, los botones, las sombras y el
   semaforo dentro de ella. Serian dos sistemas de diseño en una
   pagina. La alternancia va entre los dos oscuros que ya existen
   —el fondo y la superficie— que se distinguen bien porque uno es
   negro azulado y el otro tira a indigo.

   El truco de la sombra gigante es para que la banda llegue de
   borde a borde de la pantalla sin sacar la seccion del lienzo,
   que es lo que la mantiene alineada con el resto del texto. El
   clip-path corta esa sombra arriba y abajo para que no se
   desborde en vertical. */
.banda {
  position: relative;
  padding: var(--aire-tramo) 0;
  border-top: 1px solid var(--linea);
}

/* ---- EL CENTRADO, que Joel pidio mirando Stripe ----

   El diagnostico suyo fue exacto: "todo se ve como hacia la
   izquierda". Pasaba porque cada titulo llevaba max-width: 30rem
   pegado al borde, asi que en una pantalla ancha quedaba media
   pagina vacia a la derecha y la vista no tenia donde apoyarse.

   Lo que se centra es la CABECERA de cada seccion —el titulo y su
   bajada— y no el contenido de las cajas. Un parrafo largo
   centrado se lee peor: cada renglon empieza en un sitio distinto
   y el ojo tiene que buscar. Por eso las columnas, las listas y
   los planes siguen con su texto alineado a la izquierda, pero el
   BLOQUE entero va centrado en la pagina.

   El heroe queda fuera de esta regla, arriba explicado. Esa es la
   alternancia: abre a un lado, sigue centrado. */
.banda > h2,
.banda > .bajada,
.banda > .letra-chica {
  text-align: center;
  margin-inline: auto;
}
.banda > .bajada { max-width: 40rem; }
/* La letra chica de cierre de seccion respira mas: es el pie de un
   argumento, no la continuacion del parrafo anterior. */
.banda > .letra-chica { max-width: 44rem; margin-top: 2rem; }

/* ---- LA BARRITA DEL ACENTO, elegida por Joel el 2026-08-21 ----

   Una raya corta del color de la seccion, debajo de su titulo.

   ---- POR QUE HIZO FALTA, QUE NO ES LO QUE PARECE ----

   El alternado morado/naranja del pendiente 22 estaba montado desde
   el 2026-08-16: `.banda.oscura` redefine --acento al naranja y
   `.banda.clara` al morado, y hasta la excepcion de la cifra estaba
   escrita. Lo que nadie habia medido es si se VEIA, y no:

     banda 1 utilizacion   oscura ... 0 elementos con el acento
     banda 2 el cruce      clara .... 0
     banda 3 estrategias   oscura ... las vinietas de la lista
     banda 4 ingresos      clara .... 0
     banda 5 como funciona oscura ... los numeros de paso
     banda 6 precios       clara .... la cinta y el boton

   Tres de seis en cero, y las otras tres por casualidad: solo donde
   la seccion resulta tener listas o pasos. Habia un mecanismo sin
   nada que lo consumiera — que es la peor forma de "hecho", porque
   el codigo esta puesto y el pendiente parece cerrado.

   La barrita es el elemento CONSTANTE que faltaba: la lleva toda
   banda por tener un <h2>, sin depender de que adentro haya listas.

   ---- Y NO PUEDE SER OTRA COSA ----

   Tiene que ser decoracion. La regla del naranja prohibe pintar con
   el un chip, un estado o una cifra, porque esta a 4 grados de matiz
   de --cat-deuda. Una raya bajo un titulo de seccion no dice nada de
   la plata de nadie.

   Se probaron ademas el filo de color arriba de las tarjetas y los
   h3 en el acento; las dos metian el color DENTRO de las cajas,
   donde compite con el borde que ya tienen y, en "como funciona",
   se suma a los numeros gigantes que ya van del mismo color. */
.banda > h2::after {
  content: "";
  display: block;
  width: 3.2rem;
  height: 3px;
  border-radius: 2px;
  background: var(--acento);
  /* Centrada con `auto`, igual que el titulo que acompania. El
     margen de arriba la separa del texto sin despegarla: por debajo
     de 1rem se lee como un subrayado del titulo y no como una marca
     de seccion. */
  margin: 1.1rem auto 0;
}

/* ============================================================
   LAS BANDAS ALTERNAS — rehechas el 2026-08-16

   Antes alternaban dos oscuros casi iguales, con
   `:nth-of-type(even)`. Ahora alternan de verdad: una oscura con
   acento naranja y la siguiente CLARA con acento morado.

   ---- POR QUE AHORA SI SE PUEDE ALTERNAR CON CLARO ----

   En la semana 5 se descarto, y con razon: "toda la piel esta
   armada para letra clara sobre fondo oscuro, y una banda blanca
   obligaria a invertir texto, botones, sombras y semaforo dentro de
   ella. Serian dos sistemas de diseno en una pagina."

   El argumento se cayo solo cuando el tema claro se construyo
   entero: **el segundo sistema ya existe y se usa a diario**. La
   banda clara no inventa ni un color — lleva `data-tema="claro"` y
   hereda las dieciocho variables que base.css ya tenia escritas.
   Por eso este bloque es corto: casi todo el trabajo lo hace un
   atributo en el HTML.

   ---- LA CLASE VA EN EL HTML Y NO ES `nth-of-type` ----

   `nth-of-type` contaba tambien el `<section class="heroe">`, asi
   que "par" no queria decir lo que parecia y agregar una seccion en
   el medio invertia media pagina sin que nadie lo pidiera. Con la
   clase escrita, cual banda es clara se lee en el HTML.
   ============================================================ */

/* ---- La banda CLARA ----

   El color sale de `--fondo`, que dentro de esta seccion ya es el
   claro porque el atributo redefinio la paleta. No hay ni un hex
   escrito aca: cambiar el tema claro en base.css cambia estas
   bandas tambien.

   Sigue el mismo truco de sangrado de siempre —box-shadow enorme
   recortado con clip-path— porque es el unico que llega de borde a
   borde SIN generar desborde horizontal. Un `margin-inline` con
   `50vw` seria mas corto y volveria a traer el bug del scroll de
   lado: `100vw` incluye la barra de desplazamiento y `100%` no. */
.banda.clara {
  /* ---- SANGRA CON MARGIN Y NO CON BOX-SHADOW ----

     El resto de la hoja sangra con `box-shadow: 0 0 0 100vmax` +
     `clip-path`, que era el unico truco que no generaba scroll
     lateral. Aca no sirve, y ese fue el hallazgo del dia: **un
     box-shadow con spread se infla en las cuatro direcciones, asi
     que rellena justo el hueco que deja una silueta curva.** Con el
     shadow puesto, la curva de abajo simplemente no existia.

     Con `overflow-x: clip` en el body —arriba de esta hoja— el
     desborde deja de importar, asi que la banda puede medir el ancho
     real de la ventana y quedarse con su forma. El `padding-inline`
     devuelve el contenido a la columna del lienzo. */
  margin-inline: calc(50% - 50vw);
  padding-inline: calc(50vw - 50%);

  background: var(--fondo);
  border-top-color: transparent;

  /* LA FORMA. Una elipse muy ancha y muy baja: 50% del ancho por
     3rem de alto. A lo largo de 1200 px eso no se lee como una
     esquina redondeada sino como una curva suave de lado a lado,
     que es lo que Joel pidio. */
  border-radius: 50% / 3rem;
  /* El acento vuelve a ser el morado de marca, que es el que se ve
     bien sobre claro. */
  --acento: var(--acento-boton);

  /* ---- ESTA LINEA NO ES REDUNDANTE, Y COSTO ENCONTRARLA ----

     Sin ella los titulos salian BLANCOS sobre el fondo claro, o sea
     invisibles, aunque `--tinta` aca ya valia el color oscuro.

     El motivo es que `color` se hereda **como valor ya computado**.
     `body` resolvio `var(--tinta)` una sola vez, con la paleta
     oscura, y lo que heredan los hijos es el resultado —#ededed— y
     no la variable. Redefinir `--tinta` en un ancestro intermedio no
     vuelve a resolver nada: solo afecta a las reglas que la
     mencionan de nuevo.

     Por eso hay que RE-DECLARAR la propiedad heredada donde cambia
     la paleta. Las que sí se recalculan solas son las que aparecen
     escritas en alguna regla —`color: var(--suave)` de las bajadas,
     los bordes, los fondos— porque esa declaracion se evalua con las
     variables del elemento donde aplica.

     Vale para cualquier propiedad heredada que se pinte desde una
     variable. Aca la unica es `color`. */
  color: var(--tinta);
}

/* Dentro de una banda clara las cajas suben un escalon: si la caja
   y su banda son del mismo color, la caja desaparece y la banda
   deja de servir para nada. */
.banda.clara .columna,
.banda.clara .lado { background: var(--superficie-alta); }

/* ---- La banda OSCURA: el acento pasa a naranja ----

   ---- ESTO NO ROMPE LA REGLA DEL NARANJA, Y CONVIENE VER POR QUE ----

   La regla dice que el naranja no puede aparecer "en un chip, un
   estado ni una cifra". Las tres cosas son DATOS sobre la plata de
   la persona, y el riesgo es que se confunda con `--cat-deuda`, que
   esta a cuatro grados de matiz.

   En la landing no hay ningun dato de nadie: los numeros que se ven
   estan dentro de las capturas, que son imagenes y no leen ninguna
   variable. Lo que se pinta aca son bordes, titulos de seccion y
   botones, o sea controles y decoracion.

   Y la proteccion de fondo sigue en pie: esta regla vive en
   `inicio.css`, la hoja que el dashboard NO carga, asi que el
   naranja no puede llegar a un chip de la aplicacion aunque alguien
   lo escriba aqui. */
.banda.oscura {
  --acento: var(--naranja);
}

/* La UNICA excepcion, y esta escrita porque el pendiente 22 la
   dejo avisada: `.lado.verdad .cifra` es una CIFRA, y ahi la regla
   del naranja aplica entera. Se le devuelve el morado a mano.
   Hoy ese bloque no esta en el HTML, pero la regla se queda: si
   vuelve, vuelve protegido. */
.banda.oscura .lado.verdad .cifra { color: var(--acento-boton); }

/* ---- LA COSTURA ENTRE BANDAS ----

   Joel: "que exista una fluidez entre secciones, tal vez con
   degradados no rectos, sino con formas".

   ---- LO QUE NO SE PUDO HACER, Y POR QUE, PARA NO REINTENTARLO ----

   El primer intento fueron dos pseudo-elementos con `border-radius`
   eliptico asomando por fuera de la banda. **No funciona, y son dos
   choques distintos:**

     * el `clip-path: inset(0 -100vmax)` que da el sangrado recorta
       a la caja EN VERTICAL, asi que todo lo que asome arriba o
       abajo desaparece;
     * y si se le da aire vertical al clip, el `box-shadow` del
       sangrado —que se infla en las cuatro direcciones— rellena
       justamente el hueco que la curva acababa de dejar.

   O sea que **el sangrado por box-shadow y una silueta curva son
   incompatibles**: uno pinta un rectangulo inflado y la otra
   necesita que ese rectangulo tenga una mordida. Para curvas de
   verdad la banda tendria que sangrar de otra forma —ancho real de
   viewport con un `overflow-x: clip` en un contenedor que no
   contenga el heroe— y eso es un cambio de estructura, no de color.

   ---- LO QUE SI SE HACE ----

   La costura es un degradado vertical del color de la banda que
   deja, desvaneciendose sobre la que llega. No es una linea recta
   ni un corte: son 5rem en las que un color se convierte en el
   otro, y a la vista se lee como que las secciones se funden.

   Va DENTRO de la caja (`top: 0`, sin asomar) para no chocar con el
   clip vertical, y con `left`/`right` en -100vmax, que el clip SI
   permite a los lados. Asi la costura llega de borde a borde de la
   pantalla igual que la banda. */
.banda.clara::before,
.banda.clara::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 4rem;
  pointer-events: none;
  /* El degradado va con la curva, no en vez de ella: la curva
     resuelve la silueta y esto difumina el ultimo milimetro del
     encuentro, que si no se lee como un filo. */
}

/* Arriba: entra desde el oscuro de la banda anterior. */
.banda.clara::before {
  top: 0;
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--fondo-pagina) 55%, transparent), transparent);
}

/* Abajo: vuelve al oscuro de la siguiente. */
.banda.clara::after {
  bottom: 0;
  background: linear-gradient(to top,
    color-mix(in srgb, var(--fondo-pagina) 55%, transparent), transparent);
}

/* El contenido, por encima de las dos costuras. */
.banda.clara > * { position: relative; }

/* El cierre lleva su propio resplandor: es el ultimo empujon de la
   pagina y merece verse distinto de los tramos de en medio. */
.cierre {
  position: relative;
  background:
    radial-gradient(60% 80% at 50% 0%,
      color-mix(in srgb, var(--acento) 16%, transparent), transparent 70%);
}

.banda h2 {
  font-size: var(--t-titulo);
  letter-spacing: -.025em;
  line-height: 1.15;
  /* ---- ESTE ANCHO SE MIDIO DOS VECES ----

     Primero se puso en 22rem para obligar a los titulos a partirse
     en dos renglones cortos. Se vio en pantalla y estaba mal: los
     titulos de la landing ya traen su propio <br> escrito a mano
     —puesto en la semana 5, donde termina la idea, que es donde
     parte un subtitulo— y 22rem le agregaba un corte MAS. "El
     numero de tu resumen / no es lo que debes" salia en tres
     renglones desiguales.

     Con 30rem el <br> es el unico corte de los titulos que lo
     traen, y los que no lo traen los reparte text-wrap: balance,
     que ya viene de base.css. O sea: el corte lo decide quien
     escribe la frase, y el CSS no le discute. */
  max-width: 30rem;
}
.banda .bajada { font-size: var(--t-bajada); }

/* ---- POR QUE 3 COLUMNAS FIJAS Y NO auto-fit ----

   Con auto-fit y un minimo de 17rem, en una ventana de tamanio
   medio caben dos y la tercera cae sola a un renglon nuevo: queda
   un 2+1 con medio renglon vacio a la derecha. En una lista de
   caracteristicas se aguanta; en los PASOS numerados es un error,
   porque un 1-2 arriba y un 3 abajo se lee como si el tercero fuera
   de otra cosa.

   Las dos secciones que usan esto tienen exactamente tres hijos, y
   tres es 3 o es 1, nunca 2+1. Debajo de 900px se apilan los tres,
   que en telefono es lo correcto de todas formas. */
.columnas {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.5rem;
  margin-top: 3rem;
  /* Sin esto, tres columnas en una pantalla de 1900px se estiran a
     600px cada una y el texto queda en renglones de 90 caracteres,
     que es el doble de lo comodo. Con el tope, el bloque se centra
     debajo del titulo centrado. */
  max-width: 62rem;
  margin-inline: auto;
}

.columna {
  padding: var(--aire-caja);
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-radius: var(--curva);
  box-shadow: var(--sombra);
  /* ---- EL HOVER, acelerado ----
     Joel: "tarda como medio segundo y es bastante tosco". Medido, el
     dibujo va a 63 fps, asi que no era falta de maquina: eran los
     tiempos. .2s con la curva `ease` reparte la velocidad por igual
     y se siente blando. Ahora .14s con una curva que arranca de
     golpe y frena al final, que es como se mueve algo que responde.
     Y el desplazamiento sube de 3 a 4 pixeles: si el movimiento es
     muy corto, acortar el tiempo hace que directamente no se lea. */
  transition: border-color .14s cubic-bezier(.16,.8,.3,1),
              box-shadow   .18s cubic-bezier(.16,.8,.3,1),
              transform    .14s cubic-bezier(.16,.8,.3,1);
}
.columna:hover {
  border-color: color-mix(in srgb, var(--acento) 55%, var(--linea));
  box-shadow: var(--sombra-alta);
  transform: translateY(-4px);
}
.columna h3 { font-size: var(--t-bajada); font-weight: 640; margin-bottom: .65rem;
              letter-spacing: -.015em; }
.columna p  { color: var(--suave); font-size: var(--t-cuerpo); line-height: 1.6; }

/* El numerito de cada paso. Es un contador de CSS y no un numero
   escrito en el HTML: reordenar los pasos no obliga a renumerar. */
/* ---- EL NUMERO DEL PASO, rehecho en la semana 9 ----

   Antes era una bolita de color arriba a la izquierda con el titulo
   debajo. Joel: "se ve horrible el titulo debajo del numero". Tenia
   razon y la causa era estructural: la bolita ocupaba su renglon,
   asi que empujaba el titulo hacia abajo y dejaba la caja con tres
   alturas distintas de contenido (bolita, titulo, parrafo) que no se
   alineaban con nada.

   Ahora el numero NO ocupa lugar: es una marca de agua gigante
   pegada al fondo del recuadro, y el texto vive encima como si el
   numero no existiera. Es lo que pidio, y de paso resuelve el
   problema real —el numero deja de competir por el espacio del
   titulo—.

   Tres decisiones para que no estorbe:

   1. Va con position:absolute y aria/pointer apagados, o sea fuera
      del flujo: el texto se coloca igual que si la caja estuviera
      vacia.
   2. Se DESVANECE hacia abajo con un mask, para que el borde
      inferior del numero no forme una linea dura debajo del
      parrafo.
   3. La opacidad es distinta por tema. En oscuro un 8% de blanco se
      ve; en claro el mismo valor sobre superficie blanca desaparece
      del todo, asi que sube. Es la misma leccion de los degradados
      de los baldes en la semana 6. */
.pasos { counter-reset: paso; }

.pasos .columna {
  position: relative;
  overflow: hidden;          /* el numero se recorta contra la caja */
  text-align: center;        /* pedido: el texto centrado en el recuadro */
  padding-top: 2.5rem;

  /* ---- POR QUE HAY UN ALTO MINIMO, desde el 2026-08-16 ----

     Joel pidió que el número vaya "desde el borde de arriba hasta el
     de abajo". Para que un tamaño fijo llegue justo a los dos bordes,
     los recuadros tienen que medir siempre lo mismo — y no lo hacían.
     Medido antes de tocar: 234 px con tres columnas, 200 en teléfono,
     y en la franja de 620 a 760 los tres tenían **alturas distintas
     entre sí** (149, 175 y 175), porque ahí van apilados y nada los
     estira.

     Con esto, todos miden al menos 232 y el número de abajo cae
     clavado en cualquier ancho. La alternativa era una media query
     con un tamaño por tramo, que es la que deja el problema esperando
     en el ancho siguiente — la lección del pendiente 23. */
  min-height: 14.5rem;
}

.pasos .columna::before {
  counter-increment: paso;
  content: counter(paso);
  /* ---- EL NUMERO, DE BORDE A BORDE Y PEGADO A LA DERECHA ----

     Pedido de Joel el 2026-08-16: "que llegaran completo desde el
     borde de arriba hasta el de abajo y que estuvieran pegados al
     borde derecho del recuadro, con una fuente que se vea
     tecnológica, pero manteniéndolos por debajo del texto así
     difuminados".

     `inset: 0` cubre la caja de relleno entera, o sea de borde a
     borde por dentro — que es exactamente el marco que él nombró. El
     grid centra el número en vertical y lo empuja al final en
     horizontal, sin depender de que el alto de línea cuadre. */
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center end;

  /* ---- LA FUENTE ----

     Monoespaciada del sistema: es lo que se lee como "tecnológico" y
     no descarga nada. Instrument Sans está solo en titulares y el
     proyecto no baja fuentes de terceros nunca — eso le mandaría la
     IP del usuario a Google, y la política de privacidad afirma que
     no hay rastreadores.

     Y trae un regalo que una proporcional no da: TODOS LOS DIGITOS
     MIDEN LO MISMO. Medido: 60,2 px de avance para el 1, el 2 y el 3
     a 100 px de cuerpo. Los tres números caen en la misma columna sin
     que nadie los alinee a mano. */
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* ---- EL TAMANIO SALE DE UNA MEDICION, Y SE MIDIO EL 3 ----

     Medido en el navegador con `actualBoundingBox`, no estimado. Y la
     primera cuenta salió mal por medir el dígito equivocado: **los
     tres números no miden lo mismo de alto**. El 1 ocupa 0,729 em,
     pero el 2 llega a 0,741 y el 3 a 0,757, porque las curvas se
     dibujan un poco fuera de la línea justamente para que el ojo las
     vea del mismo tamaño que las rectas.

     Con el 1 como referencia el archivo quedó en 19.9rem y **el 3 se
     salía 9 px**, recortado arriba y abajo por el `overflow`. La
     cuenta correcta usa el más grande: 232 / 0,757 = 306 px, o sea
     19,1rem. Ahí entran los tres. */
  font-size: 19.1rem;
  line-height: 1;
  font-weight: 700;

  /* El `letter-spacing` de un solo carácter se aplica DESPUES del
     glifo, así que empuja el número hacia la izquierda separándolo
     del borde. Con un dígito suelto no hay nada que espaciar. */
  letter-spacing: 0;

  /* ---- Y EL MARGEN NEGATIVO TAMBIEN SE MIDIO ----

     La tinta de un dígito monoespaciado no llena su avance: queda una
     banda muerta a cada lado, y sin compensarla "pegado al borde
     derecho" se vería con un dedo de aire que nadie pidió.

     Pero esa banda **no es igual en los tres**: 14, 25 y 20 px a este
     cuerpo. Con un solo valor no se pueden dejar los tres flotando
     exactamente sobre el borde, así que se usa el MENOR —el del 1— y
     no el promedio. Con el promedio, el 1 se salía 6 px y el
     `overflow` le comía el costado; con el mínimo, el 1 queda clavado
     al borde y los otros dos entran 5 y 10 px, que a este tamaño y al
     11% de opacidad no los distingue nadie.

     La regla: entre recortar y dejar aire, aire. Un número recortado
     se lee como un error; uno con tres píxeles de margen, no se lee
     de ninguna manera. */
  margin-right: -.047em;

  color: var(--acento);

  /* ---- DIFUMINADO HACIA EL TEXTO, que es lo que se pidió ----

     La opacidad plana ya no alcanza: el número pasa de 7rem a casi
     20 y cubre el recuadro entero, así que a la misma intensidad
     empieza a pelear con el párrafo. La máscara lo deja fuerte
     contra el borde derecho —donde no hay nada escrito— y lo apaga
     antes de llegar al texto, que va centrado.

     Es un degradado LINEAL sobre un color plano, no una máscara
     redonda sobre una textura: el bandeo que costó cuatro intentos
     con la linterna aparecía porque un círculo de opacidad sobre una
     retícula tiene siempre un radio donde se ve el aro. Acá no hay
     radio ni textura debajo. Aun así va con tres paradas y no dos,
     para que la caída no tenga un codo. */
  -webkit-mask-image: linear-gradient(to right,
    transparent 0%, rgba(0,0,0,.35) 46%, #000 100%);
  mask-image: linear-gradient(to right,
    transparent 0%, rgba(0,0,0,.35) 46%, #000 100%);

  opacity: .11;
  pointer-events: none;
  user-select: none;
}

/* En el tema claro el mismo valor sobre superficie blanca casi no
   existe. Es la misma leccion de los degradados de los baldes en la
   semana 6: un porcentaje de opacidad no vale lo mismo en los dos
   temas y hay que medirlo en los dos. */
/* Sin `:root`, por lo mismo que el bloque de la paleta en base.css:
   asi vale tanto cuando la pagina entera es clara como cuando solo
   lo es la banda que contiene estos pasos. */
[data-tema="claro"] .pasos .columna::before { opacity: .15; }

/* El contenido, por encima de la marca de agua. */
.pasos .columna h3,
.pasos .columna p { position: relative; z-index: 1; }

/* ---- La comparacion del bug de las cuotas ----
   Es el argumento mas fuerte que tiene el producto, asi que va con
   los dos numeros uno al lado del otro y no en un parrafo. */
.contraste {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: 1.5rem;
  margin-top: 3rem;
  max-width: 52rem;
  margin-inline: auto;
}

/* ---- POR QUE ESTOS DOS LADOS YA NO SON ROJO Y VERDE ----

   Lo reporto Joel en la semana 9: "lo leo como que uno es malo y el
   otro es bueno". Y no era una impresion suya, era un error de
   verdad, mas grave que el de gusto:

   --malo y --bueno son los colores del SEMAFORO. En toda la app,
   rojo significa "tu utilizacion esta critica" y verde "vas bien".
   Aca el numero pintado de VERDE era el 80%, que es justamente la
   utilizacion que la app pinta de ROJO tres pantallas mas adelante.
   O sea que la landing le enseniaba al usuario un codigo de color
   que el producto contradice apenas entra.

   Ahora el par no es bueno/malo sino APAGADO / ENCENDIDO: la cifra
   que engania va en gris, con su caja mas tenue; la cifra cierta va
   en el acento de la marca y con el borde vivo. Se sigue leyendo
   cual de las dos manda, sin decir que 80% sea una buena noticia.

   El hover es el mismo de .columna, pedido por Joel: una caja de
   esta pagina no puede reaccionar de dos maneras distintas segun la
   seccion. */
.lado {
  padding: var(--aire-caja);
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-left: 4px solid var(--linea);
  border-radius: var(--curva);
  /* ---- EL HOVER, acelerado ----
     Joel: "tarda como medio segundo y es bastante tosco". Medido, el
     dibujo va a 63 fps, asi que no era falta de maquina: eran los
     tiempos. .2s con la curva `ease` reparte la velocidad por igual
     y se siente blando. Ahora .14s con una curva que arranca de
     golpe y frena al final, que es como se mueve algo que responde.
     Y el desplazamiento sube de 3 a 4 pixeles: si el movimiento es
     muy corto, acortar el tiempo hace que directamente no se lea. */
  transition: border-color .14s cubic-bezier(.16,.8,.3,1),
              box-shadow   .18s cubic-bezier(.16,.8,.3,1),
              transform    .14s cubic-bezier(.16,.8,.3,1);
}
.lado:hover {
  border-color: color-mix(in srgb, var(--acento) 55%, var(--linea));
  box-shadow: var(--sombra-alta);
  transform: translateY(-4px);
}
/* El hover del acento no puede pisar el borde izquierdo, que es el
   que distingue los dos lados. Se vuelve a fijar despues. */
.lado.falso,  .lado.falso:hover  { border-left-color: var(--linea); }
.lado.verdad, .lado.verdad:hover { border-left-color: var(--acento); }
/* La caja del dato que engania va un punto mas apagada que la otra:
   la jerarquia la hace el contraste, no el color. */
.lado.falso { opacity: .82; }
.lado.falso:hover { opacity: 1; }
.lado small    { display: block; color: var(--suave); font-size: var(--t-etiqueta);
                 text-transform: uppercase; letter-spacing: .09em; }
.lado .cifra   { display: block; margin-top: .5rem; font-size: var(--t-cifra);
                 font-weight: 700; letter-spacing: -.03em; line-height: 1; }
.lado.falso  .cifra { color: var(--suave); }
.lado.verdad .cifra { color: var(--acento); }
.lado p { margin-top: .85rem; color: var(--suave); font-size: var(--t-cuerpo);
          line-height: 1.6; }

/* ---- Lista de lo que NO hace ----
   El bloque va centrado en la pagina; el texto de cada punto, no.
   Un renglon de lista centrado obliga a buscar donde empieza el
   siguiente. */
.lista-limpia { list-style: none; padding: 0; margin: 3rem auto 0;
                display: grid; gap: 1.1rem; max-width: 44rem; }
.lista-limpia li { display: flex; gap: .8rem; font-size: var(--t-cuerpo);
                   line-height: 1.6; }
.lista-limpia li::before { content: "—"; color: var(--acento); flex-shrink: 0; }

/* ---- LA MISMA LISTA, PERO DENTRO DEL HEROE ----

   .lista-limpia esta pensada para el medio de la pagina: centrada,
   con 3rem de aire arriba y 44rem de ancho. En el heroe es una
   columna de texto alineada a la izquierda, dos puntos cortos y
   pegada al parrafo que la explica, asi que hay que deshacer las
   tres cosas.

   Es una variante y no una lista nueva porque el marcado y el guion
   de adelante son los mismos: dos listas distintas que se ven igual
   se separan solas con el tiempo.

   ---- SE BORRO el 2026-08-16 ----

   Joel quitó los dos puntos del héroe: "demasiado texto y son cosas
   que se pueden explicar más abajo". La regla se va con ellos porque
   `.hitos` no la usaba nadie más —se comprobó con un grep antes de
   borrarla— y un selector que no aplica a nada es peor que uno
   feo: el día que alguien escriba esa clase creyendo que existe algo,
   se lleva un estilo que nadie diseñó para su caso.

   Si vuelven, eran: margin 1.4rem arriba, max-width 34rem (el ancho
   de `.bajada`), gap .6rem, `--t-chico` en `--suave`, y el `strong`
   en `--tinta`. */

/* ---- EL SUBTITULO QUE PARTE UNA BANDA EN DOS ----

   Lo trajo la segunda version del estudio y resuelve algo real: la
   seccion de privacidad son DOS cosas —los tres pasos del mes y los
   cuatro "no"— y sin nada en el medio la lista de abajo se leia como
   una continuacion de los pasos. Con el rotulo, cada mitad se sabe
   que es.

   Es la version chica de un h2, no un h3 de columna: por eso va en
   mayusculas y con espaciado, que es como esta piel marca los
   rotulos, y no en el tamano de un titulo. */
.sub-banda {
  margin: 3.5rem 0 0;
  font-size: var(--t-etiqueta);
  font-weight: 640;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--suave);
}
/* Pegado a lo que rotula: si el bloque de abajo trae su propio aire,
   el rotulo queda flotando entre las dos mitades sin pertenecer a
   ninguna. */
.sub-banda + .columnas,
.sub-banda + .lista-limpia { margin-top: 1.25rem; }

/* ---- LOS TITULOS DE LAS CAJITAS VAN CENTRADOS ----

   Pedido de Joel el 2026-08-16. Solo el TITULO, no el parrafo: la
   cabecera de cada seccion ya va centrada desde la semana 9 por el
   mismo motivo —"todo se ve como hacia la izquierda"— y las cajitas
   eran lo unico que seguia empezando pegado al borde.

   El parrafo TAMBIEN va centrado, corregido el 2026-08-16 a pedido
   de Joel. La regla de "un parrafo largo centrado se lee peor" vale
   para parrafos largos; estos son de tres o cuatro renglones dentro
   de una caja angosta, y ahi un titulo centrado sobre un texto a la
   izquierda se lee como un descuido. */
.columna h3,
.columna p { text-align: center; }

/* Los dos rotulos que parten la seccion de privacidad en dos. Van
   centrados sobre lo que rotulan, no alineados a la izquierda. */
.sub-banda { text-align: center; }


/* ============================================================
   LAS CAPTURAS DE LA APLICACIÓN

   Son pantallas reales del producto, no ilustraciones. Por eso el
   marco es discreto: un borde de 1px y una sombra. Todo lo que se
   le agregue —una barra de navegador falsa, un reflejo, una
   perspectiva— compite con lo que hay que mirar, que son los
   números de adentro.

   ---- POR QUE 62rem Y NO EL ANCHO DEL LIENZO ----

   Es el mismo ancho máximo que `.columnas`, o sea que una captura
   ocupa exactamente lo que ocupa el bloque de texto de tres puntos
   que va debajo. Con eso la página mantiene un solo borde
   izquierdo y derecho de arriba abajo, que es la mitad de lo que
   hace que se vea ordenada.

   ---- EL FONDO SE CONTINÚA, NO SE CORTA ----

   Las capturas se tomaron sobre el mismo `--fondo` de la
   aplicación, que es casi el de la landing. Un borde muy tenue y
   nada de fondo propio: la imagen se funde con la página en vez de
   quedar como un recorte pegado encima.
   ============================================================ */
/* ---- LAS CAPTURAS VAN A SANGRE, SIN MARCO ----

   Decisión de Joel del 2026-08-16, en la segunda vuelta. Antes esto
   llevaba `border`, `border-radius` y `box-shadow`, y las tres se
   fueron juntas por dos razones:

   1. Las capturas se toman sobre el --fondo de la aplicación, que es
      casi el de la landing. Sin marco, la imagen se funde con la
      página y se lee como si la app estuviera empotrada ahí; con
      marco se leía como un recorte pegado encima.
   2. EL PUENTE TENÍA DOS MARCOS. Ese módulo trae su propia franja de
      color redondeada —es lo que dice si alcanza o no— y el borde de
      acá le quedaba por fuera a ocho píxeles, concéntrico. Dos
      rectángulos redondeados casi iguales no se leen como un marco:
      se leen como un error de dibujo. Es la misma lección del
      contorno del número: un trazo tiene que verse deliberado o no
      verse.

   Lo que reemplaza al marco es el aire de adentro de la propia
   captura: herramientas/capturas.html fotografía cada bloque con el
   mismo margen lateral que .lienzo le da al contenido en la app.

   La regla de `overflow: clip` también se fue con el radio: sin
   esquinas redondeadas no hay nada que recortar. */
.captura {
  margin: 3rem auto 0;
  max-width: 62rem;
}

/* La imagen no arrastra el renglón de abajo: sin `display:block` un
   <img> es texto y deja el hueco del descenso de la letra, que se ve
   como un borde inferior más grueso. */
.captura img { display: block; width: 100%; height: auto; }

/* ---- ACÁ IBA .captura.cuadrada, y su porqué dejó de valer ----

   Decía: "la de utilización es casi cuadrada y a 62rem quedaría más
   alta que la pantalla", y la achicaba a 44rem.

   El problema es que achicar es exactamente lo que rompía la
   legibilidad. Esa captura se toma a 868px de ancho y la landing la
   muestra a 804, o sea a 0,93x: la letra de adentro se lee. Metida
   en 44rem (704px) volvería a 0,81x, que es la escala de la que Joel
   se quejó.

   Sigue siendo la más alta de las cinco —858px en escritorio— y eso
   ahora es a propósito: son cuatro paneles y hay que poder leerlos.
   Si algún día molesta, la salida NO es encogerla sino fotografiar
   menos paneles, que es justo lo que hace la versión de teléfono. */

/* Pegada al texto que la explica, no flotando entre dos secciones. */
.captura + .letra-chica { margin-top: 1.5rem; }

/* ---- Los planes ----

   Dos columnas y no tres. Con tres, la de en medio existe nada mas
   para que la cara se vea barata, y aca no hay tres planes: hay uno
   gratis que sirve de verdad y uno que quita los limites.

   Se apoyan en .columna (misma caja, mismo hover) y solo agregan lo
   que un plan necesita: el precio grande, la lista y el destaque.
   Asi una caja de la landing reacciona igual en toda la pagina. */
.planes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  gap: 1.5rem;
  margin: 3rem auto 0;
  max-width: 46rem;
  /* align-items: stretch por defecto: las dos cajas quedan del mismo
     alto aunque una tenga tres renglones mas. Dos planes de distinto
     alto se leen como si uno estuviera a medio terminar. */
}

.plan { display: flex; flex-direction: column; position: relative; }

/* El destacado NO cambia de tamano ni se sale de la fila: solo se
   marca con el borde del acento. Agrandarlo obliga a que el otro se
   vea recortado, y el plan gratis no es un plan de segunda. */
.plan-destacado {
  border-color: color-mix(in srgb, var(--acento) 60%, var(--linea));
  box-shadow: var(--sombra-alta);
}

.plan-cinta {
  position: absolute; top: -.65rem; left: 1.5rem;
  padding: .15rem .55rem;
  border-radius: 999px;
  background: var(--acento-boton); color: #fff;
  font-size: var(--t-etiqueta); font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em;
}

.plan-precio {
  margin-top: .7rem;
  font-size: var(--t-cifra); font-weight: 700;
  letter-spacing: -.03em; line-height: 1;
}
/* El "al año" no puede competir con la cifra: es la unidad, no el
   dato. */
.plan-precio small { font-size: var(--t-cuerpo); font-weight: 500; color: var(--suave); letter-spacing: 0; }

/* ---- CON LA COLUMNA DELANTE, o la regla no hace nada ----

   `.plan-nota` sola es 0-1-0 y pierde contra `.columna p`, que es
   0-1-1 y le pone `var(--t-cuerpo)`. Medido el 2026-08-17: salia a
   16px teniendo escrito 14. Es la tercera vez que este proyecto paga
   la misma trampa —las otras dos fueron `.descargo` contra
   `.documento p` (pendiente 20) y `.plan-o`, aca abajo— y las tres
   veces el sintoma fue el mismo: la regla se carga, se lee bien y no
   aplica. Se comprueba con el valor computado, no leyendo el archivo. */
.columna p.plan-nota,
.plan-nota { margin-top: .6rem; color: var(--suave); font-size: var(--t-chico);
             line-height: 1.55; }

/* La segunda forma de pagar. Separada de la nota del anual por una
   linea, para que se lean como dos opciones y no como una frase
   larga. El "o" en minuscula y en gris; el precio, en tinta. */
/* Con `.columna` delante por lo mismo que `.plan-nota`: sin eso salia
   a 16px. Se encontraron juntas y se arreglan juntas — buscar quien mas
   comparte el truco es la regla que dejo la prueba 7 de sql/42. */
.columna p.plan-o,
.plan-o {
  margin-top: .85rem; padding-top: .85rem;
  border-top: 1px solid var(--linea);
  color: var(--suave); font-size: var(--t-chico);
}
.plan-o strong { color: var(--tinta); font-weight: 650; }

.plan ul {
  list-style: none; padding: 0;
  margin: 1.5rem 0 0;
  display: grid; gap: .7rem;
  font-size: var(--t-cuerpo);
  line-height: 1.5;
}
.plan li { display: flex; gap: .55rem; }
/* La palomita va como texto y no como imagen ni SVG: es un caracter
   que traen todas las tipografias de sistema, incluidas las de
   Windows. Misma razon por la que las banderas del mazo son
   caracteres y no archivos. */
.plan li::before { content: "✓"; color: var(--bueno); flex-shrink: 0; font-weight: 700; }

/* ---- LOS BOTONES, A LA MISMA ALTURA ----

   Joel: "que el boton no quede al mismo nivel lo hace ver
   desprolijo". Y no era que faltara la regla: estaba puesta y
   ANULADA. `margin-top: auto` es lo que empuja el boton al fondo de
   su tarjeta, pero justo debajo habia un
   `.plan ul + .como-boton { margin-top: 1.5rem }` que, por venir
   despues y ser mas especifico, le pisaba el auto con un valor fijo.
   El boton quedaba pegado a la lista en vez de al fondo, y como una
   lista tiene seis puntos y la otra cuatro, cada uno terminaba a una
   altura distinta.

   El aire entre la lista y el boton ahora lo pone la lista con su
   margen de abajo, que no compite con nada. */
.plan .como-boton { margin-top: auto; width: 100%; text-align: center; }
.plan ul { margin-bottom: 1.5rem; }

/* ---- Cierre ---- */
.cierre { text-align: center; padding: 4rem 0; }
.cierre .acciones { justify-content: center; }
.cierre .bajada { margin-inline: auto; }

/* La reticula es una capa fija que cubre la pantalla entera, asi
   que tambien asomaba detras del pie. Joel pidio que no se vea ahi:
   el pie es el cierre de la pagina y no necesita profundidad. Un
   fondo opaco la tapa; va con el token y no con un hex para que
   siga a la piel. */
/* El pie se MUDO a base.css el 2026-08-16. Lo usan ahora tambien
   terminos.html y privacidad.html, que solo cargan esa hoja: antes
   esas dos cerraban con un enlace "Volver" suelto y ahora llevan el
   pie completo, que es lo que Joel pidio. Un pie no es adorno de la
   landing — es la salida de la pagina, y las tres la necesitan. */

@media (max-width: 620px) {
  /* En telefono la segunda columna no cabe al lado; se apila debajo
     y los enlaces quedan pegados al borde izquierdo, como todo lo
     demas de la pagina en ese ancho. */
  .pie { grid-template-columns: 1fr; }
}

/* Los tres pasos apilados antes de que se vean apretados. 900px y no
   720 porque a 800 cada columna mide 15rem y el titulo de dos
   palabras ya se parte en tres renglones. */
@media (max-width: 900px) {
  .columnas { grid-template-columns: 1fr; max-width: 32rem; }
}

@media (max-width: 720px) {
  /* El aire se mide en pantallas, no en centimetros: 6rem de respiro
     que en escritorio se ven generosos, en un telefono son un tercio
     de la pantalla en blanco y obligan a hacer scroll para descubrir
     que hay una seccion mas. Se toca el token y baja todo junto, que
     es la ventaja de haberlo puesto en un solo sitio. */
  .lienzo { --aire-tramo: 3.5rem; --aire-caja: 1.5rem; }

  .heroe { padding: 2.5rem 0 1.5rem; gap: 2rem; }

  /* En telefono no hay mouse, asi que de todo el efecto queda solo
     el vaiven —que corre igual, es CSS— y ese es justamente el que
     importa aca: es lo unico que le dice a alguien con el dedo que
     la tarjeta esta viva. El giro con el cursor no se pierde: no
     existia. */
  .plastico { --ancho: 18rem; margin-bottom: 2.5rem; }

  /* "Podría dejarse la tarjeta moviendo levemente pero sin dar
     vuelta, que se vea solo la cara frontal." El vaiven de
     escritorio ya se queda muy lejos de los 90 grados, asi que el
     reverso no aparecia igual; lo que se baja aca es la amplitud,
     porque en una pantalla angosta la tarjeta ocupa casi todo el
     ancho y 30 grados de balanceo se leen como un cabeceo de barco.
     Queda la mitad: se nota que respira y no se va a ninguna
     parte. */
  @keyframes onda-y { from { --onda-y: -13deg; } to { --onda-y: 2deg; } }
  @keyframes onda-x { from { --onda-x: 1deg; }   to { --onda-x: 8deg; } }

  /* ACA VIVIA EL PARCHE DE LA MANCHA DEL TITULO, y se fue el
     2026-08-16. Decia `inset: -2rem -1rem` para que el derrame no
     se saliera de la pantalla en telefono.

     Arreglaba 375 px y dejaba roto el tramo de 721 a 799, donde el
     bloque tambien ocupa el ancho entero pero esta media query ya
     no aplica. O sea que no resolvia el bug: lo mudaba al ancho de
     al lado, y ahi vivio hasta que aparecio medindo otra cosa.

     La regla de arriba ya no derrama a la derecha, asi que no hay
     nada que recortar en ningun ancho y este bloque sobra. Si
     alguna vez vuelve a hacer falta un ajuste aca, la pregunta
     correcta es por que la regla base no se sostiene sola. */

  /* EL HALO SE METE PARA ADENTRO, Y ESTO ES UN BUG ARREGLADO, no
     un ajuste de gusto. En escritorio el halo sobresale un 12% a
     cada lado de la tarjeta, que es lo que lo hace verse. En un
     telefono la tarjeta ya ocupa casi todo el ancho, asi que ese
     12% caia FUERA de la pantalla: medido en 375px, el documento
     media 386 y la landing entera se podia arrastrar de lado.
     Un desborde horizontal no rompe nada visible —por eso no se
     ve mirando— y se nota como que la pagina "se mueve rara". */
  .plastico-piso { left: 0; right: 0; }

  .acciones > * { flex: 1; text-align: center; }
}


/* ============================================================
   EL ENCABEZADO, INTEGRADO AL HEROE — 2026-08-16

   Joel: "que el header no se vea como una barra separada, sino que
   parezca que todo esta en la misma pantalla del Hero".

   La barra la define app.css y ahi esta bien: en el dashboard flota
   sobre contenido que se desplaza debajo, asi que necesita fondo
   propio, desenfoque y una linea que la separe. En la landing eso
   sobra — arriba del todo no hay nada que se le meta debajo, y la
   linea partia la pantalla justo donde el heroe tiene que sentirse
   entero.

   Se le quitan las tres cosas SOLO aca.

   El `backdrop-filter` se quita ademas por un motivo tecnico: crea
   su propia capa de dibujo, que es lo que aplana un contexto 3D
   —la lista de la semana 9— y la tarjeta del heroe vive a pocos
   pixeles de aca. */
.lienzo-encabezado .barra,
body > .barra {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: none;
}

/* ---- Y DEJA DE VIAJAR CON LA PAGINA — 2026-08-17 ----

   Joel: "los botones de iniciar sesión y crear cuenta siguen pasando
   por encima de texto o imágenes de la landing al bajar. Igual que
   el logo. Mejor no lo dejes pegado arriba al bajar".

   ---- POR QUE ABRIRLO HACIA AFUERA NO ALCANZO ----

   El dia anterior el riel paso de 76rem a 88rem para sacar el logo y
   los botones de la columna del contenido. Ayuda en pantalla ancha y
   **no podia arreglar esto**, porque el problema no es horizontal:
   la barra es `sticky` y aca su fondo es transparente —justamente
   por el bloque de arriba—, asi que el contenido se ve desfilando
   por debajo del logo y de los botones. Dos decisiones que por
   separado estaban bien y juntas producian esto.

   Con `static` la barra se queda arriba del documento y se va con el
   scroll. No hace falta ningun `scroll-margin-top` en las anclas:
   eso hace falta cuando una barra fija tapa el destino, y ahora no
   hay ninguna.

   VA SOLO EN LA LANDING. Las pantallas con sesion conservan la suya
   pegajosa, y ahi si sirve: son tableros largos donde la navegacion
   tiene que estar siempre a mano. Por eso el selector es
   `body > .barra` y no `.barra`. */
body > .barra {
  position: static;
}
/* Un renglon que no se puede partir. Lo usa el titulo de las
   estrategias: Joel lo quiere en DOS lineas exactas —"Reparte tu
   ingreso" arriba y el resto abajo— y sin esto el navegador partia
   la segunda mitad en dos, dejando tres.
   Va con `text-wrap: nowrap` y no con &nbsp; entre cada palabra
   porque el nbsp tambien impide que se parta en el telefono, donde
   SI tiene que poder hacerlo. */
.renglon-firme { white-space: nowrap; }
@media (max-width: 620px) { .renglon-firme { white-space: normal; } }

/* El titulo de las estrategias necesita mas ancho que los demas: su
   segunda mitad mide 33 caracteres y el max-width de 30rem que
   sirve al resto la partia en dos, dejando el titulo en tres
   renglones. Se ensancha SOLO ese, con :has, en vez de aflojar el
   maximo de todos —que es el que mantiene los titulos en dos
   renglones cortos y legibles. */
.banda h2:has(.renglon-firme) { max-width: min(40rem, 100%); }

/* ---- EL ENCABEZADO SE ALINEA CON EL LIENZO ----

   Joel: "no está alineado con el logo y el botón de Entrar del
   header". Medido a 1425 px: el contenido de la página empieza en
   129 y el del encabezado en 24. Son 105 px de desfase.

   La causa es que `.barra` ocupa el ancho de la VENTANA y lleva su
   propio `padding: .85rem 1.5rem`, mientras todo lo demás vive
   dentro de `.lienzo`, que se topa en 76rem y se centra. Mientras la
   ventana fue más angosta que el lienzo los dos coincidían en 24 px
   —por eso no se veía— y a partir de ahí se separan.

   El fondo de la barra tiene que seguir llegando de borde a borde,
   así que no se le pone `max-width`: lo que se alinea es su
   CONTENIDO, con un padding que reproduce la cuenta del lienzo.

   El `max()` es lo que mantiene el caso angosto: cuando la ventana
   mide menos que el lienzo, la resta da negativo y gana 1.5rem, que
   es exactamente lo que había antes. */
/* ---- Y DESDE EL 2026-08-16 SE ABREN HACIA AFUERA ----

   Alinearlos con el lienzo arregló el desfase, pero los dejó en la
   MISMA columna que el contenido: la barra es pegajosa, así que al
   bajar, el logo y los botones pasan justo por encima del titular y
   de las capturas. Joel: "pasan por encima de los textos e imágenes
   de la landing [...] podrían abrirse más hacia afuera para que no
   interrumpan el contenido".

   Entonces el riel de la barra pasa a 88rem contra los 76rem del
   lienzo: 6rem hacia afuera de cada lado en pantalla ancha, que es
   margen vacío, y el contenido queda libre por debajo.

   El `max()` sigue sosteniendo el caso angosto igual que antes:
   cuando la ventana mide menos que el riel, la resta da negativo y
   gana 1.5rem. O sea que en teléfono no cambia nada. */
.barra {
  padding-inline: max(1.5rem, calc((100% - 88rem) / 2 + 1.5rem));
}

/* Los dos botones de la barra no se parten nunca. "Crear cuenta"
   salia en dos renglones apenas la ventana se angostaba, y un boton
   de dos lineas dentro de una barra de una no se lee como un boton
   angosto: se lee como algo roto. */
.barra-fin .como-boton { white-space: nowrap; }

/* ---- EL PIE SE ABRE LO MISMO, Y NO ES DECORACION ----

   "Igualmente habría que abrir el footer para que queden alineados
   header y footer". Si solo se abriera la barra, los dos extremos
   verticales de la página dejarían de coincidir, que es justo el
   desfase que se arregló hace dos semanas.

   Para eso el pie salió de `<main class="lienzo">` en index.html: ahí
   dentro no podía pasar de 76rem sin márgenes negativos y cuentas
   con `100vw` —que además incluyen la barra de desplazamiento y
   habrían dejado los dos desalineados por 7 px—. Afuera, las dos
   reglas miden contra el mismo `100%` del body.

   ---- LOS DOS NUMEROS SON EL MISMO RIEL, ESCRITO DE DOS FORMAS ----

   La barra pinta de borde a borde y mete su contenido con padding;
   el pie es una caja que se centra. Por eso uno dice 88rem y el otro
   85rem: 85 = 88 − 3, que son los 1.5rem de aire de cada lado. Con
   eso los bordes coinciden EXACTAMENTE en todos los anchos, no
   aproximadamente. Comprobado en la cuenta a 120rem, 88rem, 80rem y
   40rem antes de escribirlo.

   SI SE MUEVE UNO HAY QUE MOVER EL OTRO, y la diferencia son 3rem. */
body > .pie {
  width: min(85rem, 100% - 3rem);
  margin-inline: auto;
  /* El aire de abajo lo daba `.lienzo` con su padding de 5rem. Fuera
     de él hay que ponerlo, o el pie queda pegado al borde. */
  padding-bottom: 5rem;
}

/* Debajo de 720 la barra baja su aire a 1rem (más abajo en este
   mismo archivo), así que el pie tiene que bajarlo con ella o los
   dos se separan justo en el teléfono. */
@media (max-width: 720px) {
  body > .pie { width: min(85rem, 100% - 2rem); }
}

/* Debajo de 720 el lienzo baja su padding a 1rem (app.css), asi que
   el minimo del max() de arriba tiene que bajar con el o el
   encabezado queda 8 px por dentro. Medido: era el unico desfase
   que quedaba, en 320 y 375. */
@media (max-width: 720px) {
  .barra { padding-inline: 1rem; }
}
