/* Matteria — capa de la CINTA (scroll continuo + animaciones, Eric).
   Todo lo que las landings de la cinta (ficha5 = lay-hero-card, ficha4 =
   lay-hero) añaden SOBRE el CSS de José Luis. Cargar SIEMPRE después de
   colorN.css. Aquí no se toca ninguna de sus hojas: cuando él consolide
   algo en base.css / entry-hero.css, se borra de aquí.
   Origen: nuestra capa de base.css v5, entry-hero.css y ficha5.css v16
   (sistema anterior), re-homada el 21-ago al CSS reorganizado. */


/* ==== 1. Base compartida ==== */

/* Hover suave por defecto: los cambios de color de enlaces y botones se
   deslizan con el easing de la casa. Las reglas específicas mandan. */
a, button {
  transition: color 0.3s var(--ease), background-color 0.3s var(--ease),
    border-color 0.3s var(--ease), opacity 0.3s var(--ease);
}
/* Deslizamientos de 3px y cambios de color de las listas, al ritmo de la casa
   (petición de José Luis, 15-ago: nada de «ease» genérico a 0.18s) */
.entry-links li span, .entry-links li svg,
.author-works li span, .author-works li svg,
.fold-specs dt, .fold-specs dd,
.release-row dt, .release-row dd {
  transition: translate 0.32s var(--ease), color 0.3s var(--ease);
}
.team-avatar::after { transition: opacity 0.3s var(--ease), transform 0.3s var(--ease); }

/* Scroll suave (Lenis, vendorizado en assets/js/vendor) */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

/* Cifras en tabular para que el tambor no baile el ancho */
.stat-figure { font-variant-numeric: tabular-nums; }

/* ---- Cifras de tambor (scroll-extras.js) ---- */
/* Cada dígito es la ventana de un tambor: la columna de cifras rueda hasta
   asentarse en su valor, como el contador de una calculadora mecánica. */
.odo {
  display: inline-flex;
  overflow: hidden;
  vertical-align: bottom;
  /* Respiro lateral: el interletrado negativo deja la tinta del dígito a un
     par de píxeles del borde y el redondeo del recorte rebanaba el canto */
  padding-inline: 0.06em;
  margin-inline: -0.06em;
}
.odo-reel { display: block; transition: transform 1.7s var(--ease); }
/* Caja holgada por cifra: el interlineado de la cifra estática es menor que
   el cuerpo y la tinta lo desborda; scroll-extras.js compensa la celda más
   alta con márgenes negativos para que el hueco en la fila no cambie */
.odo-reel span { display: block; line-height: 1.2; }

/* Las comillas «» de la cita van en el texto real (así entran en el troceado
   por palabras y se funden con la primera y la última), no en pseudoelementos */
.author-quote p::before, .author-quote p::after { content: none; }


/* ==== 2. Hero ==== */

/* El logo entra solo con fundido, sin desplazamiento (petición 15-ago) */
@keyframes logoFade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: no-preference) {
  .entry-top[data-load][data-shown] .logo-face { animation-name: logoFade; }
}

/* Salida del hero: ficha.js escribe --hero-exit (0→1 mientras la tarjeta sale
   de pantalla). La tarjeta remolonea al salir con su contenido dentro, en
   bloque y en sincronía, mientras el contenido se funde. translate y no
   transform, para no pisar los revelados de carga ni el tilt. */
@media (prefers-reduced-motion: no-preference) {
  .entry-hero2 > .hero2-body { translate: 0 calc(var(--hero-exit, 0) * 40px); }
  .hero2-body .entry-header,
  .hero2-body .entry-cover { opacity: calc(1 - var(--hero-exit, 0) * 1.25); }
}

/* El lienzo 3D desborda el hueco por los cuatro lados: al girar, las esquinas
   del libro se proyectan fuera y sin este margen se cortarían. book3d.js
   compensa el zoom midiendo la demasía. No captura el puntero: los eventos
   viven en el hueco (.book3d). SOLO escritorio: en móvil no hay vuelo al
   estante y la demasía provocaba el overflow-x de la página (el lienzo
   asomaba 100px por la derecha — feedback de Eric, 24-ago). */
@media (min-width: 961px) {
  .entry-cover .book3d canvas {
    display: block;
    position: absolute;
    left: -40%;
    top: -40%;
    width: 180%;
    height: 180%;
    pointer-events: none;
  }
}

/* Perspectiva de la tarjeta siguiendo el puntero (sutil): hero-tilt.js escribe
   --tilt-x / --tilt-y (grados) con el mismo amortiguado que el libro 3D. Solo
   escritorio con puntero fino; en táctil y reduced-motion no existe.
   SOLO en la disposición de tarjeta (lay-hero-card): en el hero a sangre de
   la ficha 4 no hay tarjeta que inclinar ni iluminar (feedback de Eric,
   21-ago), y el contra-giro del libro sin tarjeta detrás quedaría suelto. */
