/* Benny The Artist — field, face, type
   Palette measured from Benny's own portrait: #D00202 red, black, white, grey. */

:root{
  color-scheme: light;

  --red:    #D00202;
  --ink:    #0B0B0B;
  --paper:  #FAFAF8;
  --grey:   #8E8E8E;
  --grey-d: #3A3A3A;

  --field: var(--red);
  --on-field: var(--paper);
  --hair: color-mix(in srgb, var(--on-field) 26%, transparent);


  --display: "Bricolage Grotesque", Georgia, serif;
  --body:    "Familjen Grotesk", "Segoe UI", sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, monospace;

  /* ── el revelado ────────────────────────────────────────────────────
     La pagina va en BLANCO Y NEGRO. Este es el interruptor, y es uno solo:
     todo lo que lleva fotografia de Benny compone su propio filtro con
     var(--revelado) delante.

     Se hace asi y no repitiendo `grayscale(1)` en cada regla porque filter NO
     se acumula entre reglas -- la que gana pisa a la otra -- asi que una hoja
     que quisiera devolver el color tendria que volver a escribir la luz de
     cada pieza: el brillo del pliegue de la camiseta, la sombra de la funda,
     el revelado del seso. Con la variable, /version solo tiene que cambiar
     esta linea.

     El valor "en color" es opacity(1), un filtro que no hace nada, y no una
     cadena vacia: `filter:` con nada delante de la coma es sintaxis invalida
     en algunos motores y la regla entera se cae. */
  --revelado: grayscale(1);

  --ease: cubic-bezier(.22,1,.36,1);
  --pad: clamp(1rem, 3.2vw, 2.75rem);
  --edge: clamp(1rem, 3.125vw, 60px);   /* the reference runs a 60px margin at 1920 */
}

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

/* scroll-padding-top y no scroll-margin en cada ancla: son seis destinos hoy y
   el generador escribe mas cada vez que se regenera la tienda. Puesto en el
   contenedor de scroll vale para todos, incluidos los que aun no existen.

   --barra-alta lo mide app.js sobre la barra pegajosa de verdad. No es una
   constante: son 63px con las pildoras en una fila y 118 cuando se parten en
   dos. El +1rem es el aire entre el canto de la barra y el titulo que aterriza.
   Sin esto, "Camisas" dejaba su titulo 96px POR DEBAJO de la barra que lo tapa. */
html{
  -webkit-text-size-adjust:100%; scroll-behavior:smooth; scrollbar-width:none;
  scroll-padding-top:calc(var(--barra-alta, 4rem) + 1rem);
}

/* El bloqueo de scroll de los paneles. Uno solo para el menu y para el carrito;
   window.Benny.lock lleva la cuenta. En <html> y no en <body>: overflow en body
   crea contenedor de scroll y mata el position:sticky del hero. */
html.is-lock{ overflow:hidden; }
html::-webkit-scrollbar, body::-webkit-scrollbar{ width:0; height:0; display:none; }

body{
  margin:0;
  min-height:100svh;
  font-family:var(--body);
  font-size:clamp(1rem, .95rem + .25vw, 1.125rem);
  line-height:1.5;
  color:var(--on-field);
  background:var(--field);
  transition:background-color .55s var(--ease), color .55s var(--ease);
  overflow-x:clip;      /* `hidden` crea contenedor de scroll y mata el sticky */
}

/* screen-print grain, so the red is never a dead flat fill */
.grain{
  position:fixed; inset:0; z-index:60; pointer-events:none;
  opacity:.14; mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'>\
<filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/>\
<feColorMatrix type='saturate' values='0'/></filter>\
<rect width='180' height='180' filter='url(%23n)'/></svg>");
}

a{ color:inherit; }
:where(a,button,[tabindex]):focus-visible{
  outline:3px solid var(--on-field); outline-offset:4px; border-radius:2px;
}

/* ── curtain ─────────────────────────────────────────────── */
.curtain{
  /* Fondo plano, sin grano ni degrade: en la referencia el azul es #1D213E
     exacto, desviacion 0.00, y no cambia de tono en ningun frame. Aqui el
     campo es el rojo de la marca. */
  position:fixed; inset:0; z-index:90;
  background:var(--red); color:var(--paper);
  transition:transform .9s var(--ease);
}
/* ── Preloader ──────────────────────────────────────────────────────────
   Dice el nombre entero. El "The" va rotando por CINCO tipografias, y la A de
   ARTIST no es una letra: es la cara de Benny recortada por el contorno del
   glifo, con los ojos cambiando mientras carga.
   La entrada por letra es la de la referencia, leida de su CSS critico:
       .logo-part { transform: translateY(110%) }
   o sea el glifo sube desde debajo de su propio recorte. */
.pre{ position:absolute; inset:0; display:grid; align-content:center;
      justify-items:center; gap:.4svh; padding:0 var(--edge); }
.pre__line{ display:flex; align-items:flex-end; overflow:hidden; line-height:0; }
.pre__line--artist{ display:flex; align-items:flex-end; }
.pre__w{ display:block; height:var(--u); width:auto; fill:var(--paper); }
.pre{ --u:clamp(3.2rem, 13svh, 9rem); }

/* El bloque del "The": las cinco variantes ocupan el MISMO sitio y solo se ve
   una. Ancho fijo para que el cambio de tipografia no empuje la linea: las hay
   de 143 a 248 unidades de ancho, y sin esto el nombre saltaria en cada cambio. */
.pre__line--the{ position:relative; display:grid; place-items:center;
  height:calc(var(--u) * .58); width:calc(var(--u) * 1.75);
  background:var(--paper); border-radius:2px; }
.pre__the{ grid-area:1/1; height:74%; width:auto; fill:var(--red);
  display:block; opacity:0; }
.pre__the.is-on{ opacity:1; }

/* La A ES la cara. Sin recorte de glifo: se ve su silueta de sticker, con el
   borde deckled, igual que en el hero. Ancho = el natural de la placa. */
.pre__A{ position:relative; display:block; height:var(--u);
  width:calc(var(--u) * 1332 / 1546); }
.pre__face{ position:absolute; inset:0; }
.pre__plate{ position:absolute; inset:0; width:100%; height:100%;
  object-fit:contain; opacity:0; }
.pre__plate.is-on{ opacity:1; }
/* los ojos solo mandan en la cara en reposo: una mueca ya trae los suyos */
.pre__eye{ position:absolute; width:27.027%; height:14.489%; top:49.288%;
  opacity:0; }
.pre__face.is-rest .pre__eye{ opacity:1; }
.pre__eye--l{ left:21.471%; } .pre__eye--r{ left:51.502%; }
.pre__eye img{ position:absolute; inset:0; width:100%; height:100%; opacity:0; }
.pre__eye img.is-on{ opacity:1; }

.pre__num{ position:absolute; left:var(--edge); bottom:6svh;
  font-family:var(--display); font-weight:800; font-size:clamp(2rem,7svh,4.5rem);
  line-height:1; color:var(--paper); }
/* La referencia lleva contador Y barra: <div class="progress_bar"><div
   class="progress_bar_fill">. Se copia. */
.pre__bar{ position:absolute; left:var(--edge); right:var(--edge); bottom:4svh;
  height:2px; background:color-mix(in srgb, var(--paper) 30%, transparent); }
.pre__bar i{ display:block; height:100%; width:0; background:var(--paper);
  transition:width .25s var(--ease); }

@media (prefers-reduced-motion:reduce){ .pre__bar i{ transition:none; } }

.curtain.is-up{ transform:translateY(-101%); transition-delay:.5s; }

/* ── top bar ─────────────────────────────────────────────── */
.bar{
  /* Measured off the reference: the header rests at 39.44% of the viewport
     height, holds still for the first 40px of scroll, then rides up 1:1 with
     the page and pins at y=40. No fade - it is visible from the first frame.
       headerY = 39.44svh - clamp(scrollY - 40, 0, 39.44svh - 40)
     --hy carries the clamped travel; app.js owns it. */
  position:fixed; left:0; right:0; top:39.44svh; height:60px; z-index:1;
  translate:0 var(--hy, 0px);
  padding:0 var(--edge);
  display:flex; align-items:center; gap:1rem;
  font-size:.94rem; letter-spacing:.02em;
}
/* .bar__mark / .bar__status / .bar__shop se fueron con el header viejo: hoy la
   barra son .pastilla y .burger, y ninguna de las tres esta ya en el HTML. */

/* ── stage ───────────────────────────────────────────────── */
/* The reference hero is 150% of the viewport (measured live: 1392px on 928).
   The head is pinned inside it and rises as you scroll that first stretch. */
.stage{
  position:relative;
  --alto-cara:128.85svh;
  /* El escenario acaba DONDE ACABA LA CARA. La cabeza ocupa 2.68svh de
     margen + 128.85 de alto = 131.53svh; con 150 fijos sobraban 18.5svh de
     campo rojo entre el menton y el blanco, y la cara quedaba flotando en vez
     de apoyada. El menton esta al 99.94% del alto de la imagen, asi que el
     corte del escenario cae justo en la barbilla. */
  min-height:calc(var(--top-cara, 2.68svh) + var(--alto-cara));
  overflow:clip;
}

.wordmark{
  position:absolute; left:var(--edge); right:var(--edge); top:var(--edge);
  margin:0; z-index:1;
  display:block; width:auto;
}
/* An SVG with a viewBox is the only way to guarantee the fill at every width:
   BEN is anchored to the left edge, NY to the right, so the gap the head sits
   in is whatever is left over — it never depends on font metrics. */
/* Cada letra vive en su propio recorte fijo y el glifo SUBE desde abajo.
   Medido en la referencia: opacidad 1.0 desde el primer pixel (no se funde
   nunca), deriva horizontal de 0.01 px en 44 frames, y lo primero que asoma es
   la barra de la T entera de golpe por el filo inferior del recorte - o sea un
   recorte por letra, no un barrido lateral.
   Desfase 51.5 ms, uniforme, y el espacio entre palabras NO consume turno: ese
   numero es robusto y se autoverifica (la letra predicha aparece donde toca).
   La curva y la duracion NO se pudieron determinar: cuatro ease-out empatan
   dentro del 6% y exigen duraciones de 1.17 s a 2.03 s. Se elige una del
   empate que reproduce los hitos medidos por letra: 50% a los 220 ms, 90% a
   los 627 ms, 99% a los 1023 ms. */
.ltr__in{ transform:translateY(var(--rise)); }
.is-lettering .ltr__in{
  transform:translateY(0);
  transition:transform 1.4s var(--ease) var(--d);
}
@media (prefers-reduced-motion:reduce){
  .ltr__in{ transform:none; }
  .is-lettering .ltr__in{ transition:none; }
}

.wordmark svg{ display:block; width:100%; height:auto; overflow:visible; }
.wordmark text{
  font-family:var(--display); font-weight:800;
  font-variation-settings:"wdth" 78;
  letter-spacing:-.045em; fill:currentColor;
}

/* The canvas is a FACE, not a head: hairline to moustache, crown and chin both
   outside the frame. That is what the reference does too - its top edge is a torn
   paper edge above the brow, not a crown, and its chin is below the fold.
   Why it has to be that way: the only reproducible number on the reference is the
   rendered eye separation, 315.0px on a 928px viewport = 33.94svh. Benny's pupils
   sit 400px apart on the source photograph, so the canvas can be at most
   400 / (0.3394/0.79) = 931px tall. His crown is 909px above the eye line - it
   does not fit, and no crop can make it fit. Height is the anchor; the WIDTH is
   free (it cancels out of the eye-separation maths) and is set for framing only. */
.face{
  /* La cabeza es MAS ALTA QUE LA VENTANA, como la de la referencia: el menton
     cae por debajo del fold. Medido alli: en el 9% del alto no hay un solo
     pixel de cabeza, y en el 88% la cabeza todavia mide 701px de ancho - la
     linea que se daba por "menton" cae sobre el bigote.
     Alto tal que la separacion entre ojos de 311.7px en pantalla, que es lo que
     mide la referencia (33.6% del alto de ventana). */
  position:absolute; z-index:2;
  left:50%; top:var(--top-cara, 2.68svh);
  height:var(--alto-cara); width:auto;
  aspect-ratio:1332/1546;
  /* Se traslada 1:1 con el scroll, o sea se va con la pagina. Lo que habia
     antes (subir 25svh al bajar) era invencion mia: la referencia no lo hace. */
  translate:calc(-50% + var(--tx, 0px)) var(--ty, 0px);
  filter:drop-shadow(0 1.25rem 2rem rgb(0 0 0 / .34));
  pointer-events:none;
}
/* The eye patches sit exactly where the eyes are in the head picture. The patches
   themselves never changed; only the canvas under them did. It was cropped to
   x 57..1183, y 350..1281 of the old 1240x2000 plate, so the pupil centres moved
   (420,828),(820,828) -> (363,478),(763,478) of 1126x931, patch still 360x224.
   The swap is a hard cut - the reference selects its tile with floor() and
   its dead-zone texture with step(), and neither of those fades. */
.eye{ position:absolute; width:34.535%; height:20.699%; top:46.184%; pointer-events:none; }
.eye--l{ left:17.718%; }
.eye--r{ left:47.748%; }
.eye img{ position:absolute; inset:0; width:100%; height:100%; opacity:0; }
.eye img.is-on{ opacity:1; }

/* Aqui vivia el sistema "peel" -- la hoja que se despegaba por una esquina,
   con su reflejo sobre la linea de pliegue y su sombra. Lo movia peel.js, y
   peel.js no lo carga ningun <script> desde hace varios commits: eran 124
   lineas de JS y 40 de CSS animando algo que no llegaba nunca al navegador.
   Fuera las dos. Si vuelve el efecto, vuelve entero desde git. */

.head{ display:block; width:100%; height:100%; object-fit:contain; }


/* With the panel open the header has to climb above it, or the only way out is
   the Escape key. The reference does exactly this: a second header at z-index
   301 over a z-index 302 panel, pinned at y=40. */
.is-menu-open .bar{
  /* The pin runs through translate, not `top`: it composites instead of
     relaying out the fixed bar on every frame, and it reuses the same --hy the
     scroll law already drives, so the two can never disagree about where the
     header is. app.js owns --hy. */
  z-index:310;
  color:var(--paper);
  transition:translate .5s var(--ease), color .4s var(--ease);
}

/* ── burger ──────────────────────────────────────────────────────────────
   48x48 in the header, hard against the right margin (the reference runs the
   same box). Three lines that fold into an X on open. */
