:root {
  --glass-bg-color: 255, 255, 255; 
  --glass-opacity: 0.4; 
  --glass-blur: 10px; 
  --glass-radius: 8px; 
  /* Perilla de control para el tiempo de aparición de la etiqueta de audio en móvil */
  --tab-fade-time: 0.8s;
  /* Perillas del reproductor (Valores por defecto si config.js falla) */
  --gap-title-wave-scroll: 12px;
  --gap-title-wave-zoom: 12px;
  --gap-wave-controls-scroll: 15px;
  --gap-wave-controls-zoom: 15px;
  --player-bottom-scroll: 1rem;
  --player-bottom-zoom: 1rem;
  --tab-offset: -4px;
  --contact-mobile-top: 2rem;
  --contact-mobile-font-size: 0.65rem;
  --about-hover-zone-width: 90px;
  --about-cursor-label-font-size: 0.85rem;
  --about-panel-width: 65vw;
  --about-ring-bottom-offset: 2.5rem;
  --about-ring-size: 28px;
  --about-canvas-gap: 48px;
  --about-parallax-bleed: 120px;
}

* {
  box-sizing: border-box;
  outline: none;
}

html,
body {
  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 19px;
  height: 100%;
  margin: 0;
  padding: 0;
}

p,
h1,
h2 {
  padding: 0 1rem;
}

body {
  height: 100vh;
  width: 100vw;
  overflow: hidden;
}

.post-container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  position: fixed;
  top: 0;
  left: 0;
  transition: none !important;
  pointer-events: none;
  /* Marco fijo: SOLO recorta a los bordes de la pantalla. Nunca se
     transforma ni anima (ver .post-canvas más abajo, que es lo que en
     verdad se mueve/escala) — así el recorte a los 4 bordes siempre queda
     perfecto, pase lo que pase con la escala del lienzo de adentro. */
}

/* Lo que main.js pan/escala de verdad (antes era ".post-container" mismo).
   Deliberadamente más alto que la pantalla (ver altura de abajo): al
   achicarse con "scale" para dar la sensación de "alejarse" en el eje Z al
   abrir el About (ver window.setAboutCanvasScale en main.js), sus bordes
   reales siguen llegando de sobra hasta el marco fijo de arriba, que es
   quien de verdad recorta — así nunca hace falta animar ningún alto/ancho
   real (reflow costoso), solo "transform" (barato, sin reflow). El
   transform-origin "left top" ancla el escalado a esas esquinas: la
   distancia con el panel de About sigue dependiendo solo del translateX de
   siempre (setAboutCanvasPush), sin que la escala la altere. */
.post-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 250vh; /* alcanza de sobra hasta con una reducción de escala de 0.6 */
  transform-origin: left top;
}

.post-container .post {
  pointer-events: auto; /* Solo los posts pueden recibir clicks */
  position: absolute;
  top: 0;
  left: 0;
  width: 20vw;
  height: auto;
}

/* Los videos son 16:9 (horizontales): al mismo ancho que una foto se ven más
   chicos porque su caja es más baja. Les damos un poco más de ancho para que
   el "área" se sienta similar a la de las fotos dentro de la lluvia. */
.post-container .post.is-video-post {
  width: 32vw;
}

/* SIN ESTO, este ancho de arriba no hacía nada: a diferencia de una foto (la
   imagen tiene tamaño intrínseco propio y ".inner" se ajusta solo a él),
   ".video-embed-wrapper" es un simple contenedor sin contenido intrínseco
   una vez que el iframe de YouTube pasa a ser width:100% por CSS — en ese
   caso el navegador ignora el ancho real de ".post" y ".inner" (que no tiene
   ancho propio) colapsa al tamaño por defecto de un iframe (~300px), sin
   importar cuánto creciera ".post". Fijándole 100% a ".inner" acá, el video
   sí sigue el ancho real de ".post" (esto no hace falta en las fotos).
*/
.post-container .post.is-video-post .inner {
  width: 100%;
}

.post-container .post .inner {
  pointer-events: auto;
  display: inline-block;
  padding: 0;
  position: relative;
  z-index: 2;
  background-color: #fff;
}

/* Forzar el centro de gravedad para animaciones de escala GSAP */
.post .inner {
  transform-origin: center center !important;
}

.post.is-expanded {
  z-index: 2147483000 !important;
}

.post.is-expanded .inner {
  transform-origin: center center !important;
  overflow: visible !important;
}

.post.is-expanded.is-extreme-ratio img {
  object-fit: contain !important;
  background: #000;
}

.post-container .post img {
  object-fit: cover;
  object-position: center;
  width: 100%;
  height: auto;
  position: relative;
  z-index: 2;
  background: #111;
  display: block;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transform: translateZ(0);
}

/* Proyectos de VIDEO (archivo propio, vía Plyr — ver js/video.js): ocupan el
   mismo lugar que ocuparía el <img>, con el mismo z-index relativo a la
   pestaña (.info-tab) para que el hover y el "mantener visible mientras
   reproduce" se comporten igual que en las fotos. Plyr arma su propio
   reproductor (controles, miniatura antes de reproducir, pantalla completa)
   DENTRO de este contenedor; nosotros solo necesitamos que ocupe el 100% de acá. */
.video-embed-wrapper {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9; /* Escritorio: alto proporcional al ancho, como un video real */
  background: #111;
  overflow: hidden;
  z-index: 2;
}

.video-embed-wrapper .plyr,
.video-embed-wrapper .plyr__video-wrapper {
  width: 100%;
  height: 100%;
}

/* Controles propios de Plyr (play, línea de tiempo, volumen, pantalla
   completa): ocultos hasta que el usuario le da play desde NUESTRO ícono (el
   de la pestaña, .play-btn) — recién ahí ".post" gana la clase
   "video-playing" (ver video-state-change en js/main.js) y se revelan. Antes
   de eso solo se ve la miniatura/primer fotograma, sin ninguna barra encima. */