@media (prefers-reduced-motion: no-preference) and (min-width: 961px) and (pointer: fine) {
  body.lay-hero-card .entry-hero2 { perspective: 1400px; }
  body.lay-hero-card .entry-hero2 > .hero2-body {
    transform: rotateX(calc(var(--tilt-x, 0) * 1deg)) rotateY(calc(var(--tilt-y, 0) * 1deg));
  }
  /* Luz sobre el papel: un brillo tenue que acompaña al puntero, entre el
     grano (::before) y el contenido; hero-tilt.js escribe su posición */
  body.lay-hero-card .hero2-body::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    pointer-events: none;
    background: radial-gradient(clamp(360px, 42vw, 640px) circle at var(--sheen-px, 50%) var(--sheen-py, 50%), var(--veil-white-10), transparent 65%);
    opacity: var(--sheen-o, 0);
    transition: opacity 0.6s var(--ease);
  }
  body.lay-hero-card .hero2-body > * { position: relative; z-index: 1; }
  /* El libro cede en sentido contrario a la tarjeta: profundidad entre capas */
  body.lay-hero-card .entry-hero2 > .hero2-body .entry-cover {
    transform: rotateX(calc(var(--tilt-x, 0) * -0.7deg)) rotateY(calc(var(--tilt-y, 0) * -0.7deg));
  }
}

/* El sello «2ª Edición» (.cover-badge) se pinta tal cual lo trae el base.css
   de José Luis (pastilla colgando del borde superior del marco, badgeIn):
   aquí no se toca (feedback de Eric, 21-ago). */


/* El carrusel en teléfono: la hoja de José Luis deja --slide-span: 2 en
   ≤767px, que con las 2 columnas de tablet es el ancho completo — pero en
   ≤479px la retícula baja a 1 columna y el span de 2 hacía slides al 200%
   del ancho (feedback de Eric, 24-ago: «el slider no me va bien»). Una
   columna: el slide llena el contenido y el siguiente asoma por el sangrado
   derecho. Candidato a consolidar en su entry-hero.css/entry.css (las
   fichas 1-3 lo arrastran igual). */
@media (max-width: 479px) {
  .gallery { --slide-span: 1; }
}
/* Y la segunda foto asoma un pelín más en el primer vistazo (Eric, 24-ago:
   «que se vea 1% más»): la fórmula de ancho de la casa, al 99%. */
@media (max-width: 767px) {
  .gallery {
    --slide-w: calc((var(--slide-span) * var(--grid-col) + (var(--slide-span) - 1) * var(--grid-gutter)) * 0.99);
  }
}

/* La última slide RESPETA el margen derecho al llegar al final del carrusel
   (Eric, 24-ago): la hoja de José Luis abre con aire (padding-left) pero
   cierra a cero y la última foto moría pegada al borde de la pantalla. El
   mismo aire que abre, cierra: en escritorio el sangrado completo (la foto
   remata donde remata el contenido de la retícula), en móvil el margen. */
.slider { padding-right: var(--bleed-pad); }
@media (max-width: 767px) {
  .slider { padding-right: var(--edge); }
}

/* El lightbox en móvil enseña la foto ENTERA (Eric, 24-ago: «lo veo zoomeado
   y no puedo ver la imagen entera»): el object-fit: cover de la casa llena la
   pantalla recortando — bien en apaisado de escritorio, pero en vertical de
   móvil una foto 16:9 quedaba amputada. Contain solo en pantallas estrechas. */
@media (max-width: 960px) {
  body.lay-hero-card .lightbox-stage img,
  body.lay-hero .lightbox-stage img { object-fit: contain; }
}

/* Arrastre del carrusel con ratón (gallery.js v3): en táctil el scroll ya es
   nativo; con ratón no existía y el cursor grab de la casa prometía lo que
   no hacía. Mientras se arrastra, fuera el snap y la selección de texto. */
.slider { cursor: grab; }
.slider.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
  scroll-behavior: auto;
  user-select: none;
}
.slider.is-dragging .slide { pointer-events: none; }


/* ==== 3. Libro de estantería (cover-pin.js) y compra pegajosa ==== */

/* Bloque de compra pegajoso: acompaña la lectura. Su tope real lo escribe
   cover-pin.js (borde inferior del libro fijado); 48px es el respaldo. */
@media (min-width: 961px) {
  .entry-side { position: sticky; top: 48px; align-self: start; }
}