.burger{
  margin-left:auto; width:48px; height:48px; flex:0 0 48px;
  display:grid; place-items:center; gap:0;
  background:none; border:0; padding:0; cursor:pointer; color:inherit;
}
.burger__box{ position:relative; width:25px; height:14px; }
.burger__line{
  position:absolute; left:0; width:100%; height:2px; background:currentColor;
  transition:translate .4s var(--ease), rotate .4s var(--ease), opacity .2s linear;
}
.burger__line:nth-child(1){ top:0; }
.burger__line:nth-child(2){ top:6px; }
.burger__line:nth-child(3){ top:12px; }
.burger:hover .burger__line:nth-child(1){ translate:0 -2px; }
.burger:hover .burger__line:nth-child(3){ translate:0 2px; }

.is-menu-open .burger__line:nth-child(1){ translate:0 6px; rotate:45deg; }
.is-menu-open .burger__line:nth-child(2){ opacity:0; }
.is-menu-open .burger__line:nth-child(3){ translate:0 -6px; rotate:-45deg; }
.is-menu-open .burger:hover .burger__line{ translate:0 6px; }
.is-menu-open .burger:hover .burger__line:nth-child(3){ translate:0 -6px; }

/* ── the menu ────────────────────────────────────────────────────────────
   The reference does NOT fade this in. It wipes it down from the top edge
   with clip-path, measured exactly:
     clip-path: inset(0% 0% 100%)  ->  inset(0% 0% 0%)
     transition: clip-path .9s cubic-bezier(.645, 0, 0, 1)
   The colours are Benny's, not the reference's navy. */

/* ── el pie ───────────────────────────────────────────────────────────────
   NEGRO, no rojo. Antes era exactamente el mismo rgb(208,2,2) que la seccion
   "Quien es Benny" de encima -- medido -- con una raya de 1px entre las dos: no
   habia frontera, el pie parecia el final de esa seccion. En negro hay corte, y
   ademas el recorrido cierra por donde abrio (el escaparate tambien es negro).

   Y SIN opacidad en el contenedor. La que habia (.75) caia tambien sobre
   "Llevate una", o sea sobre la unica accion del pie: lo mas grande de la
   pagina era lo que menos se leia. Ahora la transparencia esta solo donde toca,
   en la linea legal. */
.foot{
  position:relative; z-index:2; overflow:clip;
  background:var(--ink); color:var(--paper);
  padding:clamp(3.5rem,9vw,6.5rem) var(--edge) clamp(7.5rem,15vw,12rem);
  display:grid; justify-items:start;
  gap:clamp(1.8rem,4.5vw,3rem);
}

/* ── el revelado, aplicado ────────────────────────────────────────────────
   Todo lo que es FOTOGRAFIA DE BENNY pasa por --revelado. Las fotos de
   PRODUCTO no: son la obra que se vende, y ensenar en gris una camiseta que
   llega roja no es un tratamiento grafico, es una foto que miente sobre lo que
   estas comprando. Por eso .pz__foto y .tv__foto se quedan fuera a proposito.

   Las caras de la caja (.c--dorso, .c--der...) tampoco: son var(--ink) sobre
   var(--ink), o sea negro, y el gris no tiene nada que hacer con ellas.

   OJO: nada de esto puede ir sobre .o3d ni sobre .o3d__cuerpo. Un elemento con
   filter pierde el preserve-3d de sus hijos, las seis caras se pintan por orden
   del DOM, el dorso tapa al frente y -- al ir al 42% de brillo -- el objeto
   entero se ve NEGRO. Esta escrito tambien arriba, en el bloque de .o3d,
   porque ya paso una vez. */
.head,
.eye img,
.tapa img,
.pre__plate,
.pre__eye img,
.o3d--cuadro .c--frente img{
  filter:var(--revelado);
}

/* El retrato del "Quien es Benny" NO entra en el revelado, y es a proposito.
   Ese archivo ya viene revelado de origen: la cara en grises y LAS GAFAS EN
   ROJO, que es la foto tal como el la firma. Estaba en la lista de arriba y
   grayscale(1) le apagaba las gafas -- lo unico con color de toda la pieza y
   justo lo que la hace suya. Un filtro que borra el sujeto no es un filtro.

   Y no hace falta para nada: el resto de la foto ya es gris en el propio
   pixel, asi que en la web principal se ve igual con filtro o sin el. La
   diferencia son las gafas. */

/* Las piezas que salen del craneo se encienden a color cuando las eliges: con
   el raton encima, con el foco del teclado, al tocarlas, o cuando el carrusel
   del telefono las tiene puestas (.is-ct lo pone carrusel.js).

   Basta con cambiar la VARIABLE en la pieza: las propiedades personalizadas se
   heredan, asi que la imagen del cuadro, la funda y las veinte lamas de la
   camiseta la recogen solas, cada una conservando su propia luz. Antes esto
   eran ocho reglas repitiendo el brillo de cada cosa. */
.o3d{ transition:filter .38s var(--ease) }
.o3d:hover,
.o3d:focus-visible,
.o3d:active,
.o3d.is-ct{ --revelado:opacity(1) }

/* ── narrow ──────────────────────────────────────────────── */
@media (max-width:820px){
  .wordmark{ font-size:clamp(4.5rem, 26vw, 12rem); top:clamp(4rem,11vh,6rem); }
  .wordmark__a{ margin-right:clamp(2rem, 34vw, 9rem); }
  /* the third term is the width budget: the canvas is now landscape (1126/931),
     so height alone would push it off a phone. 92vw * 931/1126 = 76vw. */
  .stage{ --alto-cara:min(58svh, 26rem, 96vw); }
  .rail{ bottom:calc(var(--pad) + 6.5rem); font-size:1.35rem; }
  .stage__line{
    left:var(--pad); right:auto; text-align:left;
    bottom:calc(var(--pad) + 2.6rem); max-width:26ch; font-size:1rem;
  }
  .bar__status{ display:none; }
}

@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{ animation-duration:.001ms !important; transition-duration:.001ms !important; }
}


/* ── header + rail states, driven by app.js off the measured thresholds ── */

/* Social rail: the reference pins five icons bottom-right and never moves them
   (measured: y=828 of 928 = 89% vh, right edge 60px in, at every scroll stop). */
.rail-social{
  position:fixed; right:var(--edge); bottom:6.2svh; z-index:40;
  display:flex; gap:.6rem; align-items:center;
}
.rail-social a{
  width:44px; height:44px; border-radius:50%;
  border:1px solid color-mix(in srgb, var(--on-field) 42%, transparent);
  display:grid; place-items:center; color:var(--on-field);
  transform:scale(0);
  transition:transform .6s var(--ease) .6s, background-color .25s var(--ease), color .25s var(--ease);
}
.is-ready .rail-social a{ transform:scale(1); }
.rail-social a:hover{ background:var(--on-field); color:var(--field); }
.rail-social svg{ width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:1.6; }

@media (prefers-reduced-motion:reduce){
  .menu{ transition:opacity .2s linear, visibility 0s linear .2s; clip-path:none; opacity:0; }
  .is-menu-open .menu{ opacity:1; transition:opacity .2s linear, visibility 0s linear 0s; }
  .menu__link{ translate:none; opacity:1; }
  .wordmark .logo-part{ transform:none; }
  .rail-social a{ transform:scale(1); }
}


/* El titulo sigue existiendo para Google y para un lector de pantalla, aunque
   ya no se dibuje: quitarlo del todo dejaria la pagina sin <h1>. */
.solo-lectura{
  position:absolute; width:1px; height:1px; margin:-1px;
  padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap;
}

/* ── el rotulo de detras ──────────────────────────────────
   "Benny The Artist" en letra corrida, con ARTIST rotando entre siete cursivas.
   Va a trazos: el navegador no descarga ni una tipografia para esto.

   La caja de ARTIST tiene ancho FIJO y cada variante se centra dentro. Los
   anchos crudos van del 66 % al 100 % entre tipografias, asi que dejarlos sueltos
   daria un tiron lateral en cada cambio y se leeria como un fallo. */
.rotulo{
  position:absolute; left:var(--edge); right:var(--edge); top:7svh; z-index:1;
  display:flex; align-items:center; justify-content:space-between;
  color:var(--paper); pointer-events:none;
  filter:var(--revelado) drop-shadow(0 .6rem 1.1rem rgb(0 0 0 / .30));
}
/* Separados a los dos cantos, con la cabeza ocupando el hueco de en medio: es
   lo que hace la referencia con su nombre. Centrarlo dejaba "enny The" debajo
   de la cara, ilegible. */
.rotulo svg{ height:26svh; width:auto; display:block; fill:currentColor; }
.rot__caja{ position:relative; display:block; height:26svh; width:36svh; }
.rot__var{
  position:absolute; inset:0; display:grid; place-items:center;
  opacity:0;                       /* corte seco, sin fundido: en el cruce se
                                      veian dos cursivas encimadas */
}
.rot__var.is-on{ opacity:1; }
/* Oculta por defecto y encendida solo en el telefono. Va ANTES del @media:
   un @media no sube la especificidad, asi que si esta linea queda por
   debajo gana ella y los botones no aparecen nunca. */
.social{ display:none }

@media (max-width:760px){
  /* En el telefono las dos piezas NO caben en una linea. Con 343px de ancho
     util, "Benny The" se come 279 y a la caja de ARTIST le quedan 64 -- pero
     sus cursivas piden hasta 183, asi que se salian 44px por la derecha y la
     palabra aparecia cortada contra el canto de la pantalla.

     Se apilan. Y el que manda pasa a ser el ANCHO, no la altura: con
     `height` fijo el ancho lo pone la proporcion de cada cursiva y en una
     pantalla estrecha eso se desborda siempre. Con `width` fijo no puede. */
  /* Dos filas: el nombre entero arriba, y abajo los dos botones a la
     izquierda con ARTIST empujado a la derecha. En grid y no en flex porque
     asi la segunda fila se reparte sola sin calcular anchos a mano. */
  .rotulo{
    top:3.5svh;
    display:grid; align-items:center;
    grid-template-columns:auto 1fr;
    grid-template-areas:"nombre nombre" "social artist";
  }
  .rot__fijo{ width:100%; grid-area:nombre }
  .social{
    grid-area:social; display:flex; align-items:center; gap:.4rem;
    pointer-events:auto;              /* el .rotulo entero los tiene apagados */
  }
  .social__b{
    display:grid; place-items:center;
    width:44px; height:44px;          /* toque, aunque el icono mida 24 */
    color:var(--paper); text-decoration:none;
    -webkit-tap-highlight-color:transparent;
  }
  .social__b svg{
    width:25px; height:25px; display:block;
    fill:none; stroke:currentColor; stroke-width:1.7;
    stroke-linecap:round; stroke-linejoin:round;
  }
  .social__punto{ fill:currentColor; stroke:none }
  .social__b:active svg{ scale:.9 }
  .social__b:focus-visible{ outline:2px solid var(--paper); outline-offset:2px; border-radius:50% }
  .rot__fijo svg{ width:100%; height:auto }

  /* ARTIST conserva su caja de alto fijo -- es lo que impide el tiron lateral
     cuando cambia de tipografia -- pero ahora cada variante se ajusta DENTRO
     de ella: `meet` la encoge hasta caber en vez de rebosar. */
  /* width:100% de su CELDA. Sin el, hereda el width:36svh de la regla base
     -- 292px -- dentro de una celda de 249 y se sale por la derecha. */
  .rot__caja{ grid-area:artist; width:100%; height:11svh; margin-top:-.8svh }
  .rot__var{ place-items:center end }
  .rot__var svg{ width:auto; height:100%; max-width:100% }

  /* Cinturon: en el rotulo nada puede ser mas ancho que su hueco. */
  .rotulo svg{ max-width:100% }

  /* Al apilar, el rotulo baja hasta y=251 y los ojos estaban en y=153: la
     palabra caia justo encima de la mirada. La cabeza se corre hacia abajo
     hasta que los ojos quedan por debajo del rotulo; ARTIST cae entonces
     sobre el craneo abierto, que es hueco, en vez de sobre la cara. */
  .stage{ --top-cara:calc(100svh - var(--alto-cara)) }
}

/* ── la pastilla de tienda ────────────────────────────────
   Lo unico que se vende esta a un clic desde cualquier punto de la pagina. */
.pastilla{
  justify-self:end; display:inline-flex; align-items:center; gap:.4em;
  min-height:44px; padding:.55rem 1.15rem; border-radius:999px;
  background:var(--paper); color:var(--ink); text-decoration:none;
  font-family:var(--display); font-weight:700; font-size:1rem; letter-spacing:-.01em;
  transition:transform .18s var(--ease), box-shadow .18s var(--ease);
}
.pastilla:hover, .pastilla:focus-visible{
  transform:translateY(-2px); box-shadow:0 .6rem 1.4rem rgb(0 0 0 / .32);
}

/* ── el menu ──────────────────────────────────────────────
   Retrato a un lado, destinos al otro. Tres entradas, no cinco: solo se lista
   lo que existe de verdad y lleva a algun sitio. Sin numerar -un menu no es
   una secuencia, y numerarlo seria decorado que finge ser informacion. */
.menu{
  position:fixed; inset:0; z-index:60; display:grid;
  overscroll-behavior:contain;
  grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  align-items:center; gap:clamp(1rem,4vw,4rem);
  padding:clamp(1.5rem,5vh,4rem) var(--pad);
  background:var(--ink); color:var(--paper);
  opacity:0; visibility:hidden; transition:opacity .42s var(--ease), visibility .42s;
}
.is-menu-open .menu{ opacity:1; visibility:visible; }

/* El retrato entra de lado, como una foto tirada sobre la mesa. La inclinacion
   es lo que impide que se lea como un banner. */
.menu__retrato{ position:relative; align-self:center; }
.menu__retrato img{
  display:block; width:100%; height:auto; max-width:none;
  rotate:-7deg; translate:-6% 0; scale:1.12;
  transform-origin:50% 60%;
  filter:var(--revelado) drop-shadow(0 1.6rem 2.6rem rgb(0 0 0 / .55));
  opacity:0; transition:opacity .5s var(--ease) .12s, rotate .6s var(--ease) .12s;
}
.is-menu-open .menu__retrato img{ opacity:1; rotate:-9deg; }