.video-embed-wrapper .plyr__controls {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.post.video-playing .video-embed-wrapper .plyr__controls {
  opacity: 1;
  pointer-events: auto;
}

#mobile-player {
  display: none;
  pointer-events: auto; /* El player escucha */
  touch-action: none;   /* Evita que el SO intente hacer scroll nativo aquí */
}

/* Minireproductor (solo móvil, ver @media más abajo) */
#mini-player {
  display: none;
}


#site-title {
  position: fixed;
  top: 2rem;
  left: 0.8rem;
  /* Por encima incluso del panel de About (2147483001) y su flecha: así el
     nombre se siente parte del mismo lienzo, no algo que el panel tapa. */
  z-index: 2147483002;
  display: inline-block;
  margin: 0;
  
  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: clamp(1.6rem, 1.9vw, 2.1rem); 
  font-weight: 300; 
  letter-spacing: 0.02em; 
  line-height: 1;
  padding: 0 var(--text-box-px, 15px); 
  background-color: transparent; 
  background-image: linear-gradient(#ffffff, #ffffff); 
  background-size: 100% var(--text-box-py, 75%); 
  background-position: center; 
  background-repeat: no-repeat;
  color: #000000;
  border: none; 
  
  opacity: 1;
  transition: opacity 0.75s ease-in-out;
}

#site-title img {
  max-height: 2.5rem; 
  width: auto;
  display: block;
}

#site-title.is-hidden {
  opacity: 0;
  pointer-events: none;
}

#site-title.about-transition-hidden {
  opacity: 0;
  pointer-events: none;
}


/* Segundo acceso al About (solo escritorio): franja invisible pegada al borde
   izquierdo. Su ancho es una variable (--about-hover-zone-width, editable
   desde aboutConfig.hoverZoneWidth en config.js) justamente para poder probar
   distintos anchos y ver a partir de cuál empieza a estorbar la interacción
   con las fotos/videos que floten por esa columna. z-index moderado a
   propósito: alto para tapar fotos "en reposo" (z-index:0), pero por debajo
   de cualquier foto que ya esté en hover (que sube por encima de 100), así
   que una foto que ya estás tocando no se ve interrumpida a medio camino. */
#about-hover-zone {
  position: fixed;
  top: 0;
  left: 0;
  width: var(--about-hover-zone-width, 90px);
  height: 100vh;
  z-index: 50;
  cursor: pointer; /* Ya no reemplaza al puntero nativo — ver #about-cursor-label */
  background: transparent;
}

/* Palabra "About"/"Home": ya NO sigue al cursor — vive fija en el punto
   medio del espacio entre el panel (cerrado: 0) y el lienzo, y se mueve en
   vivo con la posición REAL del lienzo (ver positionAboutWord en
   js/about.js), con el mismo resorte de mouse que el resto del parallax —
   misma sensación que "estar pegada a esa capa" en vez de reemplazar el
   puntero. Fija verticalmente al centro de la pantalla; "left" lo anima JS
   en cada cuadro. Sin franja invisible que "active" su aparición: al
   acercar el mouse al borde izquierdo, el parallax invertido de la cámara
   (ver applyPan en js/main.js) la corre hacia la derecha y la trae a la
   vista sola — por eso no necesita su propio fade de opacidad. Un solo
   elemento para las dos direcciones (ver updateAboutWordLabel en
   js/about.js): cerrado muestra "About" sola, abierto muestra "Home" + la
   flecha (oculta por defecto, ver el estilo inline en index.html). */
#about-cursor-label {
  position: fixed;
  top: 50%;
  left: 0;
  transform: translate(-50%, -50%);
  z-index: 2147483002; /* Por encima incluso del panel de About */
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: 0.4rem;

  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: var(--about-cursor-label-font-size, 0.85rem);
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #000000;
}

/* Salida del About (solo escritorio): mientras el panel está abierto, cubre
   TODA el área del lienzo de proyectos que queda visible del lado derecho
   (desde donde termina la caja del panel, bleed incluido, hasta el borde
   derecho de la pantalla) — no una franja angosta, sino toda esa zona. Oculta
   por defecto (display:none) y solo se activa mientras el About está abierto
   (ver body.about-open más abajo), para no taparle nunca el lienzo al usuario
   cuando el About está cerrado. */
#home-hover-zone {
  position: fixed;
  top: 0;
  left: calc(var(--about-panel-width, 75vw) + var(--about-parallax-bleed, 120px));
  right: 0;
  height: 100vh;
  z-index: 50;
  cursor: pointer; /* Ya no reemplaza al puntero nativo — la palabra "Home" la muestra #about-cursor-label, fija */
  background: transparent;
  display: none;
}

body.about-open #home-hover-zone {
  display: block;
}

/* Reemplaza al puntero (lo sigue) al pasar el mouse sobre un proyecto —
   mismo patrón que #about-cursor-label, un ícono en vez de texto. Un solo
   elemento compartido: lo posiciona/muestra js/main.js (lienzo normal) y
   js/about.js (proyectos que asoman con el About abierto), vía
   window.showPostCursorIcon/hidePostCursorIcon. */
#post-cursor-icon {
  position: fixed;
  top: 0;
  left: 0;
  transform: translate(-50%, -50%);
  z-index: 2147483002;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
  color: #ffffff;
}

#post-cursor-icon.is-visible {
  opacity: 1;
}

/* El proyecto que YA está sonando/reproduciéndose muestra el ícono de pausa
   en vez de play mientras el mouse pasa por encima — el resto sigue
   mostrando play (ver isPostPlaying/refreshPostCursorIconState en main.js). */
#post-cursor-icon .icon-pause {
  display: none;
}

#post-cursor-icon.is-playing .icon-play {
  display: none;
}

#post-cursor-icon.is-playing .icon-pause {
  display: block;
}

@media (max-width: 768px) {
  #about-hover-zone,
  #about-cursor-label,
  #home-hover-zone {
    display: none !important; /* Este segundo acceso es exclusivo de escritorio */
  }

  #post-cursor-icon {
    display: none !important; /* No hay cursor de mouse que reemplazar en móvil */
  }
}