/* cover-pin.js fija el libro desde la carga y lo tumba en el estante mientras
   pasa la descripción. Selectores SIN el ancestro .hero2-body: la figura se
   reparenta a <body> (un fixed dentro de la tarjeta con transform dejaría de
   ser fijo), así que estas reglas deben alcanzarla también fuera. */
/* Especificidad: las reglas de portada de José Luis van como
   «body.lay-hero-card .entry-cover» / «body.lay-hero .entry-cover», así que
   las nuestras llevan el mismo prefijo (y ganan por orden de carga). */
@media (prefers-reduced-motion: no-preference) and (min-width: 961px) {
  /* La figura no se funde con la salida del hero: el libro se queda */
  body.lay-hero-card .entry-cover,
  body.lay-hero .entry-cover { opacity: 1; overflow: visible; }
  /* El lienzo desborda la figura: el libro tumbado al ancho del botón de
     comprar necesita sitio para no recortarse */
  /* Márgenes SIMÉTRICOS arriba/abajo (antes -18%/-24%): el libro se centra en
     el hueco y, con el reposo plano, un hueco descentrado lo dejaba unos
     píxeles bajo del centro de la vitrina (Eric: «no está simétrico») */
  body.lay-hero-card .entry-cover .book3d,
  body.lay-hero .entry-cover .book3d { inset: -21% -26%; }
  /* La figura viaja por encima de la columna de compra: si capturase el
     puntero robaría los clics al bloque de compra. Solo el visor 3D
     conserva el arrastre. */
  body.lay-hero-card .entry-cover,
  body.lay-hero .entry-cover { pointer-events: none; }
  body.lay-hero-card .entry-cover .book3d,
  body.lay-hero .entry-cover .book3d { pointer-events: auto; }
  /* El libro viajero va desnudo: marco, halo y sello se quedan en la vitrina
     (.cover-case, el doble dentro de la tarjeta). Borde transparente y no 0
     para que el tamaño no cambie respecto al doble que le da medida. */
  body.lay-hero-card .entry-cover.is-flying,
  body.lay-hero .entry-cover.is-flying { border-color: transparent; }
  body.lay-hero-card .entry-cover.is-flying::before,
  body.lay-hero .entry-cover.is-flying::before { display: none; }
}


/* ==== 4. Cinta: cruce global de paleta ==== */

/* Las variables de color de la hoja de paleta (colorN.css) se registran como
   <color> para que el navegador sepa interpolarlas: al cambiar de paleta en
   <html> (clase .palette-next, la pone next-entry.js cuando el punto medio de
   la pantalla pisa el libro siguiente), TODO lo que bebe de ellas — fondo,
   textos, botones, velos derivados de --ink — cruza a la vez.
   Los initial-value son los de color5.css (solo valen si la hoja no define). */