.menu__globo{
  position:absolute; left:calc(var(--pad) + 8%); top:clamp(1rem,7vh,4.5rem);
  margin:0; z-index:2; padding:.7rem 1.15rem;
  background:var(--paper); color:var(--ink); border-radius:1.1rem .9rem 1.1rem .2rem;
  font-family:var(--display); font-weight:700; font-size:clamp(1rem,1.5vw,1.2rem);
  opacity:0; translate:0 .6rem;
  transition:opacity .34s var(--ease) .4s, translate .34s var(--ease) .4s;
}
.is-menu-open .menu__globo{ opacity:1; translate:0 0; }

.menu__nav{ display:flex; flex-direction:column; gap:clamp(.4rem,2.2vh,1.4rem); }
.menu__link{
  display:block; padding:.5rem 0; text-decoration:none; color:inherit;
  border-bottom:1px solid rgb(250 250 248 / .16);
  opacity:0; translate:0 .8rem;
  transition:opacity .4s var(--ease), translate .4s var(--ease), color .18s;
}
.is-menu-open .menu__link{ opacity:1; translate:0 0; }
.is-menu-open .menu__link:nth-child(1){ transition-delay:.20s,.20s,0s; }
.is-menu-open .menu__link:nth-child(2){ transition-delay:.28s,.28s,0s; }
.is-menu-open .menu__link:nth-child(3){ transition-delay:.36s,.36s,0s; }
.menu__que{
  display:block; font-family:var(--display); font-weight:800;
  font-size:clamp(2.4rem,7vw,5.2rem); line-height:1.02; letter-spacing:-.03em;
}
/* El pie de cada entrada dice QUE hay detras. Un menu de una sola palabra
   obliga a entrar para averiguarlo. */
.menu__pie{
  display:block; margin-top:.25rem; font-style:normal;
  font-size:clamp(.95rem,1.1vw,1.05rem); opacity:.62;
}
.menu__link:hover .menu__que, .menu__link:focus-visible .menu__que{ color:var(--red); }
.menu__link:focus-visible{ outline:2px solid var(--paper); outline-offset:6px; }
.menu__foot{
  grid-column:2; margin:clamp(1rem,3vh,2rem) 0 0;
  font-size:.95rem; opacity:.55;
}
@media (max-width:860px){
  .menu{ grid-template-columns:1fr; align-content:center; }
  .menu__retrato{ display:none; }      /* en movil el retrato robaria el sitio
                                          a lo unico que importa: los destinos */
  .menu__globo{ position:static; align-self:start; justify-self:start; margin-bottom:1rem; }
  .menu__foot{ grid-column:1; }
}
@media (prefers-reduced-motion:reduce){
  .menu, .menu__retrato img, .menu__globo, .menu__link{ transition-duration:.001s; }
  .menu__retrato img{ rotate:-9deg; }
}

/* ── el pie ───────────────────────────────────────────────
   Lo grande no es el nombre: es la unica cosa que se puede hacer aqui. */
/* Nivel 1: lo unico que se puede hacer aqui. A plena opacidad. */
.foot__grande{
  position:relative; z-index:1;
  display:inline-flex; align-items:center; gap:.14em;
  font-family:var(--display); font-weight:800;
  font-size:clamp(2.6rem,9vw,7rem); line-height:.95; letter-spacing:-.035em;
  color:var(--paper); text-decoration:none;
  transition:color .22s var(--ease);
}
/* La flecha sale disparada en su propia direccion, no arrastrada por el texto.
   Antes iba con align-items:baseline y se quedaba flotando por encima de la
   linea de las mayusculas. */
.foot__flecha{
  display:inline-block; font-size:.58em; line-height:1;
  transition:translate .28s var(--ease);
}
.foot__grande:hover, .foot__grande:focus-visible{ color:var(--red); }
.foot__grande:hover .foot__flecha,
.foot__grande:focus-visible .foot__flecha{ translate:.14em -.14em; }
.foot__grande:focus-visible{ outline:2px solid var(--paper); outline-offset:8px; border-radius:4px; }

/* Nivel 2: donde encontrarlo. Dos sitios que EXISTEN, con su area tactil. */
.foot__donde{
  position:relative; z-index:1;
  display:flex; flex-wrap:wrap; gap:.7rem;
}
.foot__enl{
  display:inline-flex; align-items:center; gap:.7rem;
  min-height:44px; padding:.7rem 1.15rem;
  border:1px solid color-mix(in srgb, var(--paper) 24%, transparent);
  border-radius:2.4rem; text-decoration:none; color:inherit;
  transition:background-color .22s var(--ease), color .22s var(--ease),
             border-color .22s var(--ease);
}
.foot__enl:hover, .foot__enl:focus-visible{
  background:var(--paper); color:var(--ink); border-color:var(--paper);
}
.foot__enl:focus-visible{ outline:2px solid var(--paper); outline-offset:3px; }
.foot__enl svg{
  width:20px; height:20px; flex:0 0 auto;
  fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}
.foot__punto{ fill:currentColor; stroke:none; }
.foot__enl-txt{ display:grid; gap:.05rem; line-height:1.22; }
.foot__que{ font-weight:700; font-size:.9375rem; }
.foot__quien{ font-size:.875rem; opacity:.62; }

/* Nivel 3: el dato legal. La mono se queda SOLO aqui. En esta pagina la mono
   es la voz de los precios; ponersela tambien al copyright y a un eslogan --
   como estaba -- le quitaba ese significado. */
.foot__legal{
  position:relative; z-index:1; margin:0;
  font-family:var(--mono); font-size:.8125rem; letter-spacing:.04em;
  opacity:.45;
}

/* El comodin: el nombre otra vez, gigante, cortado por el canto de abajo.
   Mismo gesto que el hero -- la cabeza APOYADA en el borde, no flotando -- y
   sale de img/wordmark.svg, que estaba en el repositorio sin usar. Va detras de
   todo y no atrapa el raton. */
.foot__firma{
  position:absolute; left:50%; bottom:0; z-index:0;
  width:min(126%, 90rem); height:auto; max-width:none;
  translate:-50% 34%;
  opacity:.16; pointer-events:none; user-select:none;
}
@media (max-width:760px){
  /* El recorte del comodin es VERTICAL, no lateral. Con el ancho al 190% en
     una pantalla estrecha solo asomaba el centro del rotulo -- se leia "NY the
     A R", letras sueltas, no el nombre. El nombre tiene que caber entero y
     dejar que lo corte el canto de abajo, que es de lo que iba el gesto. */
  .foot__firma{ width:103%; translate:-50% 26%; opacity:.15; }
  .foot__donde{ width:100%; }
  .foot__enl{ flex:1 1 100%; }
}
@media (prefers-reduced-motion:reduce){
  .foot__grande, .foot__flecha, .foot__enl{ transition:none; }
}

/* Con el menu abierto, la barra estorba: su pastilla se encimaba con el globo.
   Se va toda menos el boton de cerrar, que vive en la propia barra. */
.is-menu-open .pastilla{ opacity:0; pointer-events:none; transition:opacity .2s; }
/* Por encima del menu SOLO mientras el menu esta abierto: puesto siempre,
   la barra flotaba tambien sobre la tienda y su "Shop" se comia el titulo
   de cada familia. El hero es z-index 0 y la cortina que sube es 2, asi que
   con 1 la barra se ve sobre la cara y desaparece bajo el blanco sola. */
.bar{ z-index:1; }
.is-menu-open .bar{ z-index:70; }

/* El globo baja y se separa del canto: arriba chocaba con la pastilla. */
.menu__globo{ left:auto; right:8%; top:auto; bottom:16%; }

/* El retrato entraba cortado por abajo y por la izquierda. */
.menu__retrato{ overflow:visible; }
.menu__retrato img{ scale:.98; translate:2% 2%; }
@media (max-width:860px){ .menu__globo{ right:auto; bottom:auto; } }

/* El retrato llega al borde del lienzo de la foto, y al girarlo ese canto se ve
   como una diagonal dura bajo el hombro. Se funde hacia abajo en vez de cortar. */