/* A la inversa: estos dos son exclusivos de MÓVIL (segundo acceso por
   arrastre) — sin este bloqueo explícito, sus tickers de posición (ver
   positionEntryIndicator/positionExitIndicator en js/about.js) corren
   igual en escritorio, porque ahí "isOpen"/el lienzo también existen (solo
   que los mueve el mouse en vez del dedo) — sin ningún gesto táctil que
   los mantenga en 0, se volvían visibles en medio de la pantalla, como una
   SEGUNDA palabra "About" flotando aparte de #about-cursor-label. */
@media (min-width: 769px) {
  #about-entry-indicator,
  #about-exit-indicator {
    display: none !important;
  }
}

/* Segundo acceso en MÓVIL: arrastre hacia la derecha (ver js/about.js).
   Vive pegado al borde izquierdo y empieza OCULTO fuera de pantalla
   (translateX(-100%)): la idea es que se sienta como si el About ya
   estuviera ahí, justo fuera del marco, y arrastrar lo va "asomando" — por
   eso la posición (no la opacidad) es lo que anima JS en cada touchmove,
   de 0 (oculto del todo) a 1 (totalmente asomado = trigger). */
#about-entry-indicator {
  position: fixed;
  top: 50%;
  left: 0;
  z-index: 2147483002; /* Por encima incluso del panel de About */
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  /* Valor de respaldo antes de que js/about.js lo posicione en cada cuadro
     (ver positionEntryIndicator) — fijo a una distancia constante del
     lienzo, ya no un porcentaje atado al arrastre. */
  transform: translateY(-50%) translateX(-110px);
}

#about-entry-label {
  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 0.65rem; /* achicada junto con el medio círculo (radio 20->12), para que quepan sin agrandar demasiado el hueco entre bloques */
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #000000;
  position: relative;
  z-index: 1; /* por encima del medio círculo en el pequeño solape */
}

/* Medio círculo ")" — siempre al mismo lado (derecho): a diferencia del de
   salida, este nunca cambia de palabra ni de lado. "position:absolute" para
   no empujar la posición de #about-entry-label (mismo motivo que
   #about-exit-ring-wrap); el margen negativo mete la palabra levemente
   adentro del círculo, para ahorrar espacio. */
#about-entry-ring-wrap {
  position: absolute;
  top: 50%;
  left: 100%;
  transform: translateY(-50%);
  margin-left: -3px;
  display: flex;
  align-items: center;
}

#about-entry-ring-wrap svg {
  display: block;
}

/* Salida en MÓVIL: arrastre hacia la izquierda DENTRO del About ya abierto
   (ver js/about.js). Vive centrado en el espacio angosto entre el panel y
   el lienzo que asoma (su "left" lo calcula y actualiza js/about.js — ver
   positionExitIndicator). Dos elementos que se turnan (display, nunca los
   dos a la vez — ver updateExitIndicator): la palabra "About" (solo visible
   durante el fade-out de la apertura, ver #about-exit-label) y la flecha de
   salida (solo mientras se arrastra para volver al lienzo, ver
   #about-exit-arrow) — el medio círculo de carga no empuja ni reordena a
   ninguno de los dos (se posiciona aparte, "position:absolute", pegado a
   uno de sus costados vía las clases "side-right"/"side-left" más abajo,
   alternadas en updateExitIndicator). */
#about-exit-indicator {
  position: fixed;
  top: 50%;
  left: 0; /* valor real lo pone JS, ver positionExitIndicator en about.js */
  z-index: 2147483002; /* Por encima incluso del panel de About */
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  transform: translate(-50%, -50%);
}

#about-exit-label {
  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 0.65rem; /* misma reducción que #about-entry-label, junto con el medio círculo (radio 20->12) */
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #000000;
  opacity: 0;
  position: relative;
  z-index: 1; /* por encima del medio círculo en el pequeño solape (ver "side-right"/"side-left") */
  /* Sin transition CSS: la anima GSAP a propósito (ver setOpen en
     js/about.js) — aparece de golpe al empezar a abrirse y se desvanece
     (1 -> 0) durante esa misma transición de apertura (1.3s), terminando
     invisible para cuando el lienzo ya asentó del todo. */
}

/* Flecha de salida (mismo path que #about-cursor-label-arrow, escritorio):
   reemplaza a la vieja palabra "Home" mientras se arrastra hacia la
   izquierda para volver al lienzo — señala hacia la derecha, hacia donde
   está el lienzo empujado. Su opacidad sigue el mismo "exitCharge" que el
   medio círculo (0 en reposo, 1 con el arrastre completo — ver
   updateExitIndicator en js/about.js), no la transición de apertura. */
#about-exit-arrow {
  position: relative;
  z-index: 1;
  opacity: 0;
}

/* "position:absolute" (relativo a #about-exit-indicator, ya "position:fixed")
   a propósito: así nunca participa del flujo/ancho de la fila y jamás mueve
   a #about-exit-label — solo cambia DE QUÉ LADO cuelga, vía las clases de
   abajo (alternadas en updateExitIndicator, en js/about.js). El margen
   negativo (-3px) mete la palabra levemente adentro del círculo, para
   ahorrar espacio en el hueco angosto entre el panel y el lienzo. */
#about-exit-ring-wrap {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  opacity: 0;
}

#about-exit-ring-wrap.side-right {
  left: 100%;
  margin-left: -3px;
}

#about-exit-ring-wrap.side-left {
  right: 100%;
  margin-right: -3px;
}

#about-exit-ring-wrap svg {
  display: block;
}

/* Panel de ABOUT: sale desde la izquierda, tipo carrusel (ver js/about.js,
   que anima "x" con GSAP — el transform inicial aquí es solo un valor de
   respaldo antes de que el script lo posicione con su ancho real). */