@property --paper { syntax: '<color>'; inherits: true; initial-value: #fbf5ef; }
@property --primary { syntax: '<color>'; inherits: true; initial-value: #50110c; }
@property --bg-body { syntax: '<color>'; inherits: true; initial-value: #6b1a14; }
@property --secondary { syntax: '<color>'; inherits: true; initial-value: #e76a4d; }
@property --ink { syntax: '<color>'; inherits: true; initial-value: #f1e8f0; }
@property --ink-light { syntax: '<color>'; inherits: true; initial-value: #f8cfa1; }
@property --dark { syntax: '<color>'; inherits: true; initial-value: #25251c; }
@property --accent { syntax: '<color>'; inherits: true; initial-value: #fd750a; }
@property --accent-2 { syntax: '<color>'; inherits: true; initial-value: #eb9428; }

:root {
  /* Ease-in-out y no el easing de la casa: el expo-out concentra el cambio en
     los primeros ~300ms y el fundido se sentía instantáneo por larga que
     fuera la duración. La curva simétrica reparte el color por los 600ms
     enteros. (Única excepción al easing único: solo color, no movimiento.)
     OJO: esta declaración pisa la «transition: background-color 1s» que
     base.css pone en html para su tinte por sección (data-tint): en la cinta
     el fondo lo lleva la propia variable, y dos amortiguados encadenados
     dejaban cola. */
  transition:
    --paper 0.6s ease-in-out, --primary 0.6s ease-in-out, --bg-body 0.6s ease-in-out,
    --secondary 0.6s ease-in-out, --ink 0.6s ease-in-out, --ink-light 0.6s ease-in-out,
    --dark 0.6s ease-in-out, --accent 0.6s ease-in-out, --accent-2 0.6s ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
  :root { transition: none; }
}

/* Paleta del libro siguiente (maqueta Maintenance): tinta nocturna, crema de
   papel y oro viejo — deliberadamente opuesta a la roja. Mismos papeles que
   en colorN.css: --bg-body fondo de página, --secondary superficies (la
   tarjeta del hero bebe de ella vía --paper-tint), --accent botón y enlaces. */
html.palette-next {
  --paper: #faf6e8;
  --primary: #0a1016;
  --bg-body: #10181f;
  --secondary: #1c2935;
  --ink: #f0ead7;
  --ink-light: #cdbf98;
  --dark: #090e13;
  --accent: #c8a35c;
  --accent-2: #d8b76a;
}

/* La ilustración de Adriano es tinta negra: sobre la paleta nocturna se
   invierte a tinta crema para que respire con el fondo (el libro B reutiliza
   el interior de Olivetti como placeholder) */
[data-book="maintenance"] .entry-portrait { filter: invert(0.92) sepia(0.32) saturate(0.6); }


/* ==== 5. Cinta: bucle infinito ==== */

.book-wrap[hidden] { display: none; }

/* Pista del bucle: fondo plano tras la costura del último libro. El salto
   dispara al cruzar el techo del clon; el resto es recorrido para que la
   inercia no muera contra el tope del documento. */
.loop-slack { height: 200vh; }

/* El clon-costura: mismo render de título que el hero real (a este el JS le
   fuerza transform: none sobre el scaleX del CSS; sin igualarlo, las letras
   del clon salían con otra caja y el empalme se notaba) */
.loop-seam .entry-title { transform: none; }

/* Pie cortina bajo cada libro, con el gesto de la cortina de JL (pie fijo,
   ventana entera, tarjeta centrada, la página sube descubriéndolo) pero dentro
   de una cinta sin final. Receta: el pie mide una ventana, se pega al techo
   (sticky) y arranca UNA VENTANA ANTES de donde le toca (margen negativo), así
   queda escondido bajo el final del libro; al subir el libro lo descubre
   (aparece), se sostiene solo en pantalla un tramo (margen inferior) y el
   libro siguiente —o la costura— sube por encima y lo tapa (desaparece).
   Quien tapa lleva escalón de apilamiento y fondo opaco. El pie de A va FUERA
   de su book-wrap (hermano entre los dos libros): como último hijo el sticky
   no tendría recorrido. Feedback de Eric: «el sticky tiene que estar en el
   centro de la pantalla y la cortina hacer aparecer y desaparecer el elemento»,
   con la ficha 5 de JL como referencia. */
.club--loop {
  position: sticky;
  top: 0;
  z-index: 0;
  min-height: 100dvh;
  align-content: center;
  /* El centrado exacto se sentía alto (Eric: «queda un poco arriba»): el
     bloque baja un 10% de la ventana. Solo arriba: abajo lo que hay es la
     barra inferior, que no debe salirse. */
  padding-block: 10vh 0;
  background: var(--bg-body);
  margin-top: -100dvh;
  /* Recorrido tras descubrirse: una ventana para que el libro anterior salga
     del todo y un tramo más (30vh) con el pie solo, antes de que lo tape el
     siguiente */
  margin-bottom: 130vh;
}
/* Lo que descubre y lo que tapa: los artículos de cada libro (sobre su propio
   pie por delante y sobre el pie del libro anterior) y la costura */
.book-wrap > .entry,
.loop-seam-zone {
  position: relative;
  z-index: 1;
  background: var(--bg-body);
}
.club--loop + .book-wrap {
  position: relative;
  z-index: 2;
}
@media (prefers-reduced-motion: reduce) {
  .club--loop { position: static; margin: 0; }
}
/* El final del libro es el borde de la cortina: menos aire tras los pósters
   para que no descubra el pie una franja vacía. El collage lo dimensiona
   ficha.js en línea (figura = 100vh, cartulinas centradas en el 72%): en
   escritorio la figura se ajusta a lo que ocupan las cartulinas (!important
   porque el JS escribe el estilo en línea; ~110-130px bajo la más alta a
   1280-1710). En móvil el reparto es otro y no se toca. */
.book-wrap .posters { padding-bottom: var(--space-12); }
@media (min-width: 961px) {
  .book-wrap .scatter {
    height: clamp(30rem, 42vw, 38rem) !important;
    align-items: flex-start;
  }
}

/* Separador de asteriscos en móvil: su margen propio (96px arriba y abajo) se
   sumaba al aire que ya ponen el autor y el equipo (96px cada uno) y entre esas
   dos secciones había ~420px frente a los 192 que separan a las demás. Sin
   margen propio, las estrellas quedan a 96px de cada vecino: el mismo salto
   que hay entre cualquier otro par de secciones. (Eric, ficha 5 a 363px: «el
   espacio entre los asteriscos y team grid y lo de arriba es un poco demasiado,
   acórtalo manteniendo la simetría».) */
@media (max-width: 960px) {
  .book-wrap .entry-divider { margin-block: 0; }
}