.menu__retrato img{
  -webkit-mask-image:linear-gradient(#000 68%, rgb(0 0 0 / 0) 97%);
          mask-image:linear-gradient(#000 68%, rgb(0 0 0 / 0) 97%);
}

/* ── el retrato SANGRA por la izquierda ───────────────────
   Antes cabia entero dentro de su columna, asi que se veia el canto del lienzo
   de la foto -y eso es lo que delataba el recorte-. Ahora se ancla al borde de
   la ventana y se sale por la izquierda y por abajo: el corte cae fuera de la
   pantalla, y lo que corta la figura es el propio borde del navegador.
   Por eso ya no hace falta el fundido de abajo. */
.menu__retrato{
  position:absolute; left:0; bottom:0; top:auto; width:auto;
  pointer-events:none;
}
.menu__retrato img{
  width:auto; height:126svh; max-width:none;
  translate:-19% 16%; scale:1; rotate:-9deg;
  transform-origin:0 100%;
  -webkit-mask-image:none; mask-image:none;
}
.is-menu-open .menu__retrato img{ rotate:-9deg; }
/* la columna de destinos ocupa el ancho: el retrato ya no reserva sitio */
.menu{ grid-template-columns:1fr; }
.menu__nav, .menu__foot{ grid-column:1; justify-self:end; width:min(58%, 46rem); }
.menu__globo{ right:6%; bottom:auto; top:14svh; }
@media (max-width:860px){
  .menu__retrato{ display:none; }
  .menu__nav, .menu__foot{ width:100%; justify-self:stretch; }
  .menu__globo{ position:static; }
}

/* Sangraba bien pero se comia la columna de destinos: el pie de "Instagram"
   caia sobre la cara y no habia contraste. Se recoge a su mitad, y un degradado
   del propio fondo lo despide hacia la derecha en vez de cortarlo. */
.menu__retrato img{ height:104svh; translate:-32% 14%; }
.menu__retrato::after{
  content:""; position:absolute; inset:0 -14vw 0 0; pointer-events:none;
  background:linear-gradient(90deg, rgb(11 11 11 / 0) 46%, var(--ink) 76%);
}
.menu__nav, .menu__foot{ position:relative; z-index:2; }

/* La rotacion sube la esquina de abajo a la derecha y ahi asomaba todavia el
   canto del lienzo. Se despide tambien hacia abajo, no solo hacia la derecha. */
.menu__retrato::after{
  background:
    linear-gradient(90deg,  rgb(11 11 11 / 0) 46%, var(--ink) 76%),
    linear-gradient(0deg,   var(--ink) 2%,  rgb(11 11 11 / 0) 16%);
}

/* La cabeza va inclinada hacia la DERECHA. Iba al reves: un giro negativo es
   antihorario, o sea hacia la izquierda. Con el giro cambiado hay que mover el
   anclaje, porque la esquina que se levanta pasa a ser la otra. */
.menu__retrato img{
  rotate:9deg; transform-origin:100% 100%;
  translate:-26% 12%;
  image-rendering:auto;
}
.is-menu-open .menu__retrato img{ rotate:9deg; }
.menu__retrato::after{
  background:
    linear-gradient(90deg, rgb(11 11 11 / 0) 44%, var(--ink) 74%),
    linear-gradient(0deg,  var(--ink) 1%,  rgb(11 11 11 / 0) 14%);
}

/* ── la entrada de la cabeza ──────────────────────────────
   Sube desde abajo y se agranda. Nada mas.

   Los dos numeros salen de medir la pagina de referencia, no de mi gusto:
   la escala va de 0,335 a 1 (factor 2,98) y el recorrido dura 1,9 s con la
   curva cubic-bezier(.48,0,.18,1) -entra lenta, cruza rapido y sale con cola
   larga; el pico de velocidad cae al 33% del camino, no a la mitad-.

   Crece desde su propio centro alto (50% 41,5%), que es el punto fijo medido
   alli: escalar desde el centro geometrico la haria cabecear. */
.face{ transform-origin:50% 41.5%; }
@keyframes cabeza-entra{
  from{ translate:calc(-50% + var(--tx,0px)) calc(var(--ty,0px) + 62svh); scale:.335; }
  to  { translate:calc(-50% + var(--tx,0px)) var(--ty,0px);               scale:1; }
}
.is-ready .face{
  animation:cabeza-entra 1.9s cubic-bezier(.48,0,.18,1) both;
}
@media (prefers-reduced-motion:reduce){
  .is-ready .face{ animation:none; }
}

/* ── la tienda ────────────────────────────────────────────
   Sobre papel, no sobre el rojo: las camisetas ya traen su propio color y
   sobre el campo rojo se peleaban con el. El rojo vuelve en el precio y en el
   hover, que es donde hace falta.

   La rejilla no es de tarjetas iguales. Las piezas con mas fotos ocupan dos
   columnas, asi que el ritmo lo marca el inventario y no una plantilla. */
.tienda{
  position:relative; z-index:4;
  background:var(--paper); color:var(--ink);
  padding:clamp(3rem,9vh,7rem) var(--pad) clamp(4rem,11vh,8rem);
}
.tienda__cab{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:.5rem 1.4rem;
  margin-bottom:clamp(1.6rem,5vh,3.2rem);
}
.tienda__h{
  margin:0; font-family:var(--display); font-weight:800;
  font-size:clamp(2.2rem,6.5vw,5rem); line-height:1; letter-spacing:-.035em;
}
.tienda__n{ margin:0; font-size:1rem; opacity:.6; }

.rejilla{
  display:grid; gap:clamp(1.4rem,3vw,2.6rem);
  grid-template-columns:repeat(auto-fill, minmax(min(100%, 17rem), 1fr));
}
.pz--ancha{ grid-column:span 2; }
@media (max-width:560px){ .pz--ancha{ grid-column:span 1; } }

.pz__a{ display:block; color:inherit; text-decoration:none; }
.pz__foto{
  position:relative; display:block; overflow:hidden;
  aspect-ratio:1/1; background:#EFEDE9; border-radius:2px;
}
.pz__foto img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  transition:scale .5s var(--ease), opacity .35s var(--ease);
}
/* la segunda foto es la vuelta de la prenda: se ve al pasar por encima, que es
   lo que la gente quiere mirar antes de comprar una camiseta */
.pz__vuelta{ opacity:0; }
.pz__a:hover .pz__vuelta, .pz__a:focus-visible .pz__vuelta{ opacity:1; }
.pz__a:hover .pz__foto img, .pz__a:focus-visible .pz__foto img{ scale:1.04; }
.pz__a:focus-visible{ outline:2px solid var(--red); outline-offset:5px; }

/* Agotado NO se dice solo con un color: va la palabra. */
.pz__no{
  position:absolute; left:.6rem; top:.6rem; z-index:2;
  padding:.3rem .6rem; border-radius:999px;
  background:var(--ink); color:var(--paper);
  font-size:.8rem; font-weight:700; letter-spacing:.02em;
}
.pz__pie{ display:block; padding-top:.8rem; }
.pz__frase{
  display:block; font-family:var(--display); font-weight:800;
  font-size:clamp(1.05rem,1.5vw,1.35rem); line-height:1.12; letter-spacing:-.02em;
}
.pz__prenda{ display:block; margin-top:.2rem; font-size:.9375rem; opacity:.6; }
.pz__precio{
  display:block; margin-top:.4rem; font-family:var(--mono);
  font-size:1rem; font-weight:600; color:var(--red);
}
.pz__opt{ display:block; margin-top:.14rem; font-size:.9375rem; opacity:.5; }

/* La pieza ancha ocupa dos columnas, pero con la foto cuadrada eso le duplica
   tambien el ALTO y se comia la pantalla entera. Ocupa el doble de ancho y la
   misma altura que las demas. */
.pz--ancha .pz__foto{ aspect-ratio:2/1; }
/* la barra flota sobre el contenido: la cabecera necesita sitio por arriba */
.tienda{ padding-top:clamp(5rem,13vh,9rem); }

/* ── la tapa se despega y se va por la derecha ────────────
   Un gesto entero, no un barrido: la pieza se suelta, coge vuelo y sale de
   cuadro por la derecha. Dura 900 ms — mas que los 434 del arranque medido,
   porque aqui la gracia no es la rotura sino el viaje, y los ojos tienen que
   poder seguirlo.

   Gira poco al principio y mucho al final: un papel que se suelta no empieza
   girando, empieza despegandose. */
.tapa{
  position:absolute; left:0; top:0; width:100%; z-index:3; pointer-events:none;
  transform-origin:38% 62%;
  will-change:transform;
}
.tapa img{ position:absolute; left:0; top:0; width:100%; height:auto; }
.tapa__dorso{ opacity:0; }              /* el reverso no hace falta en el vuelo */
.is-ready .o3d{ animation-play-state:running }
.is-ready .tapa{ animation:tapa-vuela 900ms cubic-bezier(.30,.02,.28,1) 1.96s both; }
@keyframes tapa-vuela{
  0%   { transform:translate(0,0)         rotate(0deg)   scale(1);    opacity:1 }
  14%  { transform:translate(1%,-2.5%)    rotate(-3deg)  scale(1.02); opacity:1 }
  46%  { transform:translate(26%,-9%)     rotate(9deg)   scale(1);    opacity:1 }
  100% { transform:translate(104%,-30%)   rotate(41deg)  scale(.9);   opacity:0 }
}
@media (prefers-reduced-motion:reduce){ .tapa{ display:none } }

/* el lienzo del rajado va justo donde la lamina */
.rasga{ position:absolute; left:0; top:0; z-index:3; pointer-events:none; }

/* ── lo que sale de la cabeza ─────────────────────────────
   Objetos con volumen, dibujados en SVG a mano: el relieve sale de los
   degradados, no de una sombra pegada debajo. Asi pesan unos pocos KB, se ven
   nitidos a cualquier tamano y no hace falta ninguna libreria 3D.

   Y cada uno LLEVA A ALGUN SITIO. Al pasar por encima dice adonde: un objeto
   que no lleva a ninguna parte es decoracion, y ocupa el mismo sitio. */
.cosas{
  /* z-index NEGATIVO, no 0: con 0 se pintaba POR DELANTE de la cabeza y el
     cuadro parecia pegado en la frente en vez de asomar por el craneo. Como
     .face crea su propio contexto de apilamiento (position + z-index), el -1
     los deja detras de la cara pero dentro de ella. Por eso la mitad de abajo
     desaparece: esta dentro del craneo de verdad. */
  position:absolute; inset:0; z-index:-1;
  container-type:size; container-name:craneo;
  perspective:1500px; perspective-origin:50% 38%;
  pointer-events:none;                     /* el hueco no come clicks; solo los objetos */
}

/* El ancla es una caja PLANA con tamano propio, y el 3D vive DENTRO.
   Si el ancla fuera la que gira, una cara a 60 grados dejaria un area de click
   de casi nada. La referencia lo resuelve igual: el <a> va aparte del dibujo. */
.o3d{
  position:absolute; display:block;
  width:var(--w); height:var(--h);
  transform-style:preserve-3d;
  pointer-events:auto;                     /* .face apaga el raton para todo lo suyo */
  cursor:pointer; -webkit-tap-highlight-color:transparent;
  rotate:var(--incl, 0deg);
  /* Sale suave desde dentro del craneo y se para donde tiene que pararse:
     la curva no rebasa el 1, asi que NUNCA sube mas alto que su sitio y
     no puede chocar con el techo de la ventana. Un bezier con rebote
     (y>1) si se pasaria de largo. */
  animation:asoma 1.35s cubic-bezier(.16,.72,.22,1) calc(2.86s + var(--n) * .17s) both;
  /* El reloj de una animacion CSS arranca al cargar el documento, no cuando
     hay algo que mirar. El preloader dura 5s como MINIMO (MIN_PRE en app.js)
     y esto iba de 2.86s a 4.21s: la animacion entera ocurria detras del telon
     y no la vio nunca nadie. Pausada, el retardo tampoco corre, asi que los
     2.86s se cuentan desde que el telon sube -que es justo para lo que
     estaban calculados: la tapa vuela a 1.96s de 'is-ready'-. */
  animation-play-state:paused;
}
.o3d:focus-visible{ outline:3px solid var(--paper); outline-offset:10px; border-radius:6px }
/* El lapiz mide 17px de ancho: se ve bien y no hay quien lo pinche. El area
   sensible se ensancha hasta los 44px que pide el proyecto SIN engordar el
   objeto — la zona de tocar y el dibujo no tienen por que medir lo mismo. */
.o3d::after{
  /* El area minima de 44px se quito: la puse cuando el lapiz media 17px de
     ancho y no habia quien lo pinchara. Ahora la pieza mas estrecha mide 78px,
     asi que ese colchon ya solo servia para capturar el raton FUERA del objeto
     y quitarselo al vecino.

     Ahora este hueco es la SOMBRA del suelo. Sin ella la pieza subia 40-59px y
     no se leia como que subiera: sin nada abajo que se abra y se aclare, un
     objeto que se aleja del suelo parece que simplemente crece.

     Va aqui y no en filter:drop-shadow sobre el cuerpo, porque un filter aplana
     preserve-3d y el objeto perderia las caras -- ya paso en este mismo archivo
     y el resultado fue que las piezas se veian NEGRAS. */
  content:'';
  position:absolute; left:6%; right:6%; bottom:-4%; height:8%;
  background:radial-gradient(50% 50% at 50% 50%, rgb(0 0 0 / .40), transparent 70%);
  translate:0 0 -3cqw;
  opacity:.5;
  pointer-events:none;
  transition:opacity .34s var(--ease), scale .34s var(--ease), translate .34s var(--ease);
}


/* Sale desde dentro del craneo: empieza hundida y pequena, detras de la cara. */
/* Salir de dentro no es subir desde abajo. Antes se encogia al 50% con scale,
   que es el truco plano de "esta lejos": el objeto se ve igual de nitido y del
   mismo grosor, solo mas chico. Ahora arranca 30cqw metido hacia el fondo y
   viaja hacia el espectador: con la perspectiva de 1500px del contenedor, el
   tamano lo pone la distancia, y las caras laterales del cubo se abren solas
   segun se acerca. Eso es lo que hace que parezca que sale del craneo. */
@keyframes asoma{
  from{ translate:0 58cqw -30cqw; scale:.94; opacity:0 }
  22% { opacity:1 }
  to  { translate:0 0 0;          scale:1;   opacity:1 }
}

.o3d__cuerpo{
  position:absolute; left:50%; top:50%;
  width:var(--w); height:var(--h); margin:calc(var(--h) / -2) 0 0 calc(var(--w) / -2);
  transform-style:preserve-3d; pointer-events:none;
  transform:rotateX(var(--gx)) rotateY(var(--gy));
  transition:translate .34s var(--ease), scale .34s var(--ease);
}
/* Gira DE VERDAD: por eso ensena sus cantos y su dorso. Un dibujo no puede. */
@keyframes orbita{
  from{ transform:rotateX(var(--gx)) rotateY(var(--gy)) }
  to  { transform:rotateX(var(--gx)) rotateY(calc(var(--gy) + 360deg)) }
}
/* Al pasar el raton NO gira: asoma un poco mas, como si tirara de el hacia
   fuera del craneo. El levante va en el CUERPO y no en el ancla porque el
   ancla la ocupa la animacion de salida con fill "both", y esa se queda
   mandando sobre translate/scale para siempre: lo que pusiera ahi no se
   veria nunca. */
/* Al pasar el raton sale hacia DELANTE ademas de subir. Con los tres pegados,
   subir a secas no basta: el vecino lo tapa. La tercera cifra del translate es
   Z, y como el contenedor conserva el 3D, adelantarse lo pinta por encima —
   que es lo que hace falta, no un z-index (aqui manda la profundidad). */
/* NADA de filter aqui. Un elemento con filter pierde preserve-3d: sus caras
   se pintan por orden del DOM y el DORSO -que va despues- tapa a la cara de
   delante. Como el dorso es tinta al 42% de brillo, el objeto entero se veia
   NEGRO. La senal de "este es el elegido" la dan el movimiento y la escala,
   que no rompen nada. */
/* :active va con los otros dos, y no es un adorno: en un telefono NO HAY hover,
   asi que hasta ahora tocar una pieza no la levantaba. Se miraba y no
   respondia. */
.o3d:hover .o3d__cuerpo,
.o3d:focus-visible .o3d__cuerpo,
.o3d:active .o3d__cuerpo{
  translate:0 -13% 8cqw;
  scale:1.09;
}
/* la sombra se separa y se abre: es lo que cuenta que la pieza se ha despegado */
.o3d:hover::after,
.o3d:focus-visible::after,
.o3d:active::after{
  opacity:.78;
  scale:1.18 1;
  translate:0 42% -3cqw;
}
/* Al tocar responde en el acto; el regreso si se toma su tiempo. Un dedo espera
   respuesta inmediata, un raton que se va no. */
.o3d:active .o3d__cuerpo, .o3d:active::after{ transition-duration:.09s }
/* El resto se apaga cuando uno esta elegido: sin esto los tres compiten y no
   se sabe cual va a responder. La atenuacion va en brillo y no en opacidad —
   bajar la opacidad de un elemento con preserve-3d lo aplana y pierde el 3D. */
/* Apagar a .55 dejaba en NEGRO a los que no eliges: el cuadro tiene marco
   negro y la camiseta es negra, asi que un 55% de brillo se los comia. Se le
   da la vuelta — se REALZA el elegido y a los otros apenas se les baja. */
/* A los no elegidos NO se les toca el brillo por el mismo motivo: cualquier
   filter sobre el cuerpo lo aplana y saca el dorso. Se quedan como estan; el
   que sube y se adelanta ya destaca de sobra. */
.o3d__cuerpo{ transition:translate .34s var(--ease), scale .34s var(--ease), filter .34s var(--ease) }

.c{ position:absolute; inset:0; display:block; background:var(--ink); }

/* --- las seis caras de una caja --- */
.c--frente{ transform:translateZ(calc(var(--d) / 2)) }
.c--dorso { transform:rotateY(180deg) translateZ(calc(var(--d) / 2)); filter:brightness(.42) }
.c--der   { width:var(--d); left:calc(50% - var(--d) / 2);
            transform:rotateY(90deg)  translateZ(calc(var(--w) / 2)); filter:brightness(1.22) }
.c--izq   { width:var(--d); left:calc(50% - var(--d) / 2);
            transform:rotateY(-90deg) translateZ(calc(var(--w) / 2)); filter:brightness(.55) }
.c--arr   { height:var(--d); top:calc(50% - var(--d) / 2);
            transform:rotateX(90deg)  translateZ(calc(var(--h) / 2)); filter:brightness(1.35) }
.c--aba   { height:var(--d); top:calc(50% - var(--d) / 2);
            transform:rotateX(-90deg) translateZ(calc(var(--h) / 2)); filter:brightness(.34) }

/* --- el cilindro: la luz de cada cara se calculo al generarla --- */
.o3d__cil .c--lado{
  inset:0 auto; width:var(--cw); left:calc(50% - var(--cw) / 2); height:100%;
  transform:rotateY(var(--a)) translateZ(var(--r));
  filter:var(--revelado) brightness(var(--luz));
}

/* El cuadro: marco de tinta, pasapartout de papel, y su dibujo dentro. */
.o3d--cuadro .c--frente{ padding:.9cqw; background:var(--ink) }
.o3d--cuadro .c--frente img{
  width:100%; height:100%; object-fit:contain; display:block;
  background:var(--paper); padding:1cqw;
}
/* La caja de envio: papel, con la cinta roja cruzada. */
.o3d--caja .c{ background:var(--paper) }
.o3d--caja .c--frente{
  background:
    linear-gradient(var(--red) 0 0) center / 12% 100% no-repeat,
    var(--paper);
}
.o3d--caja .c--arr{
  background:linear-gradient(90deg, transparent 44%, var(--red) 44% 56%, transparent 56%), var(--paper);
}
/* El lapiz: el mismo blanco que lleva en la boca, con la punta gastada. */
.o3d--lapiz .c{ background:var(--paper) }
.lapiz__punta{
  position:absolute; left:50%; bottom:-5.2cqw; width:4.8cqw; height:5.6cqw;
  translate:-50% 0; pointer-events:none;
  background:conic-gradient(from 180deg at 50% 0, var(--ink) 0 100%);
  clip-path:polygon(50% 100%, 0 0, 100% 0);
}
/* El bote: tinta, con el tapon rojo. */
.o3d--spray .c{ background:var(--ink) }
.spray__tapa{
  position:absolute; left:50%; top:-4.4cqw; width:6.4cqw; height:4.8cqw;
  translate:-50% 0; border-radius:1cqw 1cqw 0 0; background:var(--red);
  pointer-events:none;
}

/* Al pasar dice adonde lleva. Un objeto que no lleva a ningun sitio es adorno. */
.o3d__eti{
  position:absolute; left:50%; bottom:-6.8cqw; translate:-50% 6px;
  padding:.42rem .85rem; border-radius:999px; white-space:nowrap;
  background:var(--paper); color:var(--ink);
  font-family:var(--display); font-weight:700; font-size:1rem;
  opacity:0; pointer-events:none;
  transition:opacity .2s var(--ease), translate .2s var(--ease);
}
.o3d:hover .o3d__eti, .o3d:focus-visible .o3d__eti{ opacity:1; translate:-50% 0 }

@media (max-width:760px){
  .o3d__eti{ font-size:.9rem }
  .o3d--spray{ display:none }        /* a ese ancho se amontonan sobre la cara */
}
@media (prefers-reduced-motion:reduce){
  .o3d{ animation:none }
  .o3d__cuerpo{ transition:none }
}


/* ── la camiseta: tela, no caja ────────────────────────────
   Una prenda puesta es una SUPERFICIE CURVA con pliegues. La construyo con
   lamas verticales: cada una a su propia Z y girada para quedar tangente a la
   curva. El brillo de cada lama sale del coseno de su angulo contra la luz —
   calculado, no pintado — asi que al girar la cabeza el brillo VIAJA por la
   tela. Un plano con degradados no puede hacer eso, y por eso el primer
   intento con cajas rectas parecia un ladrillo.
   El estampado se reparte entre las lamas, de modo que se ondula con ella
   en vez de quedarse plano encima. */
.tela{
  position:absolute; left:50%; top:50%;
  width:var(--wt); height:var(--ht);
  margin:calc(var(--ht) / -2) 0 0 calc(var(--wt) / -2);
  transform-style:preserve-3d;
}
.tela--mizq{ transform:translate3d(var(--mx), -7cqw, -1cqw) rotateZ(var(--gz)) }
.tela--mder{ transform:translate3d(var(--mx), -7cqw, -1cqw) rotateZ(var(--gz)) }

.lama{
  position:absolute; top:0; height:100%;
  left:calc(50% + var(--x)); width:var(--w);
  transform:translateX(-50%) translateZ(var(--z)) rotateY(var(--ry));
  background-color:var(--ink);
  filter:var(--revelado) brightness(var(--luz));
  clip-path:polygon(0 var(--t), 100% var(--t), 100% var(--b), 0 var(--b));
}
/* cada lama ensena SU franja del dibujo: por eso el estampado se dobla */
.lama--est{
  background-image:url("/img/dentro/camisa.webp?v=78f1128300");
  background-repeat:no-repeat;
  background-size:var(--est, 20cqw) auto;
  background-position:var(--bx) 24%;
}

/* La lama que ensena FOTO no lleva color ni recorte: la silueta la pone el
   alfa de la prenda recortada, que es la forma real de la camiseta. */
.tela--prenda{ }
.lama--foto{
  background-color:transparent;
  background-image:url("/img/dentro/camisa-prenda.webp?v=62bffef226");
  background-repeat:no-repeat;
  background-size:var(--wt) auto;
  background-position:var(--bx) 0;
  clip-path:none;
}

/* La prenda entera, plana y detras de las lamas: lo que se cuele por una
   rendija es camiseta, no el campo rojo. Sin esto se veian rayas verticales
   rojas, porque una lama girada tapa menos ancho del que ocupa. */
.lama--fondo{
  left:50%; width:var(--wt); transform:translateX(-50%) translateZ(-1.2cqw);
  background-color:transparent; clip-path:none; filter:var(--revelado) brightness(.9);
  background-image:url("/img/dentro/camisa-prenda.webp?v=62bffef226");
  background-repeat:no-repeat; background-size:var(--wt) auto; background-position:0 0;
}

/* ── la funda ─────────────────────────────────────────────
   Ya no se construye con cajas CSS. Esta RENDERIZADA por raymarching sobre
   campos de distancia (ver el guion en la historia del repo): geometria hueca
   de verdad, esquinas redondeadas en las TRES dimensiones -que es lo que las
   cajas CSS no pueden dar, porque cada cara redondea solo en su plano-, el
   agujero de la camara pasante, y luz con especular y brillo de canto.
   470x950, 421.989 pixeles de funda. */
.funda3d img{
  width:100%; height:100%; display:block; object-fit:contain;
  filter:var(--revelado) drop-shadow(0 .8cqw 1.1cqw rgb(0 0 0 / .45));
}

/* ── la masa, dentro del craneo ───────────────────────────
   Generada por REACCION-DIFUSION (Gray-Scott, 5.200 pasos): el mismo sistema
   que produce los laberintos organicos de la naturaleza, que es justo como se
   pliega una corteza. No es una textura dibujada — de ahi que ningun surco se
   repita.
   Va MAS AL FONDO que los objetos: en un contenedor que conserva el 3D manda
   la profundidad, no el z-index, asi que se echa atras con translateZ. */
.seso{
  position:absolute; display:block;
  width:var(--w); height:var(--h);
  transform:translateZ(-5cqw);
  /* La masa se salia por arriba y por los lados. Perseguirla moviendola no
     funciona: el rasgado baja 5.8 puntos de izquierda a derecha, asi que
     cualquier cima recta asoma por algun lado. Con mascara no hay canto que
     asomar — se desvanece antes de llegar a ningun borde. */
  -webkit-mask-image:radial-gradient(ellipse 58% 92% at 50% 108%,
    #000 38%, rgb(0 0 0 / .55) 64%, transparent 82%);
  mask-image:radial-gradient(ellipse 58% 92% at 50% 108%,
    #000 38%, rgb(0 0 0 / .55) 64%, transparent 82%);
  pointer-events:none;
}
.seso::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(120% 90% at 50% 24%,
    rgb(0 0 0 / 0) 40%, rgb(0 0 0 / .38) 78%, rgb(0 0 0 / .62) 100%);
}
.seso img{
  width:100%; height:100%; display:block;
  object-fit:cover; object-position:center 46%;
  /* la ZONA MEDIA del patron: si encuadro la cima se ve el borde del domo
     y canta que es una figura pegada en vez de masa que sigue hacia dentro */
  /* a este tamano los surcos son finos: hace falta CONTRASTE para que se
     lean, no bajarle la luz como si fuera un fondo */
  filter:var(--revelado) contrast(1.14) saturate(.98) brightness(.88)
         drop-shadow(0 .4cqw .7cqw rgb(0 0 0 / .6));
}

/* ── el nombre, encima del cursor ─────────────────────────
   Se coloca con translate y no con left/top: mover un elemento por su posicion
   obliga al navegador a recalcular el diseno en cada fotograma; con translate
   solo lo recompone, que es lo unico que puede seguir al raton sin arrastrarse.
   Y NUNCA coge el raton: si lo hiciera, al ponerse bajo el cursor se dispararia
   el pointerleave del objeto y el rotulo parpadearia sin parar. */
.rotulo-cursor{
  position:fixed; left:0; top:0; z-index:80;
  translate:-50% -50%;
  rotate:-8deg;                       /* ladeada, como en la referencia */
  margin:-2.2rem 0 0 -1.1rem;         /* arriba y a la izquierda del cursor */               /* por ENCIMA del cursor, sin taparlo */
  padding:.42rem .85rem; border-radius:999px; white-space:nowrap;
  background:var(--paper); color:var(--ink);
  font-family:var(--display); font-weight:700; font-size:1rem; line-height:1;
  pointer-events:none;
  opacity:0; scale:.8;
  transition:opacity .16s var(--ease), scale .16s var(--ease);
}
.rotulo-cursor.is-on{ opacity:1; scale:1 }
@media (prefers-reduced-motion:reduce){ .rotulo-cursor{ transition:none } }

/* la etiqueta de debajo sobra: el nombre ahora va con el cursor */
.o3d__eti{ display:none }

/* ── las manos agarradas al borde blanco ──────────────────
   No agarran el craneo: agarran el canto de la seccion blanca, que es donde
   apoya la cabeza. Los dedos caen POR DELANTE del blanco -por eso el translate
   negativo deja su mitad de abajo sobre el- y el resto queda contra el rojo.
   Van pegadas al borde con bottom, no con una altura calculada: la cabeza mide
   distinto en cada pantalla y cualquier numero fijo se descuadraria. */
.manos{
  /* colgadas del BORDE DE ARRIBA de la seccion blanca. Antes iban en .stage,
     que recorta con overflow:clip, y los dedos se cortaban en seco justo en
     la linea en vez de apoyarse encima. */
  position:absolute; left:0; right:0; top:0; height:0;
  z-index:7; pointer-events:none;
}
.mano{
  position:absolute; top:0; display:block; width:var(--w); height:auto;
  /* la altura la reserva el aspect-ratio de cada una, ver abajo */
  /* Tres sombras, no una. Una sola sombra siempre lee como recorte pegado
     porque el contacto real tiene tres escalas a la vez:
       1. contacto duro y minusculo donde la yema aprieta el muro
       2. sombra media, ya desplazada a la derecha (la luz viene de arriba
          a la izquierda, la misma que ilumina la cara)
       3. oclusion amplia y floja, la que asienta la mano en el plano
     Y van desplazadas en X: una sombra recta debajo solo se da si la luz
     esta justo encima, y aqui no lo esta. */
  filter:drop-shadow(.06rem .09rem .12rem rgb(0 0 0 / .55))
         drop-shadow(.35rem .55rem .7rem rgb(0 0 0 / .40))
         drop-shadow(.9rem 1.5rem 2.2rem rgb(0 0 0 / .26));
  /* la mano se inclina hacia atras por arriba: los dedos quedan MAS CERCA del
     ojo que los nudillos, que es lo que pasa cuando algo se agarra a un borde
     que tienes delante. Sin esto la mano es plana aunque este bien recortada. */
  transform:perspective(760px) rotateX(9deg);
  transform-origin:50% 100%;
  animation:agarra 900ms cubic-bezier(.22,.85,.28,1) 3.5s both;
}
.mano--izq{ aspect-ratio:567/417; --w:31vw; left:5%;  translate:0 -52%; rotate:-5deg }
.mano--der{ aspect-ratio:581/448; --w:32vw; right:4%; translate:0 -55%; rotate:4deg }
@keyframes agarra{
  from{ opacity:0; scale:.94 }
  to  { opacity:1; scale:1 }
}
@media (prefers-reduced-motion:reduce){ .mano{ animation:none } }


/* ── el canto del muro ────────────────────────────────────
   Sin grosor, el blanco es un cambio de color y las manos parecen pegadas
   encima. Con un canto iluminado por arriba y su sombra justo debajo, el
   blanco pasa a ser una PARED que tiene delante y detras — y entonces si se
   lee que las manos la agarran por el borde. */
.tienda{ position:relative }
.tienda::before{
  content:""; position:absolute; left:0; right:0; top:0; height:.9rem;
  background:linear-gradient(#ffffff 0 38%, #efeee9 38% 72%, #d9d7cf 100%);
  box-shadow:0 .5rem .8rem rgb(0 0 0 / .16);
  z-index:5; pointer-events:none;
}
/* el rojo, oscurecido justo encima del canto: la pared proyecta hacia atras */
.tienda::after{
  content:""; position:absolute; left:0; right:0; top:-2.2rem; height:2.2rem;
  background:linear-gradient(rgb(0 0 0 / 0), rgb(0 0 0 / .22));
  z-index:5; pointer-events:none;
}

/* ── la ficha de producto ─────────────────────────────────
   Se abre con :target, SIN JavaScript. Eso no es por purismo: asi el enlace
   se puede compartir, el boton de atras la cierra, y funciona aunque el script
   falle -que es justo lo que ya pasaba con la tienda-.
   Antes cada tarjeta enlazaba a #p-{handle} y ese destino no existia: 13
   anclas muertas que no llevaban a ninguna parte. */
.ficha{
  position:fixed; inset:0; z-index:90;
  display:grid; place-items:center; padding:5vmin;
  opacity:0; pointer-events:none;
  transition:opacity .22s var(--ease);
}
.ficha:target{ opacity:1; pointer-events:auto }
.ficha__fondo{ position:absolute; inset:0; background:rgb(11 11 11 / .72); backdrop-filter:blur(3px) }
.ficha__caja{
  position:relative; z-index:1;
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:0;
  width:min(78rem, 94vw); max-height:88svh;
  overflow:auto; overscroll-behavior:contain;
  background:var(--paper); color:var(--ink);
  border-radius:1.1rem;
  scale:.97; transition:scale .22s var(--ease);
}
.ficha:target .ficha__caja{ scale:1 }
.ficha__img{ width:100%; height:100%; object-fit:cover; display:block; background:#eceae4 }
.ficha__dat{ padding:clamp(1.4rem, 3vw, 2.6rem); display:flex; flex-direction:column; gap:.7rem }
.ficha__h{ font-family:var(--display); font-size:clamp(1.7rem, 3.4vw, 3rem); line-height:1.02; margin:0 }
.ficha__prenda{ font-size:1rem; opacity:.72; margin:0 }
.ficha__precio{ font-family:var(--display); font-size:1.6rem; margin:.2rem 0 0 }
.ficha__tallas{ font-size:.95rem; opacity:.72; margin:0 }
/* La lista de versiones. Antes imprimia SIEMPRE un <li> con el mismo titulo que
   ya estaba en el <h3>, y el unico estilo escrito era para `.ficha__vers a` --
   un enlace que aqui no existe -- asi que salia texto pelado repitiendo el
   nombre. Ahora solo aparece cuando el mismo dibujo existe en mas de una
   prenda, con un rotulo que dice que son. */
.ficha__verh{
  margin:1rem 0 .35rem; font-size:.875rem; font-weight:600;
  letter-spacing:.04em; text-transform:uppercase; opacity:.5;
}
.ficha__vers{
  list-style:none; margin:0; padding:0;
  display:flex; flex-wrap:wrap; gap:.4rem;
}
.ficha__vers li{
  padding:.4rem .8rem; border-radius:999px;
  border:1.5px solid rgb(0 0 0 / .16);
  font-size:.9375rem; line-height:1.3;
}
.ficha__ago{ opacity:.5; font-style:italic }
.ficha__x{
  position:absolute; right:.7rem; top:.7rem; z-index:2;
  width:46px; height:46px; display:grid; place-items:center;
  /* 46 y no 44: el borde redondeado se come 1px por lado y medido daba 43 */
  border-radius:50%; background:var(--paper); color:var(--ink);
  text-decoration:none; font-size:1.5rem; line-height:1;
}
@media (max-width:760px){
  .ficha__caja{ grid-template-columns:1fr }
  .ficha__img{ max-height:38svh }
}
@media (prefers-reduced-motion:reduce){
  .ficha, .ficha__caja{ transition:none }
}

/* ── las tres familias ────────────────────────────────────
   El craneo saca tres cosas y las rotula Prints, Cases y Tees. Abajo tiene que
   haber tres sitios donde caigan, o la promesa de arriba no se cumple.
   Hoy solo hay camisetas: las otras dos se anuncian con la MISMA pieza que se
   ve en el craneo, y sin precio. Poner una cifra a algo que no esta a la venta
   es mentir. */
.fam{ margin-block:clamp(3rem, 7vw, 6rem) }
.fam__h{
  display:flex; align-items:baseline; gap:1rem; flex-wrap:wrap;
  font-family:var(--display); font-weight:700;
  font-size:clamp(2rem, 5.5vw, 3.6rem); line-height:1;
  margin:0 0 clamp(1.2rem, 3vw, 2.2rem);
}
.fam__n{ font-family:var(--body); font-weight:400; font-size:1rem; opacity:.6 }

/* La pieza que anuncia lo que viene ocupa la fila entera: una sola tarjeta en
   una rejilla de dos columnas deja la mitad vacia y parece que falta algo. */
/* Las piezas que aun no estan a la venta se enseñan EXACTAMENTE igual que las
   que si: misma rejilla, misma caja cuadrada, mismo pie. Antes tenian su propio
   trato -- una sola columna a todo el ancho, y dentro otras dos con la foto a
   un lado y el texto al otro -- y la funda quedaba diminuta en un mar de
   blanco, sin parecerse en nada al resto de la tienda.

   Lo unico que cambia es `contain` en vez de `cover`: un cuadro enmarcado y una
   funda son objetos con silueta, y recortarlos por los bordes como se hace con
   la foto de una camiseta les corta el marco. */
.pz--pronto{ cursor:default }
.pz--pronto .pz__foto{ background:#F4F2EE }
.pz--pronto .pz__foto img{
  object-fit:contain;
  padding:7%;
}
.pz__precio--pronto{ opacity:.62; font-style:italic }

/* ── el carrusel de categorias ────────────────────────────
   Existe por una razon concreta: el nombre de cada pieza vivia pegado al
   cursor, y en un telefono no hay cursor. rotulo.js sale en la primera linea
   con `if (!fino) return` y .o3d__eti esta en display:none, asi que en el
   movil habia tres cosas saliendo del craneo sin una sola etiqueta.

   El arco de cada flecha va DOS veces -- la pista apagada debajo, el avance
   encima -- porque el boton es tambien su propio reloj: se ve cuanto falta
   para que pase sola. Es lo que hace la referencia, y por eso no necesita una
   barra de progreso aparte quitando sitio en una pantalla que no lo tiene. */
.ct{ display:none }

@media (max-width:760px){
  .ct{
    display:flex; align-items:center; justify-content:center; gap:1.5rem;
    /* Centrado en la franja roja que queda entre ARTIST y la frente.

       Restar una cantidad fija a --top-cara no vale: ese hueco mide 201px en
       un 375x812 pero solo 73 en un 360x640, y un -8rem se comia el rotulo 55
       pixeles en el corto. Asi que se calcula donde ACABA el rotulo a partir
       de su propia geometria -- arranca a 3.5svh, "Benny The" ocupa el ancho
       util y su alto sale del ratio 503.2/205 de su trazo, y debajo van los
       11svh de ARTIST menos el solape de .8svh -- y el carrusel se centra en
       lo que sobra hasta la cabeza. Contrastado con la medicion real: da 251
       en 375x812 y 222 en 360x640, que es exactamente donde acaba. */
    --fin-rotulo:calc(13.7svh + (100vw - 2rem) / 2.455);
    --hueco:calc(var(--top-cara, 2.68svh) - var(--fin-rotulo));
    position:absolute; left:0; right:0;
    top:calc(var(--fin-rotulo) + (var(--hueco) - 58px) / 2);
    z-index:6;
  }

  .ct__fl{
    flex:0 0 auto; width:44px; height:58px;    /* 44px de toque, no negociable */
    background:none; border:0; padding:0; cursor:pointer;
    -webkit-tap-highlight-color:transparent;
  }
  .ct__fl svg{ width:100%; height:100%; display:block; overflow:visible }
  .ct__pista { fill:none; stroke:rgb(255 255 255 / .28); stroke-width:2.4 }
  .ct__avance{
    fill:none; stroke:var(--paper); stroke-width:2.4; stroke-linecap:round;
    stroke-dasharray:108.38;        /* = PI x 34.5, la media vuelta entera */
    stroke-dashoffset:108.38;       /* empieza vacio y se va llenando */
  }
  .ct__punta{
    fill:none; stroke:var(--paper); stroke-width:3.1;
    stroke-linecap:round; stroke-linejoin:round;
  }
  .ct__fl:active .ct__punta{ stroke-width:3.8 }
  .ct__fl:focus-visible{ outline:2px solid var(--paper); outline-offset:4px; border-radius:1rem }

  /* El arco se llena SOLO en la derecha: el salto automatico va hacia
     adelante, asi que un reloj en la flecha de atras estaria contando algo
     que no va a pasar. La izquierda se queda con la punta sola. */
  .ct__fl--izq .ct__pista, .ct__fl--izq .ct__avance{ display:none }
  .ct.is-corriendo .ct__fl--der .ct__avance{ animation:ct-avanza var(--ct-dur, 4.6s) linear forwards }
  @keyframes ct-avanza{ to{ stroke-dashoffset:0 } }

  .ct__ventana{ position:relative; display:grid; place-items:center; min-width:11rem }
  .ct__pastilla{
    grid-area:1/1; opacity:0; pointer-events:none;
    display:grid; place-items:center; min-height:44px;
    padding:.7rem 1.5rem; border-radius:2.4rem;
    background:var(--paper); color:var(--ink); text-decoration:none;
    font-family:var(--display); font-weight:700; font-size:1.3rem; line-height:1;
    white-space:nowrap;
    box-shadow:0 .45rem 1.1rem rgb(0 0 0 / .30);
    transition:opacity .22s var(--ease), scale .22s var(--ease);
    scale:.94;
  }
  .ct__pastilla.is-on{ opacity:1; pointer-events:auto; scale:1 }

  /* Fuera del hero los dos botones que ocupaban ese sitio. OJO: el de las
     tres rayas era la UNICA entrada al menu en telefono; queda dicho.

     Y fuera tambien el rail social de abajo: llevaba a Instagram y a la
     tienda, que es exactamente donde llevan los dos que ahora estan arriba
     junto a ARTIST. Estaba a y=718, visible y pulsable, duplicando destinos.
     En escritorio se queda, porque alli .social no aparece. */
  .pastilla, .burger, .rail-social{ display:none }

  /* la pieza de la que se esta hablando se adelanta un poco: sin esto el
     nombre aparece pero no se sabe a cual de las tres se refiere */
  .o3d.is-ct .o3d__cuerpo{ translate:0 -7% 5cqw; scale:1.05 }
}

@media (max-width:760px) and (prefers-reduced-motion:reduce){
  .ct.is-corriendo .ct__fl--der .ct__avance{ animation:none; stroke-dashoffset:0 }
  .ct__pastilla{ transition:none }
  .o3d.is-ct .o3d__cuerpo{ translate:0 0 0; scale:1 }
}

/* ── el blanco sube y tapa la cara ────────────────────────
   El hero se queda quieto y la tienda le pasa por encima, en vez de irse los
   dos hacia arriba a la vez. Es una capa, no un desplazamiento: por eso el
   rostro queda cubierto del todo en lugar de asomar por el canto.

   Solo en el telefono. En escritorio el hero mide 131svh y clavarlo obligaria
   a recorrer una pantalla y media antes de que se moviera nada. */
/* El carrito se ve SIEMPRE, en cualquier ancho. Estuvo en display:none fuera
   del telefono y en escritorio no salia: la barra quedaba con los filtros a la
   izquierda y nada a la derecha. */
.cesta{
  display:grid; place-items:center;
  width:44px; height:44px; flex:0 0 auto;
  border:0; padding:0; font:inherit; cursor:pointer;
  border-radius:50%; background:var(--ink); color:var(--paper);
  box-shadow:0 .35rem .9rem rgb(0 0 0 / .22);
  -webkit-tap-highlight-color:transparent;
}
.cesta svg{ width:22px; height:22px; fill:none; stroke:currentColor;
            stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round }
.cesta:active{ scale:.93 }
.cesta:focus-visible{ outline:2px solid var(--ink); outline-offset:3px }

/* El hero se clava y todo lo de abajo le pasa por encima. Tambien en PC.

   El `top` no es 0 sino "una pantalla menos lo que mide el hero". Con top:0 y
   un hero de 131svh el elemento queda pegado arriba desde el primer pixel y su
   parte baja -- la barbilla -- no se ve nunca. Con esta resta se pega cuando su
   FONDO toca el fondo de la pantalla, que es el momento en que ya se ha visto
   entero. En el telefono el hero mide 100svh, la resta da 0, y sale exactamente
   el mismo comportamiento que ya habia: una sola formula para los dos. */
.stage{
  position:sticky;
  top:calc(100svh - (var(--top-cara, 2.68svh) + var(--alto-cara)));
  z-index:0;
}

/* Lo que sube necesita contexto propio y fondo opaco: sin fondo, la cara se
   transparenta por debajo mientras la cortina pasa. */
.top{ position:relative; z-index:2 }
.tienda{ position:relative; z-index:2; background:var(--paper) }
/* .foot ya declara position y z-index en su propio bloque; repetirlos aqui era
   una segunda fuente de verdad para lo mismo. */

@media (max-width:760px){

  /* El carrito se despega y se queda arriba a la derecha en cuanto la tienda
     empieza a subir. Va en sticky y no en fixed a proposito: asi aparece solo
     cuando el blanco ya esta arriba, y no encima del hero desde el principio.
     El margen negativo evita que empuje al titulo hacia abajo. */
  .cesta{
    border:0; padding:0; font:inherit; cursor:pointer;
    width:44px; height:44px;
    display:grid; place-items:center;
    border-radius:50%; background:var(--ink); color:var(--paper);
    box-shadow:0 .35rem .9rem rgb(0 0 0 / .22);
    -webkit-tap-highlight-color:transparent;
  }
  .cesta svg{ width:22px; height:22px; fill:none; stroke:currentColor;
              stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round }
  .cesta:active{ scale:.93 }
  .cesta:focus-visible{ outline:2px solid var(--ink); outline-offset:3px }
}

/* ── el escaparate ────────────────────────────────────────
   El patron sale de carliphone.shop, que es del mismo dueño: tarjeta clara
   sobre fondo oscuro, numero grande en el canto, titulo y precio debajo. Lo
   que cambia es el idioma de la casa -- el rojo es el #D00202 de Benny y la
   display es la suya -- para que no parezca la otra tienda con otras fotos.

   En el telefono va en carrusel horizontal con snap en vez de apilarse: seis
   tarjetas en columna son seis pantallas de scroll antes de llegar a la
   tienda, y ninguna se ve entera junto a la siguiente. */
.top{
  background:var(--ink); color:var(--paper);
  padding:clamp(3.5rem, 9vw, 7rem) 0 clamp(3rem, 7vw, 6rem);
  position:relative; z-index:2;
}
.top__cab{ padding-inline:var(--edge); margin-bottom:clamp(2rem, 5vw, 3.5rem) }
.top__h{
  font-family:var(--display); font-weight:700; margin:0;
  font-size:clamp(2.4rem, 7vw, 4.6rem); line-height:.98;
  letter-spacing:-.01em;
}
.top__n{ margin:.7rem 0 0; font-size:1.0625rem; opacity:.62 }

.top__rej{
  list-style:none; margin:0; padding:0 var(--edge);
  display:grid; gap:clamp(1.2rem, 3vw, 2.2rem);
  grid-template-columns:repeat(3, 1fr);
}

.tv__a{
  display:grid; gap:.9rem; text-decoration:none; color:inherit;
  position:relative;
}
.tv__foto{
  position:relative; display:block; overflow:hidden;
  background:var(--paper); border-radius:1.1rem;
  aspect-ratio:4/5;
}
.tv__foto img{
  width:100%; height:100%; object-fit:contain; display:block;
  padding:12%;
  transition:scale .5s var(--ease), rotate .5s var(--ease);
}
/* La segunda foto vive debajo y solo asoma al pasar por encima. Es la misma
   idea del componente de referencia -- una imagen que entra girando -- pero
   sin traerse GSAP para animar dos propiedades. */
.tv__vuelta{
  position:absolute; inset:0; opacity:0;
  rotate:-8deg; scale:1.06;
  transition:opacity .38s var(--ease), rotate .55s var(--ease), scale .55s var(--ease);
}
.tv__a:hover .tv__vuelta, .tv__a:focus-visible .tv__vuelta{ opacity:1; rotate:0deg; scale:1 }
.tv__a:hover .tv__foto > img:first-of-type,
.tv__a:focus-visible .tv__foto > img:first-of-type{ scale:1.03; rotate:2deg }

.tv__num{
  position:absolute; top:.8rem; left:1rem; z-index:2;
  font-family:var(--display); font-weight:800; font-size:2.6rem; line-height:1;
  color:var(--red); letter-spacing:-.03em;
  pointer-events:none;
}
.tv__pie{ display:grid; gap:.2rem }
.tv__frase{ font-weight:600; font-size:1.0625rem; line-height:1.25 }
.tv__det{ font-size:.9375rem; opacity:.55 }
.tv__precio{ font-weight:700; font-size:.9375rem; margin-top:.15rem }
.tv__a:focus-visible{ outline:2px solid var(--paper); outline-offset:6px; border-radius:1.2rem }

@media (max-width:900px){ .top__rej{ grid-template-columns:repeat(2, 1fr) } }

@media (max-width:640px){
  /* Dos columnas, no carrusel. A 78vw de tarjeta se veia UNA por vez y para
     saber que habia detras habia que arrastrar a ciegas; con dos entran cuatro
     en la primera pantalla y se comparan de un vistazo, que es para lo que
     esta el escaparate. Y de paso desaparece el scroll horizontal, que dentro
     de una pagina que ya se desplaza en vertical siempre pelea. */
  .top__rej{ grid-template-columns:repeat(2, 1fr); gap:1rem .8rem }
  .tv__num{ font-size:1.8rem; top:.5rem; left:.65rem }
  .tv__foto img{ padding:9% }
  .tv__frase{ font-size:.9375rem; line-height:1.3 }
  .tv__det{ display:none }        /* con 165px de ancho, la tercera linea sobra */
  .top__cab{ margin-bottom:1.8rem }
}

/* ── los filtros de la tienda ─────────────────────────────
   Van en el HTML, no los pinta el JS: sin javascript se ven las tres familias
   enteras, que es el estado util. El script solo aporta el filtrado. */
.filtros{
  display:flex; flex-wrap:wrap; gap:.5rem;
  padding-inline:var(--edge); margin:0 0 .6rem;
}
.filtro{
  font:inherit; font-weight:600; font-size:.9375rem;
  min-height:44px; padding:.55rem 1.15rem;
  border:1.5px solid currentColor; border-radius:2rem;
  background:var(--paper); color:var(--ink); cursor:pointer;
  box-shadow:0 .25rem .6rem -.3rem rgb(0 0 0 / .18);
  opacity:.72; transition:opacity .2s var(--ease), background-color .2s var(--ease), color .2s var(--ease);
  -webkit-tap-highlight-color:transparent;
}
.filtro:hover{ opacity:.8 }
.filtro.is-on{ opacity:1; background:var(--ink); color:var(--paper) }
.filtro:focus-visible{ outline:2px solid var(--ink); outline-offset:3px }
.filtros__eco{
  padding-inline:var(--edge); margin:0 0 1.4rem;
  font-size:.9375rem; opacity:.55; min-height:1.4em;
}
.fam[hidden]{ display:none }

@media (prefers-reduced-motion:reduce){
  .tv__foto img, .tv__vuelta, .filtro{ transition:none }
}

/* ── quien es Benny ───────────────────────────────────────
   Rompe el ritmo entre dos bloques comerciales: el escaparate va sobre negro y
   la tienda sobre papel, asi que esto va en rojo. La foto NO se centra ni se
   mete en una caja: se sale por abajo contra el canto de la seccion, que es el
   mismo gesto del hero -- la cabeza apoyada, no flotando.

   Las gafas de la foto son del mismo rojo que el campo, asi que el retrato se
   pone en blanco y negro salvo ellas; el unico color de la seccion sale de su
   cara. */
.benny{
  position:relative; z-index:2;
  background:var(--red); color:var(--paper);
  overflow:clip;
  display:grid; align-items:end;
  grid-template-columns:minmax(0, 1fr) minmax(0, 1.05fr);
  gap:clamp(1.5rem, 4vw, 4rem);
  padding:clamp(3.5rem, 8vw, 6.5rem) var(--edge) 0;
}
.benny__foto{ margin:0; align-self:end; justify-self:center }
.benny__foto img{
  display:block; width:100%; height:auto;
  max-width:min(46rem, 100%);
  /* apoyada en el canto de abajo, sin sombra: el fondo del recorte ya es
     blanco y una sombra sobre rojo lo ensuciaria */
  margin-bottom:-1px;
}
.benny__txt{ padding-bottom:clamp(3rem, 7vw, 6rem); align-self:center }
.benny__h{
  font-family:var(--display); font-weight:700; margin:0 0 1.1rem;
  font-size:clamp(2.2rem, 6vw, 4.2rem); line-height:1; letter-spacing:-.01em;
}
.benny__p{ margin:0 0 .9rem; font-size:1.0625rem; line-height:1.55; max-width:34ch }
.benny__cta--sin-uso{
  display:inline-grid; place-items:center; min-height:44px;
  margin-top:.8rem; padding:.7rem 1.5rem;
  background:var(--paper); color:var(--ink); text-decoration:none;
  border-radius:2.4rem; font-weight:700;
  transition:scale .2s var(--ease);
}
.benny__cta:hover{ scale:1.04 }
.benny__cta:focus-visible{ outline:2px solid var(--paper); outline-offset:3px }

@media (max-width:760px){
  /* Texto arriba y cara abajo. Al reves la foto empuja el titulo fuera de la
     primera pantalla y la seccion abre con una barbilla. */
  /* El comentario de aqui arriba decia "texto arriba y cara abajo", y el CSS
     hacia lo CONTRARIO: no habia ningun `order`, mandaba el orden del DOM
     -- <figure> primero -- y la seccion abria con la foto. O sea abria por la
     barbilla, que es justo lo que el comentario decia estar evitando.
     Con el orden puesto, la foto ademas queda contra el canto de abajo y se
     apoya en el pie negro; antes se cortaba en seco a media altura con rojo
     debajo, y se leia como un recorte mal hecho. */
  .benny{ grid-template-columns:1fr; gap:0; padding-top:clamp(2.5rem, 8vw, 4rem) }
  .benny__txt{ order:1; padding-bottom:1.8rem }
  .benny__foto{ order:2; justify-self:center }
  .benny__foto img{ max-width:min(24rem, 88%) }
}

/* ── el carrito ───────────────────────────────────────────
   Cajon lateral, no pagina aparte: si comprar obliga a irse de la tienda se
   pierde el hilo de lo que se estaba mirando. Se cierra con el fondo, con la
   aspa y con Escape, que son las tres salidas que la gente prueba. */
.cesta{ position:relative }
.cesta__n{
  position:absolute; top:-4px; right:-4px;
  min-width:19px; height:19px; padding:0 5px;
  display:none; place-items:center;
  border-radius:10px; background:var(--red); color:var(--paper);
  font-size:.75rem; font-weight:700; line-height:19px;
}
.cesta[data-lleno="1"] .cesta__n{ display:grid }

/* El numero rebota cuando cambia. Es el unico aviso que queda si el comprador
   anade algo con el cajon ya abierto o desde una tarjeta. */
@keyframes cesta-rebota{
  0%  { scale:1 }
  38% { scale:1.42 }
  100%{ scale:1 }
}
.cesta.is-suma .cesta__n{ animation:cesta-rebota .42s var(--ease) }

/* ── la cesta que flota ───────────────────────────────────────────────────
   Se apoya justo encima del rail social y comparte su margen, para que las
   tres piezas de esa esquina lean como una columna y no como tres cosas
   sueltas que cayeron cerca.

   Vacia no existe: opacidad 0 Y pointer-events:none, no `display:none`. Asi
   puede entrar y salir con una transicion, y el lector de pantalla no anuncia
   un carrito vacio que nadie ha abierto. */
.cesta--flota{
  position:fixed; right:var(--edge);
  bottom:calc(6.2svh + 44px + .6rem);
  z-index:41;
  opacity:0; scale:.6; pointer-events:none;
  transition:opacity .28s var(--ease), scale .28s var(--ease);
}
.cesta--flota[data-lleno="1"]{ opacity:1; scale:1; pointer-events:auto }
/* Con la cesta de la tienda en pantalla sobran dos: el comprador tendria que
   decidir cual de los dos carritos es el suyo. */
.cesta--flota.is-doble,
.cesta--flota.is-hero{ opacity:0; scale:.6; pointer-events:none }
@media (prefers-reduced-motion:reduce){ .cesta--flota{ transition:none } }
.cesta.is-suma{ animation:cesta-rebota .42s var(--ease) .04s }

/* ── la foto que vuela hasta la cesta ─────────────────────────────────────
   Un clon de la foto del producto, en position:fixed, que va desde donde
   estaba hasta el boton del carrito. Se mide el punto de salida y el de
   llegada y se anima entre los dos (FLIP): asi funciona igual con la tarjeta
   en la rejilla que con la foto grande de la ficha, y no hay que escribir dos
   trayectorias.

   Por que se hace: sin esto, anadir algo desde una tarjeta no cambiaba nada en
   pantalla salvo un contador de 19px al otro lado. El vuelo dice DE DONDE sale
   lo que se compra y A DONDE va, que es la unica pregunta que tiene el que
   acaba de pulsar. */
.vuela{
  position:fixed; z-index:95; margin:0; pointer-events:none;
  object-fit:cover; border-radius:.6rem;
  box-shadow:0 .8rem 1.8rem rgb(0 0 0 / .3);
  will-change:transform, opacity;
}
@media (prefers-reduced-motion:reduce){
  .cesta.is-suma, .cesta.is-suma .cesta__n{ animation:none }
}

/* ── el boton de anadir, en la tarjeta ────────────────────────────────────
   Va como HERMANO del enlace y no dentro: la tarjeta entera es un <a>, y un
   <button> dentro de un <a> es HTML invalido -- el navegador lo saca del
   enlace al parsear y el resultado depende de cada motor.

   Aparece al pasar por encima en raton, y esta siempre visible en tactil:
   en un telefono no hay hover, y un boton que solo existe al pasar por encima
   ahi no existe nunca. */
.pz{ position:relative }
.pz__add{
  position:absolute; right:.55rem; top:.55rem; z-index:3;
  width:44px; height:44px; display:grid; place-items:center;
  border:0; border-radius:50%; padding:0; cursor:pointer;
  background:var(--ink); color:var(--paper);
  box-shadow:0 .3rem .8rem rgb(0 0 0 / .28);
  opacity:0; scale:.8;
  transition:opacity .2s var(--ease), scale .2s var(--ease), background-color .2s var(--ease);
  -webkit-tap-highlight-color:transparent;
}
.pz__add svg{ width:20px; height:20px; fill:none; stroke:currentColor;
              stroke-width:2; stroke-linecap:round; stroke-linejoin:round }
.pz:hover .pz__add,
.pz:focus-within .pz__add,
.pz__add:focus-visible{ opacity:1; scale:1 }
.pz__add:hover{ background:var(--red) }
.pz__add:active{ scale:.9 }
.pz__add:focus-visible{ outline:2px solid var(--red); outline-offset:3px }
@media (hover:none){ .pz__add{ opacity:1; scale:1 } }
@media (prefers-reduced-motion:reduce){ .pz__add{ transition:none } }

/* Entra deslizando, no aparece.

   Antes abrir era `panel.hidden = false` y punto. De display:none no se puede
   transicionar NADA -- el navegador no tiene fotograma anterior del que salir --
   asi que el cajon aparecia de golpe, entero, tapando media pantalla sin que
   nada explicara de donde habia salido. Ahora el atributo `hidden` se quita
   primero, se deja pasar un cuadro, y entonces entra la clase que dispara el
   deslizamiento. Al cerrar, al reves: sale la clase, y `hidden` vuelve cuando
   la transicion termina de verdad (transitionend), no a un setTimeout adivinado.

   El `hidden` del HTML se queda porque sin JavaScript el carrito no existe: es
   el estado correcto para quien llega sin scripts. */
.ca{ position:fixed; inset:0; z-index:80; display:flex; justify-content:flex-end }
.ca[hidden]{ display:none }
.ca__fondo{
  position:absolute; inset:0; border:0; padding:0; cursor:pointer;
  background:rgb(0 0 0 / .45);
  opacity:0; transition:opacity .34s var(--ease);
}
.ca__caja{
  position:relative; display:flex; flex-direction:column;
  width:min(26rem, 100%); background:var(--paper); color:var(--ink);
  box-shadow:-.6rem 0 2rem rgb(0 0 0 / .22);
  translate:100% 0;
  transition:translate .42s var(--ease);
}
.ca.is-abierto .ca__fondo{ opacity:1 }
.ca.is-abierto .ca__caja{ translate:0 0 }

/* La linea que acaba de entrar se enciende sola: con el cajon ya abierto y
   sumando una segunda camiseta, sin esto no se ve NADA cambiar salvo un numero
   al fondo. */
@keyframes ca-entra{
  from{ opacity:0; translate:0 -.5rem; background:color-mix(in srgb, var(--red) 12%, transparent) }
  to  { opacity:1; translate:0 0;      background:transparent }
}
.ca__li.is-nueva{ animation:ca-entra .5s var(--ease) both }

@media (prefers-reduced-motion:reduce){
  .ca__fondo, .ca__caja{ transition:none }
  .ca__caja{ translate:0 0 }
  .ca__li.is-nueva{ animation:none }
}
.ca__cab{
  display:flex; align-items:center; justify-content:space-between;
  padding:1.1rem 1.2rem; border-bottom:1px solid rgb(0 0 0 / .1);
}
.ca__h{ font-family:var(--display); font-weight:700; font-size:1.35rem; margin:0 }
.ca__x{
  border:0; background:none; font:inherit; font-size:1.7rem; line-height:1;
  width:44px; height:44px; cursor:pointer; color:inherit;
}
.ca__vacio{ margin:0; padding:2.4rem 1.2rem; opacity:.6; font-size:1rem }
/* overscroll-behavior:contain -- sin esto, llegar al final de la lista seguia
   arrastrando la pagina de detras y el comprador acababa mirando el pie de la
   web con el cajon abierto encima. */
.ca__lista{
  list-style:none; margin:0; padding:.6rem 1.2rem; flex:1;
  overflow-y:auto; overscroll-behavior:contain;
  scrollbar-width:thin; scrollbar-color:rgb(0 0 0 / .25) transparent;
}
.ca__lista::-webkit-scrollbar{ width:6px }
.ca__lista::-webkit-scrollbar-thumb{ background:rgb(0 0 0 / .22); border-radius:3px }
.ca__li{
  display:grid; grid-template-columns:56px 1fr auto; gap:.75rem;
  align-items:center; padding:.7rem 0;
  border-bottom:1px solid rgb(0 0 0 / .08);
}
.ca__img{ width:56px; height:56px; object-fit:cover; border-radius:.5rem; background:#eee }
.ca__txt{ display:grid; gap:.15rem; min-width:0 }
.ca__nom{ font-weight:600; font-size:.9375rem; line-height:1.25 }
.ca__var{ font-size:.9375rem; opacity:.6 }
.ca__cant{ display:flex; align-items:center; gap:.15rem; grid-column:2; margin-top:.3rem }
.ca__b{
  width:32px; height:32px; border:1.5px solid rgb(0 0 0 / .2); border-radius:50%;
  background:none; font:inherit; font-size:1rem; line-height:1; cursor:pointer; color:inherit;
}
.ca__n{ min-width:2ch; text-align:center; font-weight:700; font-size:.9375rem }
.ca__eur{ font-weight:700; font-size:.9375rem; align-self:start }
.ca__pie{ padding:1.1rem 1.2rem calc(1.1rem + env(safe-area-inset-bottom)); border-top:1px solid rgb(0 0 0 / .1) }
.ca__total{ display:flex; justify-content:space-between; margin:0 0 .8rem; font-size:1.0625rem }
.ca__pagar{
  width:100%; min-height:48px; border:0; border-radius:2.4rem;
  background:var(--ink); color:var(--paper); font:inherit; font-weight:700;
  font-size:1rem; cursor:pointer;
}
.ca__nota{ margin:.7rem 0 0; font-size:.9375rem; opacity:.55; text-align:center }
/* .is-carrito ya no bloquea nada: lo hace html.is-lock, que lleva la cuenta de
   cuantos paneles hay abiertos. Se queda como gancho de estado por si algo
   quiere saber que el cajon esta abierto. */

/* ── el boton de pedir, en la ficha ───────────────────── */
.ficha__pedir{ display:flex; gap:.5rem; flex-wrap:wrap; margin:.9rem 0 .2rem }
.ficha__sel{
  flex:1 1 11rem; min-height:44px; padding:.5rem .7rem;
  border:1.5px solid rgb(0 0 0 / .22); border-radius:.7rem;
  font:inherit; font-size:.9375rem; background:var(--paper); color:inherit;
}
.ficha__add{
  min-height:44px; padding:.6rem 1.3rem; border:0; border-radius:2.4rem;
  background:var(--ink); color:var(--paper); font:inherit; font-weight:700;
  font-size:.9375rem; cursor:pointer;
}
.ficha__add:active{ scale:.97 }
.ficha__no{ margin:.9rem 0 0; opacity:.6; font-size:.9375rem }

@media (max-width:520px){ .ca__caja{ width:100% } }
@media (prefers-reduced-motion:reduce){ .ficha__add, .benny__cta--sin-uso{ transition:none } }

/* la bio, tal como la tiene el en su perfil */
.benny__oficios{
  list-style:none; margin:0 0 1.4rem; padding:0;
  display:flex; flex-wrap:wrap; gap:.4rem .9rem;
  font-size:1.0625rem; font-weight:600;
}
/* Un punto entre oficios. Va en ::after del item ANTERIOR, no en ::before del
   siguiente, y eso no es una preferencia: con ::before el punto vive en la caja
   del item que EMPIEZA, asi que cuando la lista se parte en dos lineas -- y en
   un telefono se parte siempre -- la segunda ARRANCA con un punto colgando.
   Medido a 358px: "Caricaturista · Fotografo" / "· Camarografo · Productor".
   Es justo lo que el comentario anterior decia querer evitar, y pasaba igual.

   En ::after el punto viaja pegado a la palabra de delante: una linea puede
   TERMINAR en punto, que se lee como "sigue", pero ninguna puede empezar. */
.benny__oficios li:not(:last-child)::after{
  content:'·'; margin-left:.9rem; opacity:.55;
}
.benny__lema{
  font-family:var(--display); font-weight:700; margin:0;
  font-size:clamp(1.4rem, 3.4vw, 2.1rem); line-height:1.12;
  letter-spacing:-.01em;
}

/* sus redes, donde antes habia un boton de encargo */
.benny__redes{ display:flex; flex-wrap:wrap; gap:.6rem; margin-top:1.5rem }
.benny__red{
  display:inline-flex; align-items:center; gap:.5rem;
  min-height:44px; padding:.6rem 1.15rem;
  background:var(--paper); color:var(--ink); text-decoration:none;
  border-radius:2.4rem; font-weight:700; font-size:.9375rem;
  transition:scale .18s var(--ease);
}
.benny__red svg{
  width:19px; height:19px; flex:0 0 auto;
  fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}
.benny__punto{ fill:currentColor; stroke:none }
.benny__red:hover{ scale:1.04 }
.benny__red:focus-visible{ outline:2px solid var(--paper); outline-offset:3px }
@media (prefers-reduced-motion:reduce){ .benny__red{ transition:none } }

/* ── la barra de la tienda ────────────────────────────────
   Filtros y carrito viajan juntos y se quedan pegados arriba mientras se
   recorre la tienda. Antes el carrito se quedaba solo en la esquina y los
   filtros se perdian de vista al segundo scroll: para cambiar de categoria
   habia que volver arriba, y para ver lo que llevabas encima, tambien.

   Va en el DOM antes que las familias y con `top:0`, asi que se apoya en el
   canto de la ventana. El z-index queda por debajo del panel del carrito (80)
   y por encima de las tarjetas. */
.barratienda{
  position:sticky; top:0; z-index:20;
  display:flex; align-items:center; justify-content:space-between;
  gap:1rem; padding:.7rem var(--edge);
  margin-bottom:.4rem;
  /* Ni franja opaca de lado a lado ni nada: un DEGRADADO. La franja blanca
     entera cortaba la pagina en dos, pero sin nada las pildoras se apoyaban
     directamente sobre el titulo y el precio de la tarjeta que pasaba por
     debajo, y el texto salia rebanado a media letra. El degradado hace que lo
     que pasa por detras se disuelva en vez de cortarse.

     El extremo transparente se escribe con color-mix sobre el propio papel y
     no con `transparent` a secas: `transparent` es negro con alfa 0, y al
     interpolar desde un color claro deja una franja gris a mitad del recorrido. */
  background:none; pointer-events:none;
}
.barratienda::before{
  content:""; position:absolute; left:0; right:0;
  top:0; bottom:-2.2rem; z-index:-1; pointer-events:none;
  /* El tramo opaco cubre la barra ENTERA y el degradado empieza donde la barra
     acaba. Con la parada en un porcentaje del total, el desvanecido empezaba
     DENTRO de la barra y los titulos de la fila de arriba asomaban a media
     letra por detras de las pildoras. */
  background:linear-gradient(
    var(--paper) 0,
    var(--paper) calc(100% - 2.2rem),
    color-mix(in srgb, var(--paper) 0%, transparent) 100%);
}
.barratienda > *{ pointer-events:auto }
.barratienda .filtros{ padding-inline:0; margin:0; flex:1 1 auto }
.barratienda .cesta{ flex:0 0 auto; position:relative; margin:0 }

/* Sin scroll horizontal en el telefono: cuatro pildoras y el carrito no caben
   en 375px, y una barra que se arrastra al lado es peor que una que se parte. */
@media (max-width:520px){
  .barratienda{ flex-wrap:wrap; gap:.5rem }
  .barratienda .filtros{ order:2; flex:1 1 100% }
  .barratienda .cesta{ order:1; margin-left:auto }
  .filtro{ padding:.5rem .9rem; font-size:.9375rem }
}

/* ── la tienda en el telefono ─────────────────────────────
   Dos columnas. La rejilla pide 17rem por columna y en 375px solo entra una,
   asi que la tienda se recorria de uno en uno: diez pantallas para ver diez
   diseños, sin poder comparar dos que estan seguidos.

   La tarjeta ancha deja de serlo aqui: ocupando las dos columnas de un telefono
   vuelve a dejar una sola pieza por fila, que es justo lo que se quita. */
@media (max-width:640px){
  .rejilla{ grid-template-columns:repeat(2, minmax(0, 1fr)); gap:1rem .8rem }
  .pz--ancha{ grid-column:span 1 }
  /* La foto de la tarjeta ancha vuelve a ser CUADRADA aqui. El 2/1 existe para
     que ocupando dos columnas no le salga tambien el doble de alto; en cuanto
     deja de ocupar dos, ese mismo 2/1 la deja achatada al lado de una cuadrada
     -- distinto alto de foto, pies desalineados, y la rejilla deja de leerse
     como rejilla. Se veia en la primera fila de la tienda en un telefono. */
  .pz--ancha .pz__foto{ aspect-ratio:1/1 }
  .pz__frase{ font-size:.9375rem; line-height:1.3 }
  .pz__prenda, .pz__opt{ font-size:.9375rem }
  .tienda__cab{ margin-bottom:1.2rem }
}

@media (prefers-reduced-motion:reduce){
  .o3d::after{ transition:none }
  .o3d:hover .o3d__cuerpo, .o3d:focus-visible .o3d__cuerpo, .o3d:active .o3d__cuerpo{
    translate:0 0 0; scale:1.03;
  }
}

/* ── el menu, con imagen por item ─────────────────────────
   Sacado del video de la referencia frame a frame: cada linea del menu tiene
   SU imagen, y al pasar por encima aparece una pildora clara detras, el texto
   cambia de color y la imagen entra por la derecha DENTRO de la pildora. En
   "About" la imagen es otra cara distinta de la del retrato fijo; aqui pasa lo
   mismo -- la del retrato es la de las gafas rojas y la del hover es la otra.

   El numero delante (01, 02...) va porque el menu SI es una lista ordenada de
   secciones y el orden lo eligio alguien; no es adorno. */
.menu__link{
  position:relative; isolation:isolate; overflow:visible;
  display:flex; align-items:center; gap:.9rem;
  padding:.55rem 1.2rem; padding-right:clamp(6.5rem, 13vw, 9.5rem);
  border-radius:5rem;
  border-bottom:1px solid rgb(250 250 248 / .16);
}
.menu__n{
  flex:0 0 auto; font-size:.9375rem; opacity:.45;
  font-variant-numeric:tabular-nums; letter-spacing:.04em;
}
/* La pildora se dibuja detras con un pseudo-elemento y no con background:
   asi puede crecer de los lados sin mover ni un pixel del texto. */
.menu__link::before{
  content:''; position:absolute; inset:0; z-index:-1;
  border-radius:5rem; background:var(--paper);
  scale:.97; opacity:0;
  transition:scale .34s var(--ease), opacity .28s var(--ease);
}
.menu__link:hover::before,
.menu__link:focus-visible::before{ scale:1; opacity:1 }
.menu__link:hover, .menu__link:focus-visible{ border-bottom-color:transparent }
.menu__link:hover .menu__que,
.menu__link:focus-visible .menu__que{ color:var(--red) }
.menu__link:hover .menu__pie,
.menu__link:focus-visible .menu__pie,
.menu__link:hover .menu__n,
.menu__link:focus-visible .menu__n{ color:var(--ink); opacity:.6 }

.menu__foto{
  /* FUERA DEL FLUJO. La linea es flex y su alto lo marca el hijo mas alto, asi
     que al subir la pieza subia la linea con ella: medido, la linea pasaba de
     137px a 210 y la pieza NUNCA sobresalia -- se perseguian. Absoluta, la
     linea conserva su alto y la pieza si rompe el canto de arriba. */
  position:absolute; right:1.4rem; bottom:0;
  width:clamp(4.5rem, 11vw, 7.5rem);
  /* SOBRESALE. Mirando el video cuadro a cuadro, lo que da el volumen no es un
     giro: la pieza rompe el borde de ARRIBA de la pildora, va inclinada unos
     ocho grados y lleva sombra propia. El giro en Y de sesenta grados que habia
     aqui la ponia de canto, que no es lo que hace. */
  display:flex; align-items:flex-end; justify-content:center;
  overflow:visible;
  opacity:0;
  transition:opacity .26s var(--ease);
  pointer-events:none;
}
.menu__foto img{
  display:block; width:auto;
  /* MAS ALTA QUE LA LINEA, o no sobresale nada. La linea mide 137px y con
     7.4rem la pieza salia de 122: cabia dentro y el efecto no existia. Ahora
     el minimo esta por encima de la linea en cualquier ancho. */
  height:clamp(9.5rem, 15vw, 13rem);
  transform-origin:50% 100%;
  rotate:-7deg; translate:0 1.1rem; scale:.9;
  filter:drop-shadow(0 .5rem .8rem rgb(0 0 0 / .3));
  transition:translate .42s var(--ease), scale .42s var(--ease);
}
.menu__link:hover .menu__foto img,
.menu__link:focus-visible .menu__foto img{ translate:0 -.55rem; scale:1 }

/* La cara va recta y asoma mas: en el video la del About no esta inclinada
   como el libro, y saca casi media cabeza por encima del canto. */
.menu__link[href="#quien-es"] .menu__foto img{ rotate:0deg }
.menu__link[href="#quien-es"]:hover .menu__foto img,
.menu__link[href="#quien-es"]:focus-visible .menu__foto img{ translate:0 -1.2rem }
.menu__link:hover .menu__foto,
.menu__link:focus-visible .menu__foto{ opacity:1; translate:0 0 }

/* La cara del hover se sale un poco por arriba de la pildora, igual que en la
   referencia: es lo que hace que parezca pegada encima y no metida dentro. */
.menu__foto--cara{ height:clamp(4rem, 9vw, 6.4rem); margin-block:-.9rem }

@media (max-width:760px){
  .menu__link{ padding:.5rem .9rem; padding-right:5.6rem; gap:.6rem }
  /* La camisa es la pieza mas ancha del juego y a 375px se salia 11px por la
     derecha y se comia el texto. Se limita por ANCHO ademas de por alto: con
     solo el alto, cada pieza acaba de un ancho distinto segun su proporcion. */
  .menu__foto{ right:.7rem; width:5rem }
  .menu__foto img{ height:6.6rem; max-width:5rem; object-fit:contain }
  .menu__link[href="#quien-es"]:hover .menu__foto img,
  .menu__link[href="#quien-es"]:focus-visible .menu__foto img{ translate:0 -.7rem }
  .menu__n{ font-size:.9375rem }
  /* los circulos sociales se quedan dentro del menu, que es donde los pone la
     referencia; fuera de el siguen ocultos en el telefono */
  .is-menu-open .rail-social{ display:flex; position:static; margin-top:1.4rem }
}

@media (prefers-reduced-motion:reduce){
  .menu__link::before, .menu__foto{ transition:none }
  .menu__foto{ translate:0 0 }
}

/* ── la linea de socials del menu ─────────────────────────
   Es una linea mas del menu -- lleva su numero, como las otras cuatro -- pero
   no es un enlace: dentro van los circulos. Por eso es un div y no un <a>: un
   enlace con enlaces dentro no es HTML valido y el teclado se pierde. */
.menu__socials{
  display:flex; align-items:center; gap:.9rem;
  padding:.55rem 1.2rem;
  border-bottom:1px solid rgb(250 250 248 / .16);
  opacity:0; translate:0 .8rem;
  transition:opacity .4s var(--ease), translate .4s var(--ease);
}
.is-menu-open .menu__socials{ opacity:1; translate:0 0; transition-delay:.44s }
.menu__redes{ margin-left:auto; display:flex; gap:.5rem }
.menu__redes a{
  width:44px; height:44px; border-radius:50%;
  border:1px solid color-mix(in srgb, var(--on-field) 42%, transparent);
  display:grid; place-items:center; color:var(--on-field);
  transition:background-color .22s var(--ease), color .22s var(--ease);
}
.menu__redes a:hover{ background:var(--on-field); color:var(--field) }
.menu__redes a:focus-visible{ outline:2px solid var(--on-field); outline-offset:3px }
.menu__redes svg{
  width:21px; height:21px; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
}
.menu__redes .social__punto{ fill:currentColor; stroke:none }

@media (prefers-reduced-motion:reduce){
  .menu__foto img{ transition:none; translate:0 -.55rem; scale:1 }
}