#about-panel {
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh; /* Respaldo para navegadores viejos */
  height: 100dvh; /* Alto REAL visible en móvil: 100vh incluye el espacio que
     tapa la barra de direcciones del navegador (que aparece/desaparece al
     scrollear), así que panel.clientHeight quedaba más alto de lo que en
     verdad se ve — por eso no se alcanzaba a leer la última línea del texto
     ni a ver el círculo de "reload" (quedaba dibujado más abajo del borde
     visible real). dvh se ajusta al viewport visible de verdad. */
  /* Un poco más ancho que --about-panel-width a propósito: ese sobrante
     (--about-parallax-bleed) es "área de recorte" extra e invisible (fondo
     transparente) para que el parallax en X pueda mover la imagen/texto sin
     que se corten contra el borde derecho de la caja. Todo lo que depende
     del ancho "visual" del panel (empuje del lienzo, posición de la flecha)
     sigue usando --about-panel-width solo, sin este agregado — ver js/about.js. */
  width: calc(var(--about-panel-width, 75vw) + var(--about-parallax-bleed, 120px));
  background: transparent;
  z-index: 2147483001; /* Por encima de cualquier post, incluso expandido */
  /* Marco fijo, sin scroll propio: el texto ya no scrollea de forma nativa,
     lo traslada JS (ver #about-content y js/about.js) igual que el scroll
     mueve los proyectos del lienzo. overflow:hidden recorta el contenido en
     el borde del panel; touch-action:none evita cualquier gesto nativo
     (paneo, pull-to-refresh) porque el manejo es 100% manual ahora. */
  overflow: hidden;
  touch-action: none;
  pointer-events: none; /* Mientras está cerrado, no bloquea clicks del lienzo */
  transform: translateX(-100%);
}

#about-panel.is-open {
  pointer-events: auto;
}

/* Elemento que JS traslada verticalmente (gsap.set(content, {y: ...})) para
   simular el scroll del texto — el padding vive aquí (no en #about-panel)
   porque su scrollHeight (que incluye este padding) es lo que se usa para
   calcular cuánto se puede "scrollear" el contenido. */
#about-content {
  box-sizing: border-box;
  /* OJO: NO "100%" — #about-panel ahora es más ancho que --about-panel-width
     a propósito (el "bleed" del parallax, ver la regla de #about-panel más
     arriba). Si esto fuera 100%, el texto y la imagen también se
     ensancharían con ese sobrante. Fijándolo al ancho ORIGINAL, el texto
     queda exactamente igual que antes, pegado a la izquierda, con el
     sobrante como área vacía a la derecha (invisible en reposo) lista para
     cuando el parallax lo desplace. */
  width: var(--about-panel-width, 75vw);
  /* Padding izquierdo calculado para alinear con el TEXTO visible de
     #site-title, no solo con su caja: el nombre tiene "left:0.8rem" pero
     ADEMÁS un padding interno (--text-box-px, el recuadro blanco tipo
     marca-textos) que empuja la letra un poco más adentro — hay que sumar
     ambos para que la letra "I" de Ilan quede en la misma columna que la
     imagen y el texto. Top un poco mayor (7rem) para dejar respiro debajo
     del nombre, que ahora se ve por encima del panel. */
  /* El "6rem" del final (antes 2rem) deja aire después del pie de página,
     para que el círculo de carga (ver #about-overscroll-ring) no aparezca
     pegado al último texto al llegar al final del scroll. */
  padding: 7rem 2rem 6rem calc(0.8rem + var(--text-box-px, 15px));
}

/* Círculo de carga (ver js/about.js: applyAboutScrollDelta / updateRing).
   #about-panel ya es position:fixed, así que sirve de referencia para este
   position:absolute sin necesitar nada extra. Oculto hasta que hay carga. */
#about-overscroll-ring {
  position: absolute;
  left: 50%;
  bottom: var(--about-ring-bottom-offset, 2.5rem);
  transform: translateX(-50%);
  width: var(--about-ring-size, 28px);
  height: var(--about-ring-size, 28px);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

#about-overscroll-ring.is-visible {
  opacity: 1;
}

#about-overscroll-arrow {
  position: relative;
  z-index: 1;
}

/* El anillo (pista + progreso) llena todo el círculo */
#about-overscroll-ring svg:first-child {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

#about-content img {
  width: 100%; /* Mismo ancho que el texto */
  height: auto;
  display: block;
  margin-bottom: 2.5rem; /* Escritorio: un poco más de aire antes del texto */
  background: #111;
}

#about-content p {
  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 0.85rem;
  line-height: 1.6;
  color: #000000;
  margin: 0 0 1.2rem 0;
  text-align: justify;
  /* Anula el "padding: 0 1rem" global de <p> (más abajo en este archivo),
     que corría el texto hacia adentro y lo desalineaba de la imagen. */
  padding: 0;
}

#about-content p:last-child {
  margin-bottom: 0;
}

/* ============================================
   SECCIÓN DE CRÉDITOS (debajo de los párrafos) — ver #about-extra en
   js/about.js (buildAboutContent) y aboutConfig.credits/socialLinks/footer
   en js/config.js.
   ============================================ */
#about-extra {
  margin-top: 2rem;
}

.about-credits-heading {
  text-align: center !important;
  font-weight: 700;
  margin: 0 0 2rem 0 !important;
}

.about-credit-item {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 1.8rem;
}

.about-credit-title,
.about-credit-subtitle,
.about-credit-role {
  text-align: left !important;
  margin: 0 !important;
}

.about-credit-title {
  font-weight: 700;
  font-style: italic;
}

.about-credit-year {
  flex-shrink: 0;
  white-space: nowrap;
}

.about-more-link {
  display: block;
  text-align: center;
  font-style: italic;
  text-decoration: underline;
  color: #000000;
  margin: 0.5rem 0 2.5rem 0;
}

.about-social-links {
  display: flex;
  justify-content: center;
  flex-wrap: nowrap; /* Los cuatro SIEMPRE en un solo renglón, nunca se parten a una segunda línea */
  gap: 0.6rem 1.5rem;
  margin-bottom: 2.5rem;
}

.about-social-links a {
  color: #000000;
  text-decoration: underline;
  white-space: nowrap; /* "Apple Music" no se parte en dos líneas por su cuenta */
}

.about-footer-text,
.about-copyright {
  text-align: left !important;
  font-size: 0.75rem;
  color: #000000;
}

.about-footer-text a,
.about-copyright a {
  color: #000000;
}

@media (max-width: 768px) {
  #about-content {
    /* Alineado con el TEXTO de #site-title (ver nota en la regla de escritorio) */
    /* El "5rem" del final (antes 2rem) deja aire después del pie de página,
       mismo motivo que en escritorio: que el círculo de carga no aparezca
       pegado al último texto. */
    padding: 6rem 1.5rem 5rem calc(0.8rem + var(--text-box-px, 15px));
    /* Ancho del texto y la imagen en MÓVIL — independiente de
       --about-panel-width (esa es solo para escritorio). Ojo: esto no
       cambia el ancho del panel en sí (--about-panel-width sigue
       controlando eso), solo el de la columna de texto/imagen adentro. */
    width: 75vw;
  }

  /* La foto original es muy horizontal (mesa de mezcla panorámica); en un
     ancho angosto de celular eso deja al personaje chico en el medio. Le
     recortamos los costados (aspect-ratio más vertical + object-fit:cover)
     para que se vea más grande y sea el protagonista del encuadre. Ajustá
     "aspect-ratio"/"object-position" si el recorte no queda como se espera. */
  #about-content img {
    aspect-ratio: 4 / 3;
    object-fit: cover;
    object-position: 55% 38%;
    margin-bottom: 1.5rem; /* Vuelve al espaciado original (el 2.5rem de arriba es solo para escritorio) */
  }

  /* Letra un poco más chica que en escritorio (0.95rem) para el texto del About. */
  #about-content p {
    font-size: 0.70rem;
  }

  /* Más chico y con menos separación para que las cuatro entren en un
     solo renglón sin partirse a la línea de abajo (ver flex-wrap:nowrap
     en la regla base, más arriba). */
  .about-social-links {
    gap: 0.4rem 0.6rem;
  }

  .about-social-links a {
    font-size: 0.6rem;
  }
}

#contact-section,
#contact-btn { 
  position: fixed; 
  bottom: 3rem; 
  left: 50%; 
  transform: translateX(-50%); 
  display: inline-block;
  z-index: 9999; 
  opacity: 0; 
  pointer-events: none; 
  transition: opacity 0.75s ease-in-out, transform 0.2s ease; 
  
  text-decoration: none;
  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0 var(--text-box-px, 15px); 
  background-color: transparent; 
  background-image: linear-gradient(#ffffff, #ffffff); 
  background-size: 100% var(--text-box-py, 75%); 
  background-position: center; 
  background-repeat: no-repeat;
  color: #000000;
  border: none; 
}

#contact-section.is-visible {
  opacity: 1;
  pointer-events: auto;
}

#contact-section:hover {
  transform: translateX(-50%) scale(1.1); 
}

/* "showInfoTab: false" en config.js agrega esta clase al body — oculta la
   barra inferior (nombre + play/pausa) en TODOS los proyectos, sin importar
   ningún otro estado (hover, reproduciendo, móvil, etc.). El botón sigue
   funcionando igual (ver click de ".post" en main.js, que dispara ".click()"
   directo sobre él sin depender de que esté visible). */
body.hide-info-tab .info-tab {
  display: none !important;
}

.info-tab {
  padding: 0.7rem 1rem;
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  z-index: 1;
  background: #ffffff; 
  color: #000000; 

  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0.02em;

  display: flex;
  justify-content: space-between;
  align-items: center;
  transform: translateY(0);
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

/* ".about-hover-active" (agregada/quitada por js/about.js en #home-hover-zone,
   solo escritorio): con el About abierto, esa franja tapa TODO el lienzo que
   asoma para poder cerrar tocando cualquier parte — así que un proyecto ahí
   abajo nunca activa su propio ":hover" real (la franja está encima). Sirve
   para mostrar la pestaña (nombre + play) sin la descripción (esa sigue
   siendo exclusiva del lienzo normal, ver "show-desc" en js/main.js). */
.post-container .post:hover .info-tab {
  opacity: 1;
  transform: translateY(10px);
}

/* Parecido al ":hover" real de arriba, con tres diferencias a propósito:
   1) z-index apenas por encima de "#home-hover-zone" (z-index:50) — el
      proyecto está anidado dentro de ".post-canvas" (que tiene su propio
      "transform", ver initCameraPan en main.js) mientras que
      "#home-hover-zone" es un elemento aparte; sin este empujón la pestaña
      quedaba tapada por esa franja.
   2) "translateY(calc(100%))" en vez de "10px" — el mismo desplazamiento que
      ya usa el estado "reproduciendo ahora" más abajo: saca a la pestaña
      COMPLETAMENTE del área de su propia foto, para no depender de quién le
      gana a quién en z-index mientras se están superponiendo.
   3) El propio z-index (55) se aplica con "transition-delay" del mismo
      largo que la animación del deslizamiento (0.6s) — así, MIENTRAS la
      pestaña todavía viaja (parcialmente superpuesta con su propia foto),
      sigue con el z-index bajo de siempre (1, POR DETRÁS de la foto, ver
      regla base) y recién sube una vez que ya terminó de salir del todo.
      Sin este retraso, la pestaña "aparecía por delante" de su propia foto
      durante todo el deslizamiento de entrada (el z-index alto se aplicaba
      de golpe, desde el primer instante) — pero al SALIR del hover sí se
      veía bien (la clase se saca de una, así que el z-index vuelve a 1 al
      toque, y el deslizamiento de regreso queda por detrás desde el
      arranque). Con este retraso, entrar y salir se ven exactamente igual:
      siempre por detrás de la foto mientras se mueve. */
.post-container .post.about-hover-active .info-tab {
  opacity: 1;
  transform: translateY(calc(100%));
  z-index: 55;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), z-index 0s linear 0.6s;
}

.post-container .post .inner:hover .info-tab {
  transform: translateY(calc(100%));
}

/* Escritorio: mientras el track (o video) está sonando/reproduciendo, la pestaña
   (nombre + play/pausa) se mantiene visible debajo de la miniatura sin necesitar
   hover, igual que en móvil, para poder ubicar esa foto dentro del scroll infinito. */
.post-container .post.playing-audio .info-tab,
.post-container .post.video-playing .info-tab,
.post-container .post.hero-video.is-expanded .info-tab {
  opacity: 1;
  transform: translateY(calc(100%));
}


#desktop-player {
  position: fixed;
  top: 2rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  z-index: 9999;
}

/* Arreglo funcional temporal: si el About está abierto (panel a
   z-index:2147483001) y suena un proyecto, el reproductor de escritorio
   (botón + waveform) debe quedar por encima de la foto del About, no
   tapado por el panel. Acotado a "body.about-open" para no tocar el
   z-index del player en ningún otro caso. Se va a rehacer más adelante
   con otros cambios pendientes en esta zona (mismo criterio que
   #mobile-player). */
body.about-open #desktop-player {
  z-index: 2147483002;
}

#global-audio-btn {
  display: flex;
  align-items: center;
  justify-content: center;

  padding: 0.5rem;
  background-color: transparent;
  color: #000000;
  border: none;

  cursor: pointer;
  transition: opacity 0.3s ease, transform 0.2s ease;
}

#global-audio-btn:hover {
  opacity: 0.6;
}

#global-audio-btn:active {
  transform: scale(0.9);
}

#desktop-waveform-container {
  width: 220px;
  height: 40px;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.1s cubic-bezier(0.22, 1, 0.36, 1);
}

#desktop-waveform-container.is-visible {
  opacity: 1;
  pointer-events: auto;
}

.play-btn {
  background: none;
  border: none;
  color: #000000;
  font-size: 1rem; 
  cursor: pointer;
  padding: 0;
  transition: transform 0.2s ease;
}

.play-btn:hover {
  transform: scale(1.2);
}

.desc-panel {
  position: absolute;
  top: 0;
  height: auto;
  min-height: 100%;
  width: var(--desc-panel-width, 18vw); 

  background-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-radius: 0;
  padding: 1.5rem 0; 

  font-family: var(--main-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-size: var(--desc-font-size, 0.9rem);
  line-height: 1.6; 
  color: #111;

  opacity: 0;
  z-index: -1;
  pointer-events: none;
  transition-property: opacity;
  transition-duration: var(--side-text-fade-out, 0.5s);
  transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  overflow: visible; 
}

.desc-panel span {
  color: #000000;
  

  padding: 0 var(--text-box-px, 15px); 
  
  display: inline; 

  box-decoration-break: clone;
  box-shadow: none; 
  white-space: normal; 


  background-color: transparent; 
  background-image: linear-gradient(#ffffff, #ffffff); 
  background-size: 100% var(--text-box-py, 100%); 
  background-position: center; 
  background-repeat: no-repeat;
}

.post[data-side="left"] .desc-panel {
  left: calc(100% + 15px); 
  text-align: left !important; 
}
.post[data-side="left"].show-desc .desc-panel {
  opacity: 1;
  transition-duration: var(--side-text-fade-in, 0.5s);
}


.post[data-side="right"] .desc-panel {
  right: calc(100% + 15px);
  text-align: right !important;
  padding-right: var(--text-box-px, 15px);
  clip-path: inset(-100% 0 -100% -100%); 
}
.post[data-side="right"] .desc-panel span {
  padding-right: 0 !important; 
  box-shadow: 20px 0 0 var(--desc-shadow-height, 0px) #ffffff !important; 
}
.post[data-side="right"].show-desc .desc-panel {
  opacity: 1;
  transition-duration: var(--side-text-fade-in, 0.5s);
}

/* FASE 2: Ajustes del lienzo flotante para celular (Superposiciones) */
@media (max-width: 768px) {
  /* Ocultamos los controles de escritorio */
  #desktop-player {
    display: none !important;
  }

  /* Contacto en móvil: centrado horizontalmente, misma altura que el nombre.
     Misma estética (recuadro blanco) y misma lógica de aparición por scroll
     que en escritorio. */
  #contact-section {
    bottom: auto;
    top: var(--contact-mobile-top, 2rem);
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    font-size: var(--contact-mobile-font-size, 0.65rem);
    font-weight: 700; /* Bold: distinto del grosor delgado de #site-title */
  }

  #contact-section:hover {
    transform: translateX(-50%) scale(1.1);
  }

  /* Estilos del reproductor táctil fijo y su pantalla */
  #mobile-player {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: fixed;
    bottom: var(--player-bottom-scroll) !important;
    left: 50%;
    transform: translateX(-50%);
    gap: 1rem;
    width: 90vw !important; /* Deja un 5% de margen a cada lado */
    z-index: 9999;
    opacity: 1;
    pointer-events: auto;
    transition: opacity 0.4s ease; /* fade JS-driven al entrar/salir del About, ver js/about.js */
  }

  body.zoom-mode #mobile-player {
    bottom: var(--player-bottom-zoom) !important;
  }

  /* Arreglo funcional temporal: si entrás al About mientras suena un
     proyecto, el player (con su fondo blanco) debe quedar por encima del
     panel de About (2147483001), no tapado por él — antes se veía detrás,
     con el fondo blanco del panel encima. Acotado a "body.about-open" para
     no tocar el z-index del player en ningún otro caso (p.ej. modo Zoom de
     una foto, que sigue exactamente igual que antes). Se va a rehacer más
     adelante con otros cambios pendientes en esta zona. */
  body.about-open #mobile-player {
    z-index: 2147483002;
  }

  /* Minireproductor: ver js/about.js para el show/hide (opacity JS-driven,
     mismo patrón que #about-exit-label) y positionMiniPlayer (misma mecánica
     que positionExitIndicator, pegado en vivo a window.getAboutCanvasLiveX). */
  #mini-player {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    position: fixed;
    bottom: 4rem; /* ajustar tras comparar contra el diseño real */
    transform: translateX(-50%); /* el "left" lo pone JS, ver positionMiniPlayer */
    z-index: 2147483002; /* misma capa que #mobile-player mientras About está abierto */
    padding: 0.6rem;
    width: 72px;
    box-sizing: border-box;
    border-radius: 0;
    background: rgba(225, 225, 225, 0.95);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.4s ease;
  }

  #mini-player-thumbnail {
    width: 56px;
    height: 56px;
    border-radius: 0;
    overflow: hidden;
  }

  #mini-player-thumb {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  #mini-player-btn {
    background: none;
    border: none;
    padding: 4px;
    margin: 0;
    cursor: pointer;
    color: #000000;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  /* En móvil el título siempre queda fijo: anulamos el ocultado por scroll
     (esa función es exclusiva de escritorio, ver main.js). Solo se oculta
     en modo Zoom, mediante la regla de abajo. */
  #site-title.is-hidden {
    opacity: 1;
    pointer-events: auto;
  }

  #site-title.contact-visible {
    opacity: 0;
    pointer-events: none;
  }

  /* En modo Zoom (foto centrada en pantalla), ocultamos el nombre y el botón de
     contacto para que no compitan con la imagen. Reaparecen solos al cerrar el zoom,
     reutilizando las mismas transiciones de opacidad que ya tenían. */
  body.zoom-mode #site-title {
    opacity: 0;
    pointer-events: none;
  }

  body.zoom-mode #contact-section {
    opacity: 0;
    pointer-events: none;
  }

  #mobile-controls {
    display: flex;
    gap: var(--btn-spacing, 2rem);
    align-items: center;
    justify-content: center;
  }

  /* Estado de reposo: Ocultos pero reservando su espacio físico */
  #mobile-prev-btn, 
  #mobile-next-btn {
    opacity: 0;
    pointer-events: none; /* Escudo contra clics accidentales mientras son invisibles */
    transition: opacity 0.5s ease; /* Esta es la magia del Fade-In / Fade-Out */
  }

  /* Estado activo: Fade-In suave */
  #mobile-controls.has-started #mobile-prev-btn,
  #mobile-controls.has-started #mobile-next-btn {
    opacity: 1;
    pointer-events: auto; /* Reactivamos el tacto */
    animation: none !important; /* Apagamos cualquier keyframe viejo para que la transición domine */
  }

  #mobile-audio-display {
    width: 100%;
    font-family: monospace, var(--main-font);
    font-size: 0.8rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    opacity: 0; 
    pointer-events: none; 
    transition: opacity 0.4s ease;
    line-height: 1.05 !important;
    padding-top: 1px !important;
    padding-bottom: 1px !important;
    align-items: center;
  }

  #mobile-audio-display.show-display {
    opacity: 1;
    pointer-events: auto; 
  }

  /* Bloque sólido superior: Título y Tiempo */
  /* FILA 1: Título y Tiempo */
  #mobile-track-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end; /* MÁGIA UX: Ancla los textos a la base, crecen hacia arriba */
    width: 100%;
    background: transparent !important;
    gap: 15px; /* Muro de contención entre título y tiempo */
  }

  /* Ajuste para que el título baje de renglón si es necesario */
  #mobile-track-title {
    line-height: 0.9 !important; /* Respiro mínimo para que las líneas múltiples no choquen */
    padding: 0 !important;
    margin: 0 !important;
    white-space: normal !important; /* Permite el salto de línea */
    text-align: left;
    flex-grow: 1; /* Toma todo el espacio disponible que deje el reloj */
  }

  /* Blindaje absoluto para el reloj */
  #mobile-track-time {
    line-height: 0.9 !important;
    padding: 0 !important;
    margin: 0 !important;
    white-space: nowrap !important; /* NUNCA saltar de renglón */
    flex-shrink: 0; /* NUNCA encogerse, es una roca */
    text-align: right;
  }

  /* 2. El contenedor de la onda necesita blindaje flexbox */
  #waveform-container {
    flex-grow: 1;
    height: 45px !important;
    margin: 0 !important;
    min-width: 0 !important; /* MÁGIA CSS: Evita que el hijo rígido (canvas) rompa el flexbox */
    width: 100%;
    overflow: hidden; /* Todo lo que rebase esto, se corta */
    position: relative; /* Necesario para el crossfade entre canvas */
  }

  /* 3. Aseguramos que el canvas dentro no haga cosas raras */
  #waveform-container canvas {
    display: block;
    width: 100% !important; /* Obliga al canvas a no exceder la caja blindada */
    /* Alto también forzado a 100% del contenedor: así el canvas siempre se ve
       del tamaño de su caja aunque su buffer interno (fijado por resizeCanvas)
       todavía no coincida. Mientras el contenedor anima su alto (zoom <-> scroll),
       el navegador escala el canvas visualmente cuadro a cuadro junto con esa
       transición — sin esperar a que termine para "saltar" al tamaño correcto. */
    height: 100% !important;
    cursor: crosshair;
  }

  /* Fade sutil que acompaña el cambio de tamaño entre modo scroll y modo zoom:
     el waveform baja un poco de opacidad y vuelve a subir, en vez de solo
     crecer/encogerse en seco. Se dispara agregando/quitando la clase
     "is-resizing" en JS justo cuando cambia el modo (ver main.js). */
  @keyframes waveformResizePulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
  }

  #waveform-container canvas.is-resizing {
    animation: waveformResizePulse 0.3s ease-in-out;
  }

  .player-btn {
    background: none;
    border: none;
    color: #000000;
    font-size: 1.5rem;
    cursor: pointer;
    padding: 10px;
    transition: transform 0.2s ease;
  }
  
  .player-btn:active {
    transform: scale(0.9); /* Efecto tactil al presionar */
  }

  .post-canvas {
    width: 110vw;
    left: -5vw;
  }
  .post-container .post {
    width: 45vw; /* Aumentamos el ancho casi a la mitad de la pantalla para forzar colisiones organicas */
    height: auto;
  }
  /* Imagen y video conservan su tamaño/proporción original (igual que en
     escritorio): ya no se fuerza una altura fija de recorte ni un ancho fijo
     en .inner — object-fit:cover y aspect-ratio:16/9 (reglas base) hacen el
     resto, igual que en la versión de escritorio. */
  /* Igual que en escritorio: el video es 16:9 (más bajo), así que a mismo
     ancho se ve más chico que una foto — le damos un poco más de ancho. */
  .post-container .post.is-video-post {
    width: 63vw;
  }
  /* Ocultamos las pestañas por defecto en móvil */
  .post .info-tab {
    display: none !important;
  }

  /* Evitamos que el contenedor recorte la etiqueta que sale por debajo */
  .post.playing-audio,
  .post.video-playing {
    overflow: visible !important;
  }

  /* Animación de entrada suave para la pestaña */
  @keyframes fadeInTab {
    from { 
      opacity: 0; 
      transform: translateY(-5px); /* Inicia un poco escondida hacia arriba */
    }
    to { 
      opacity: 1; 
      transform: translateY(0); /* Aterriza en su posición final */
    }
  }

  /* MÁGIA UX: Etiqueta transparente que contiene bloques inline */
  .post.playing-audio:not(.is-expanded) .info-tab,
  .post.video-playing:not(.is-expanded) .info-tab,
  .post.hero-video.is-expanded .info-tab {
    display: flex !important;
    justify-content: space-between; 
    align-items: flex-end; /* Alinear todo a la base */
    position: absolute;
    bottom: var(--tab-offset, -4px);
    left: 0;
    width: 100%;
    
    background: transparent !important; /* Quitamos el fondo global */
    height: auto !important; /* Permitimos que crezca verticalmente */
    overflow: visible !important; 
    padding: 0 !important;
    z-index: 10;
    margin: 0 !important;
    animation: fadeInTab var(--tab-fade-time) cubic-bezier(0.22, 1, 0.36, 1) forwards !important;
  }

  /* El bloque de texto: clonación de fondo por cada línea */
  .post.playing-audio:not(.is-expanded) .info-tab .track-name,
  .post.video-playing:not(.is-expanded) .info-tab .track-name,
  .post.hero-video.is-expanded .info-tab .track-name {
    background: #ffffff;
    color: #000000;
    font-family: monospace, var(--main-font);
    font-size: 0.55rem; /* Más pequeño, más elegante */
    line-height: 0.75 !important;
    padding: 2px 6px 0px 6px !important;
    display: inline;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
    max-width: 80%; /* Lo obligamos a bajar a la segunda línea si es muy largo */
  }

  /* El botón pausa: bloque independiente a la derecha */
  .post.playing-audio:not(.is-expanded) .info-tab .play-btn,
  .post.video-playing:not(.is-expanded) .info-tab .play-btn,
  .post.hero-video.is-expanded .info-tab .play-btn {
    background: #ffffff;
    color: #000000;
    font-size: 0.55rem !important;
    padding: 2px 6px 0px 6px !important;
    height: auto !important;
    line-height: 0.75 !important;
    margin-left: 5px !important;
    display: inline-block;
    -webkit-appearance: none; /* Blindaje extra contra Safari */
    appearance: none;
  }

  /* CAJA MAESTRA: Modo Columna */
  #unified-player-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    background-color: transparent;
    padding: 0;
    transition: background-color 0.3s ease, padding 0.3s ease;
    gap: var(--gap-wave-controls-scroll);
  }

  body.zoom-mode #unified-player-box {
    gap: var(--gap-wave-controls-zoom) !important;
  }

  #unified-player-box.is-active {
    background-color: #ffffff; /* La caja sólida completa */
    /* padding: Arriba Derecha Abajo Izquierda */
    padding: 15px 15px 8px 15px !important; /* ANTES: 15px parejo. Ahora el piso es más delgado */
  }

  /* ENVOLTURA DE FILAS 1 y 2. display:flex fijo (antes alternaba none/flex, lo que
     cancelaba el fade de opacidad de la regla principal: un elemento con display:none
     no puede transicionar, por eso aparecía/desaparecía de golpe). La visibilidad la
     controla únicamente la opacidad (ver regla #mobile-audio-display más arriba). */
  #mobile-audio-display {
    display: flex;
    width: 100%;
    flex-direction: column;
    gap: var(--gap-title-wave-scroll);
  }
  body.zoom-mode #mobile-audio-display {
    gap: var(--gap-title-wave-zoom) !important;
  }

  /* FILA 1: Título y Tiempo (segunda instancia — ver regla principal arriba) */

  /* FILA 2: Contenedor flex para alinear Miniatura y Onda */
  #mobile-middle-row {
    display: flex;
    flex-direction: row;
    align-items: center;
    width: 100%;
    gap: 15px; /* Espacio entre foto pequeña y la onda */
  }

  /* MODO LIENZO (Comportamiento por defecto) */
  #player-thumbnail {
    width: 45px; /* Ancho miniatura */
    height: 45px; /* Alta igual que la onda */
    flex-shrink: 0;
    display: block;
  }
  #player-thumbnail img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  #waveform-container {
    flex-grow: 1;
    height: 45px !important;
    margin: 0 !important;
    min-width: 0 !important;
    width: 100%;
    overflow: hidden;
    position: relative; /* Necesario para el crossfade entre canvas */
  }

  /* La transición de alto (scroll 45px <-> zoom 60px) SOLO se activa cuando el
     reproductor ya está visible (.show-display). Si estuviera activa siempre,
     la primerísima vez que el waveform aparece (todavía invisible, con
     opacity:0) el alto empieza a animarse desde 45px justo cuando se agrega
     "zoom-mode", y el fade-in del contenedor revela ese cambio a medio hacer:
     eso era el "brinco" de posición. Mientras está oculto, el alto cambia de
     golpe (invisible, no se nota) y cuando el fade-in lo revela ya está fijo
     en su tamaño final. Una vez visible, los cambios de modo sí se animan. */
  #mobile-audio-display.show-display #waveform-container {
    transition: height 0.22s cubic-bezier(0.22, 1, 0.36, 1);
  }

  /* FILA 3: Controles */
  #mobile-controls {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    gap: var(--btn-spacing, 2rem);
    margin: 0 !important;
  }

  /* --- MODO ZOOM (Reescritura) --- */
  body.zoom-mode #player-thumbnail {
    display: none; /* Ocultamos la miniatura */
  }
  body.zoom-mode #waveform-container {
    height: 60px !important; /* La onda recupera su grosor al estar sola */
  }

  .desc-panel {
    display: none !important;
  }
}