/* ==========================================================================
   movil.css — TODO lo que solo debe pasar en pantallas pequeñas.

   Se carga desde base.html con media="(max-width: 899px)", asi que en un
   escritorio este archivo no se aplica: aqui se puede mover, encoger, reordenar
   y reescribir sin ningún riesgo para la vista de PC. Dentro lleva su propio
   @media por si alguien cambia el <link>: entonces seguiria funcionando igual.

   Regla de la casa: lo que se ponga aqui NO debe afectar a ninguna pantalla de
   900 px o más. Si algo tiene que cambiar en las dos, va en theme.css.

   Para comprobar que el escritorio sigue intacto después de tocar esto:
       node tools/revisar_anchos.mjs      (10 anchos x 10 paginas, mosaico y lista)
       node tools/revisar_rol_usuario.mjs 1440
   Y para ver el resultado en un telefono:
       node tools/capturar_pantallas.mjs 390 844
   ========================================================================== */

/* ==========================================================================
   Ajustes de MOVIL (2026-10-03 · revision en rol de usuario)

   Todo lo de este bloque vive dentro de @media (max-width: 899px): el
   escritorio se queda exactamente como estaba. Lo de aqui salio de recorrer el
   sitio con emulacion tactil real y de mirar las capturas de cada pantalla.

   1. LA FICHA NO DECIA QUE BEAT ERA. En un telefono el titulo caia en el pixel
      834 de una pantalla de 844: la portada cuadrada a ancho completo (362 px)
      mas la tabla de datos (269 px) se comian la primera pantalla entera, asi
      que el usuario abria un beat y no veia su nombre hasta desplazar. En
      escritorio los dos bloques van en dos columnas y el titulo sale arriba,
      por eso alli no pasa. Aqui la portada se limita al 62 % (centrada) y las
      filas de la tabla se aprietan un poco.

   2. TEXTO DEMASIADO PEQUENO. Las etiquetas de datos iban a 9,3 px, el "USD"
      del precio a 9,0, las etiquetas de las tarjetas de talento a 8,3 y los
      titulos del pie a 9,6. En un telefono eso no se lee. Se suben SOLO aqui.

   3. OBJETIVOS TACTILES. Los enlaces del pie median 18 px de alto y las migas
      16: con el dedo eso se falla. Se les da area sin cambiar como se ven.

   4. LA LISTA DEL DISCO NO DECIA EL PRECIO. En movil se ocultaban la miniatura,
      la duracion Y el precio, asi que se podia pulsar "Comprar" en diez filas
      sin ver cuanto cuesta ninguna. Vuelve el precio en su propia columna; la
      duracion se queda fuera porque el dato que decide la compra es el precio.

   5. EL CHIP DEL GENERO SOBRA EN LA TARJETA. Es el mas largo y el mismo en 41
      de los 42 beats, y ya se lee en la cabecera del album y en la ficha.
      Quitarlo deja sitio para que los otros tres se lean mas grandes.
   ========================================================================== */
@media (max-width: 899px) {

  /* --- 1. La ficha, con el nombre del beat a la vista ------------------- */
  .beat-page-art { max-width: 62%; margin: 0 auto; }
  .spec-list > div { padding: 7px 16px; }
  .breadcrumb { font-size: .68rem; }
  /* La miga se partia en dos lineas y se comia 86 px de la primera pantalla. En
     movil se quita el ultimo tramo (la pagina actual) porque el titular de justo
     debajo ya dice lo mismo, y con el se va su separador. Asi cabe en una linea
     y el nombre del beat sube otro tanto. */
  .breadcrumb span[aria-current="page"] { display: none; }
  .breadcrumb > span:has(+ span[aria-current="page"]) { display: none; }
  /* La miga traia 28 px de relleno arriba y 24 abajo (site.css): 52 px de aire
     para una sola linea de texto, justo debajo de una cabecera de 73. En movil
     ese aire se queda en la mitad y el contenido sube 30 px. */
  .breadcrumb { padding: 12px 0 10px; }
  /* En el disco pasa lo mismo que en la ficha: con la portada a ancho completo
     (362 px) la lista de pistas empezaba por debajo del pliegue, y esta pagina
     existe para escuchar el disco. Al 62 % la portada sigue mandando y las
     primeras pistas ya asoman en la primera pantalla. */
  .disco-cover { max-width: 62%; margin: 0 auto; }

  /* --- 2. Tamanos legibles --------------------------------------------- */
  .chip { font-size: .68rem; padding: 5px 9px; }
  .beat-card-track { font-size: .66rem; height: 20px; }
  .beat-card-price small,
  .track-price small,
  .license-price small { font-size: .66rem; }
  .track-specs, .track-time { font-size: .73rem; }
  .album-meta, .disco-meta { font-size: .7rem; }
  .disc-card-body small { font-size: .68rem; }
  .talent-rows dt { font-size: .68rem; }
  .site-footer :is(h2, h3) { font-size: .74rem; }
  .btn-sm { font-size: .84rem; }
  .spec-list dt { font-size: .66rem; }
  .notes-tool { font-size: .68rem; }

  /* --- 3. Area tactil donde el dedo fallaba ---------------------------- */
  .site-footer li a,
  .site-footer p a { display: inline-block; padding: 8px 0; }
  .breadcrumb a { display: inline-block; padding: 8px 2px; }
  .link-more { display: inline-block; padding: 8px 0; }

  /* --- 4. El precio vuelve a la lista del disco ------------------------ */
  .track-row {
    grid-template-columns: 38px minmax(0, 1fr) auto auto;
    grid-template-areas:
      "play titulo titulo comprar"
      "play datos  precio comprar";
    /* 16 px de separacion por columna son 48 px de la fila en un telefono. Con
       10 px los datos caben enteros junto al precio sin bajarles el tamaño. */
    column-gap: 10px;
  }
  .track-row .track-price {
    display: block; grid-area: precio;
    justify-self: end; align-self: center;
    font-size: .88rem; white-space: nowrap;
  }

  /* --- 5. Objetivos que con el dedo se fallan -------------------------- */

  /* El carril de un deslizador mide 3 px de alto (site.css) y su pulgar 13. El
     pulgar SOBRESALE del elemento, asi que apuntar al pulgar y tocar su parte de
     arriba o de abajo no llega al input: en un telefono el filtro de BPM, la
     barra del reproductor y la del planificador se sentian rotos.
     Se le da caja sin cambiar el dibujo: el carril se sigue pintando solo en los
     3 px del contenido (background-clip) y el relleno queda transparente pero
     recibe el toque. box-sizing explicito porque si no, con border-box, el
     relleno se comeria los 3 px del carril.
     La pantalla completa del reproductor se deja como esta a proposito. */
  input[type="range"] {
    box-sizing: content-box;
    padding: 12px 0;
    background-clip: content-box;
  }
  #player-panel input[type="range"] {
    box-sizing: border-box;
    padding: 0;
    background-clip: border-box;
  }

  /* Los enlaces del titulo de una tarjeta median 23 px de alto: a un pixel del
     minimo de 24 y muy justos para un dedo. Se les da area SIN mover la
     maqueta: el relleno agranda la caja que recibe el toque y el margen
     negativo lo devuelve a su sitio.
     El margen no es un capricho: theme.css reserva exactamente dos lineas en el
     titulo (min-height de 2.4em) para que todas las tarjetas de una fila midan
     lo mismo. Sin compensar, el titulo de una linea se quedaba en 41 px y el de
     dos en 47, y las tarjetas salian desiguales: lo detecto revisar_visual. */
  .beat-card-title a,
  .track-title {
    display: inline-block;
    padding: 3px 0;
    margin: -3px 0;
  }

  /* NOTA: aqui hubo una regla para ocultar .chip-genre en el mosaico. Se quito
     al comprobar que theme.css ya lo oculta en TODO el sitio (linea 1184): era
     una regla muerta y el motivo que la justificaba era falso. */

  /* El Camelot de la fila si sale: es el dato mas prescindible al recorrer una
     lista y es lo que hacia que los datos no cupieran junto al precio. Sigue en
     la ficha del beat y en la herramienta de mezcla armonica. */
  .track-camelot { display: none; }

  /* --- 6. Controles de los paneles laterales --------------------------- */
  /* Las auditorias de pagina EXCLUYEN los paneles (el carrito y el compositor
     viven fuera del flujo y empiezan ocultos), asi que sus controles no se
     habian medido nunca como los toca un dedo. Medidos ahora, con el panel
     abierto: las cantidades median 24x24 y "Quitar" 39x21. */
  .cart-qty { gap: 8px; }
  .cart-qty button { width: 32px; height: 32px; }
  .cart-qty span { min-width: 26px; }
  .cart-item-remove { min-height: 30px; padding: 6px 0; }
  .toast-action { min-height: 34px; }
  .mix-play { width: 38px; height: 38px; }
  .notes-strip-title { display: inline-block; padding: 4px 0; }

  /* --- 7. La meta del disco, sin partir el genero ---------------------- */
  /* La tarjeta mide 174 px: el texto entero no cabia y partia «HIP-/HOP/RAP»
     por el guion. El genero va en su propio elemento (lo emite el generador),
     asi que en movil se oculta y queda «10 pistas · 39 min», que se lee de una
     vez. El genero sigue en la cabecera del album y en la pagina del disco. */
  .disc-card-body .solo-ancho { display: none; }
}

/* ==========================================================================
   Pantallas muy bajas (320 x 568 y parecidas)

   En un telefono de 568 px de alto, con la portada al 62 % el nombre del beat
   volvia a caer justo en el borde de la primera pantalla (el mismo problema que
   se corrigio para 390, pero la pantalla es 276 px mas corta). Aqui la portada
   baja al 52 % y la tabla se aprieta un poco mas; el titulo y los chips entran
   sin desplazar. Solo afecta a estos tamaños: de 361 px en adelante manda el
   bloque de arriba.
   ========================================================================== */
@media (max-width: 360px) {
  .beat-page-art { max-width: 52%; }
  .spec-list > div { padding: 5px 12px; }
  .spec-list dt { font-size: .62rem; }
  .spec-list dd { font-size: .86rem; }
  .breadcrumb { font-size: .62rem; }
}

/* ==========================================================================
   REDISEÑO DE MOVIL (2026-10-03)

   La vista de telefono seguia leyendose como una web de escritorio encogida, y
   se puede medir por que:

     - La rejilla del catalogo bajaba de cinco columnas a DOS de 174 px metiendo
       el mismo contenido dentro (portada, pista, chips, precio y boton):
       tarjetas de 406-440 px de alto con el texto a 9-11 px para que cupiera.
     - El ritmo vertical era el de escritorio: 54 px arriba y abajo de cada
       seccion, o sea 108 px de aire entre bloques.
     - Las microetiquetas venian a 9,92 px.
     - En la barra de filtros convivian buscador, chips, contador, conmutador
       mosaico/lista y «Filtros»: una barra de herramientas de escritorio.
     - Hasta el heroe era el de escritorio escalado: titular de 40 px, parrafo
       de 104 px y dos botones en fila.

   Aqui se cambia el ENFOQUE, no solo los tamaños: el catalogo pasa a ser una
   lista de filas de una columna (como una app de musica), la seleccion de la
   portada pasa a ser un carril que se desliza con el dedo, la barra de filtros
   se compacta en dos lineas y los chips se deslizan en horizontal en vez de
   apilarse. Todo dentro de @media (max-width: 899px): el escritorio no cambia.
   ========================================================================== */
@media (max-width: 899px) {

  /* ---------- 1. Escala tipografica propia de telefono ------------------ */
  /* El titular de escritorio arrancaba en 2.1rem (33,6 px) y llegaba a 40 px en
     la portada: proporcion de escritorio. En un telefono el titular de pagina
     va sobre 30 px, y de ahi para abajo todo baja un escalon. */
  /* UN solo titular para toda la pagina, con :is() para cubrir las variantes que
     ya traia el CSS base (.page-head h1, .hero-copy h1, .disco-copy h1,
     .beat-page-info h1). Con `h1` a secas la regla perdia contra todas ellas y
     cada pagina acababa con un tamaño distinto: 29,6 en el disco, 38,4 en
     talento. La especificidad de :is() es la de su argumento mas especifico, asi
     que empata con el CSS base y gana por ir despues. */
  :is(h1, .page-head h1, .hero h1, .hero-copy h1, .disco-copy h1, .disco-head h1, .beat-page-info h1) {
    font-size: clamp(1.85rem, 8vw, 2.05rem);
    line-height: 1.08;
    letter-spacing: -.03em;
  }
  .section-head h2, .album-head h2 { font-size: 1.3rem; }
  .section-head { margin-bottom: 16px; }
  .page-lead, .hero-sub, .section-lead { font-size: .95rem; line-height: 1.52; }
  .kicker, .page-head .kicker, .hero-kicker { font-size: .73rem; letter-spacing: .1em; }
  .link-more { font-size: .74rem; }

  /* ---------- 2. Ritmo vertical de telefono ---------------------------- */
  .section { padding: 32px 0; }
  .page-head { padding: 20px 0 14px; }
  .page-head h1 { margin-top: 4px; }
  .page-lead { margin-top: 10px; }

  /* ---------- 3. Catalogo: filas nativas de una columna ---------------- */
  /* El conmutador mosaico/lista es un concepto de escritorio y en el telefono se
     oculta; app.js fuerza la vista de lista para que la imagen que viaja sea la
     miniatura de 160 y no la tile de 640 (el catalogo pesa unas cinco veces
     menos).

     NOTA SOBRE LOS SELECTORES, que costo cinco intentos: la vista de lista trae
     sus propias reglas en theme.css (`pista`, `arte`, `cuerpo`, `acciones`...)
     repartidas entre el bloque global y un @media, y con la misma especificidad
     que las de aqui. En vez de pelearse regla a regla, todo lo de esta seccion
     va con la id del catalogo (`#catalog`), que gana a cualquier clase del CSS
     base. Es feo y es a proposito: deja esta fila fuera de la cascada general.

     Lo que quedo escrito de los intentos anteriores:

     1. En la vista de lista el envoltorio .beat-card-visual viene disuelto
        (display: contents) y cada pieza ocupa un area con nombre que ya existe:
        play, art, body, duration, actions y open. Inventar nombres deja a los
        hijos sin area y el navegador los coloca donde puede.
     2. Con columnas fijas para el play, la portada y el precio, al titulo le
        quedaban 86 px y salia "Al Tod...".
     3. El cuerpo traia su rejilla de dos columnas (la pista a la izquierda, el
        texto a la derecha): eso sangraba el titulo 32 px respecto al precio.
        Ahora es UNA columna.
     4. Restaurar el envoltorio choco con las areas y la imagen acababa en 48x80,
        deformada. La forma limpia es dejar el envoltorio disuelto y poner el
        BOTON EN LA MISMA AREA que la portada: dos piezas en un area se
        superponen, y con place-self el boton cae en el centro exacto. */
  .view-toggle { display: none; }

  #catalog .beat-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 9px;
  }
  .beat-grid.picks { grid-template-columns: none; }

  #catalog .beat-card {
    display: grid;
    grid-template-columns: 5rem minmax(0, 1fr) auto;
    grid-template-areas: "art body actions";
    align-items: center;
    column-gap: 12px;
    padding: 10px;
    background: var(--surface);
    border: var(--hairline);
    border-radius: var(--radius);
  }
  #catalog .beat-card-duration,
  #catalog .beat-card-open { display: none; }

  #catalog .beat-card-visual { display: contents; }
  #catalog .beat-card-media { grid-area: art; display: block; width: 5rem; height: 5rem; }
  #catalog .beat-card-media img {
    width: 5rem; height: 5rem;
    aspect-ratio: 1 / 1; object-fit: cover;
    border-radius: var(--radius-sm);
  }
  #catalog .play-btn {
    grid-area: art; place-self: center;
    position: static; transform: none; opacity: 1;
    width: 34px; height: 34px; z-index: 2;
  }
  #catalog .play-btn svg { width: 15px; height: 15px; }

  #catalog .beat-card-body {
    grid-area: body;
    display: flex; flex-direction: column; align-items: flex-start;
    gap: 2px; min-width: 0;
  }
  #catalog .beat-card-title { font-size: .98rem; line-height: 1.18; min-height: 0; }
  #catalog .beat-card-title a {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  #catalog .beat-card-album {
    display: flex; align-items: center; gap: 6px;
    font-size: .72rem; color: var(--muted-2); margin: 0;
    max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #catalog .beat-card-album-name { display: none; }
  #catalog.is-flat .beat-card-album-name {
    display: inline;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  #catalog .beat-card-track {
    min-width: 20px; height: 18px; padding: 0 4px;
    font-size: .66rem; flex: 0 0 auto;
  }
  #catalog.is-flat .beat-card-track { align-self: center; }
  #catalog .chips { gap: 4px; margin-top: 2px; flex-wrap: wrap; }
  #catalog .chip { font-size: .7rem; padding: 2px 6px; white-space: nowrap; }
  #catalog .chip-camelot { display: none; }

  #catalog .beat-card-actions {
    grid-area: actions;
    display: flex; flex-direction: column; align-items: flex-end;
    gap: 7px; margin: 0; padding: 0; border: 0;
  }
  #catalog .beat-card-price { font-size: 1rem; line-height: 1; white-space: nowrap; }
  #catalog .beat-card-actions .js-add { min-width: 94px; min-height: 36px; }

  /* ---------- 4. Barra de filtros compacta ----------------------------- */
  /* Deja de ser una barra de herramientas de tres filas: buscador a lo ancho
     arriba, y debajo una sola linea con los chips deslizandose y «Filtros». */
  .filters-inner { flex-wrap: wrap; gap: 8px 10px; padding: 9px 0; }
  .filters-inner .search { flex: 1 1 100%; max-width: none; }
  .filters-inner .chip-filters {
    flex: 1 1 auto; flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; -ms-overflow-style: none;
    /* El desvanecido de la derecha avisa de que hay mas chips. */
    mask-image: linear-gradient(90deg, #000 88%, transparent);
    -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent);
    padding-right: 14px;
  }
  .filters-inner .chip-filters::-webkit-scrollbar { display: none; }
  .filters-inner .chip-filter { flex: 0 0 auto; }
  .filters-inner .results { flex: 0 0 auto; font-size: .68rem; }
  .filters-actions { margin-left: 0; }

  /* ---------- 5. La seleccion de la portada, carril que se desliza ----- */
  /* En la portada, seis tarjetas apiladas ocupaban 2.700 px de alto. Un carril
     con enganche muestra la primera entera y asoma la siguiente: se recorren
     las seis con el pulgar sin alargar la pagina. */
  .beat-grid.picks {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 74%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    gap: 12px;
    padding-bottom: 4px;
  }
  .beat-grid.picks::-webkit-scrollbar { display: none; }
  .beat-grid.picks .beat-card { scroll-snap-align: start; }
}


/* ==========================================================================
   REDISENO DE MOVIL, fase 2 (portada, bloques y barra de compra)

   Lo que sigue cambiando respecto al escritorio:

   - La portada tenia DOS botones en fila y un parrafo de 104 px: en el telefono
     la accion principal va a ancho completo y la secundaria debajo, que es lo
     que cabe bajo el pulgar.
   - Los bloques de album arrastraban el relleno de escritorio (24-40 px por
     arriba y por abajo, mas el hueco de la seccion): entre el titulo de un album
     y el anterior habia mas aire que contenido.
   - Faltaba lo mas caracteristico de una tienda en el telefono: una barra fija
     abajo con el precio y el boton de comprar, para no tener que subir a buscar
     el boton despues de leer la licencia. La pone app.js (initBarraCompra) y se
     coloca encima del reproductor cuando hay algo sonando.
   ========================================================================== */
@media (max-width: 899px) {

  /* ---------- 6. Portada: acciones apiladas ---------------------------- */
  .hero-actions { flex-direction: column; align-items: stretch; gap: 9px; }
  .hero-actions .btn { width: 100%; justify-content: center; min-height: 46px; }
  .hero-copy { padding-bottom: 4px; }

  /* ---------- 7. Bloques de album, con el aire justo ------------------- */
  .album-block { padding: 20px 0 8px; }
  .album-head { margin-bottom: 12px; }
  .album-meta { margin-top: 2px; }
  .disco-head { margin: 14px 0 22px; }
  .catalog { gap: 10px; }
  .catalog-wrap { padding-top: 4px; }
  /* Los grupos de contenido (talento, pasos, herramientas) traian el margen de
     escritorio y dejaban un hueco de casi 100 px entre la entradilla y el primer
     bloque: en un telefono eso es media pantalla de nada. */
  .talent-group, .section-lead + .steps, .section-head:first-child { margin-top: 0; }
  .section > .wrap > :first-child { margin-top: 0; }
  /* En los articulos (nosotros) el hueco entre el titular y el primer parrafo
     rondaba los 85 px: el texto empezaba casi fuera de la pantalla. */
  .about-body > :first-child { margin-top: 0; }
  .about-body p { line-height: 1.62; margin-bottom: 1.05em; }
  .about-body p:last-child { margin-bottom: 0; }

  /* ---------- 8. Barra de compra fija ---------------------------------- */
  /* Solo existe en la ficha del beat y solo en el telefono (la crea app.js).
     arranca oculta y aparece cuando el boton de la licencia sale de pantalla. */
  .barra-compra {
    /* z=65: por DEBAJO del reproductor (70) y por encima del contenido y de la
       cabecera (60). Es lo que permite esconderla metida debajo de el. */
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 65;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
    background: color-mix(in srgb, var(--bg-deep) 92%, transparent);
    backdrop-filter: blur(10px);
    border-top: var(--hairline-strong);
    /* Escondida: justo debajo. Mide 71 px y el reproductor 78, asi que queda
       entera dentro de su banda y no asoma ni el borde de arriba. */
    transform: translateY(100%);
    transition: transform .26s var(--ease-soft);
  }
  .barra-compra.is-visible { transform: translateY(0); }
  /* La casa de la barra es el borde de ARRIBA del reproductor, con su alto real.
     `--player-h` (92 px) es el hueco reservado —para que el contenido no quede
     debajo— y mide 14 px mas que el reproductor (78): con el valor reservado, la
     barra escondida asomaba 14 px por encima. `--player-real` lo pone app.js
     midiendo el reproductor. */
  body.has-player .barra-compra { bottom: var(--player-real, var(--player-h)); }
  .barra-compra-datos { display: flex; flex-direction: column; min-width: 0; }
  .barra-compra-datos strong {
    font-family: var(--font-display); font-weight: 700; font-size: .92rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .barra-compra-datos span { font-family: var(--font-display); font-weight: 800; font-size: 1rem; color: var(--blood-text); }
  .barra-compra .btn { flex: 0 0 auto; min-width: 132px; min-height: 46px; justify-content: center; }
}


/* ==========================================================================
   REDISENO DE MOVIL, fase 3: la FICHA DEL BEAT, en orden nativo

   En el telefono la ficha ponia la tabla de datos ENTRE la portada y el nombre:
   el usuario veia "BPM 87 / TONALIDAD Mib Menor / CAMELOT 2A..." antes de saber
   que beat estaba mirando, y la tabla ocupaba 233 px de fila con etiqueta a la
   izquierda y valor a la derecha, que es una maqueta de escritorio.

   Aqui se cambia el orden y la forma:

   - Los dos bloques de la ficha (.beat-page-media y .beat-page-info) se disuelven
     con display: contents, asi que sus piezas pasan a ser hijas directas de la
     rejilla y se pueden ordenar una a una SIN tocar el HTML. En el escritorio
     nada de esto se aplica: alli siguen siendo dos columnas.
   - El orden pasa a ser el de una ficha de producto: portada, nombre, datos y
     despues la licencia.
   - La tabla de datos se convierte en seis recuadros de dos columnas: la etiqueta
     pequena arriba y el valor debajo, alineados a la izquierda. Ocupa 156 px en
     vez de 233.
   ========================================================================== */
@media (max-width: 899px) {

  /* Las piezas de la ficha suben un nivel para poder ordenarlas. */
  .beat-page-media,
  .beat-page-info { display: contents; }

  .beat-page { grid-template-columns: minmax(0, 1fr); gap: 0; }

  /* El orden de una ficha de producto: primero que es, luego cuanto y como. */
  .beat-page-art   { order: 1; margin-bottom: 14px; }
  .dossier-kicker  { order: 2; }
  .beat-page-info > h1 { order: 3; margin-top: 2px; }
  .beat-page-info > .chips { order: 4; margin-top: 10px; }
  .beat-page .spec-list { order: 5; margin: 16px 0 4px; }
  .beat-page .license-card { order: 6; margin-top: 16px; }
  .beat-page .compose-cta { order: 7; }
  .beat-page .beat-page-extra { order: 8; }
  .beat-page .beat-meta-foot { order: 9; }

  /* La portada sigue centrada y algo mas pequeña: el nombre tiene que asomar. */
  .beat-page-art { max-width: 58%; margin-left: auto; margin-right: auto; }

  /* Los datos, en seis recuadros de dos columnas. Etiqueta arriba y valor
     debajo, todo alineado a la izquierda: se lee de un barrido y ocupa la mitad
     de alto que la tabla de escritorio. */
  .beat-page .spec-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .beat-page .spec-list > div {
    display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
    padding: 9px 11px;
    background: var(--surface);
    border: var(--hairline);
    border-radius: var(--radius-sm);
    border-bottom: var(--hairline);
  }
  .beat-page .spec-list dt { font-size: .64rem; letter-spacing: .1em; }
  .beat-page .spec-list dd { text-align: left; font-size: .95rem; }
}


/* ==========================================================================
   REDISENO DE MOVIL, fase 4: LAS PISTAS DEL DISCO

   La fila de pista venia de la lista de escritorio: la duracion escondida en el
   telefono (para ganar sitio) y el precio peleando con el titulo. Ahora muestra
   lo mismo que una app de musica y en dos lineas:

     [▶]  Al Todo O Nada                    4:36
          87 BPM · MIB MENOR · 2A     29.99 USD
                                       [Comprar]

   Arriba la duracion y el precio (lo que se consulta de un vistazo) y debajo el
   boton. La fila mide unos 80 px, asi que diez pistas del disco caben en algo
   mas de una pantalla.
   ========================================================================== */
@media (max-width: 899px) {

  .track-row {
    grid-template-columns: 40px minmax(0, 1fr) auto auto;
    grid-template-areas:
      "play texto tiempo precio"
      "play texto boton  boton";
    align-items: center;
    column-gap: 10px;
    row-gap: 4px;
    padding: 9px 10px;
    background: var(--surface);
    border: var(--hairline);
    border-radius: var(--radius);
  }
  .track-row .play-btn { grid-area: play; place-self: center; }
  .track-row .beat-card-title {
    grid-area: texto; align-self: start;
    font-size: .98rem; line-height: 1.15; min-height: 0; padding: 0; margin: 0;
  }
  .track-row .track-specs {
    grid-area: texto; align-self: end;
    font-size: .68rem; letter-spacing: .02em;
    /* El titulo y los datos comparten celda y se colocan con align-self (arriba
       y abajo). En el primer intento iban al reves y los datos salian ENCIMA del
       titulo; con margenes se descuadraba al cambiar de alto la fila. */
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* La duracion vuelve: en una lista de pistas es lo primero que se mira. Hay que
     devolverle el display, porque el bloque de movil de theme.css la esconde. */
  .track-row .track-time {
    display: block;
    grid-area: tiempo; justify-self: end; align-self: end;
    font-size: .74rem; color: var(--muted-2);
  }
  .track-row .track-price {
    grid-area: precio; justify-self: end; align-self: end;
    font-size: 1rem; white-space: nowrap;
  }
  .track-row .js-add {
    grid-area: boton; justify-self: end; align-self: start;
    min-width: 94px; min-height: 34px;
  }
  /* Ni la miniatura ni el Camelot: en un disco todas las pistas comparten
     portada, y el Camelot sigue estando en la ficha. */
  .track-row .track-thumb { display: none; }
  .track-row .track-camelot { display: none; }

  /* El encabezado del disco, con la portada un poco mas contenida. */
  .disc-hero .beat-page-art, .disco-art { max-width: 58%; margin-inline: auto; }
  /* Aqui habia una regla propia para el titular del disco: ganaba por ir despues
     de la regla unica y dejaba esa pagina en 29,64 px mientras las demas estaban
     en 31,2. Se quito para que el titular sea el mismo en todo el sitio. */
  .disco-actions { display: flex; gap: 9px; }
  .disco-actions .btn { flex: 1 1 auto; justify-content: center; min-height: 44px; }
}


/* ==========================================================================
   UN SOLO TITULAR Y UNA ESCALA DE CAPAS (fase 5)

   Khris aviso de que hay tamaños que no concuerdan entre paginas y de que las
   ventanas flotantes se ponen delante del reproductor de abajo y afean la
   experiencia. Las dos cosas medidas antes de tocar:

   Titulares: 29,64 px en el disco, 32 en nosotros, 33,54 en la portada, 33,6 en
   catalogo/discografia/licencia/contacto, 35,2 en la ficha y 38,4 en talento.
   La culpa era de la especificidad (ver arriba). Ahora 31,2 px en todas.

   Capas, tal como estaban:
     z=60   cabecera (sticky)
     z=70   #player            abajo=0    78 px de alto
     z=78   #toast             abajo=90   (misma banda que la barra de compra)
     z=90   #cart-drawer       abajo=0    pantalla completa  -> TAPABA el reproductor
     z=190  .barra-compra      abajo=92   -> flotaba ENCIMA del carrito abierto
     z=400  #notes-panel       abajo=0    pantalla completa  -> TAPABA el reproductor

   Escala nueva, escrita aqui para que no vuelva a pelearse:
     cabecera 60  <  reproductor 70  <  ventanas 260  <  avisos 300
   Y las ventanas se apoyan ENCIMA del reproductor (bottom: --player-h) en vez de
   taparlo, para poder seguir escuchando mientras se compra o se escribe.
   ========================================================================== */
@media (max-width: 899px) {

  /* ---------- Ventanas flotantes: encima del reproductor, no delante ------ */
  /* Con el reproductor sonando, el carrito y el compositor empiezan por encima
     de el. Sin el reproductor, siguen llegando al borde inferior. */
  /* El CARRITO se apoya encima del reproductor, para poder seguir escuchando
     mientras se compra.
     El COMPOSITOR no lleva hueco a proposito: site.css ya oculta el reproductor
     al abrirlo (body.notes-open .player { display: none }) porque el panel trae
     sus propios controles. Reservandole el hueco quedaba una banda vacia de
     92 px abajo, que es el fallo que salio al medirlo. */
  body.has-player:not(.notes-open) #cart-drawer { bottom: var(--player-h); }
  body.has-player:not(.notes-open) #cart-drawer .drawer-foot { padding-bottom: 14px; }

  /* Por encima de la barra de compra (190): asi el carrito abierto no queda con
     la barra flotando encima, que era lo que se veia. */
  #cart-drawer, #notes-panel, .drawer-overlay { z-index: 260; }

  /* ---------- Avisos: por encima de todo y sin chocar -------------------- */
  /* Estaba en z=78 y abajo=90, justo en la banda de la barra de compra
     (abajo=92), asi que el aviso de «añadido» salia detras de la barra. */
  #toast { z-index: 300; }
  body.has-player #toast { bottom: calc(var(--player-h) + 10px); }
  body:has(.barra-compra.is-visible) #toast { bottom: calc(var(--player-h) + 84px); }

  /* La barra de compra se retira mientras hay una ventana abierta: su sitio lo
     ocupa el propio carrito, que ya lleva su boton. */
  /* Con una ventana abierta no hace falta ninguna regla: el carrito y el
     compositor estan en z=260, o sea por encima de la barra (65), y la tapan
     ellos. Antes habia aqui un escondite propio que ademas peleaba con el
     translateY; con una sola forma de esconderse, no hay dos que se contradigan. */
}


/* ==========================================================================
   SUELO TIPOGRAFICO DE MOVIL (fase 6)

   Khris aviso de «tamaños que tampoco deben ir asi». Medido con
   tools/revisar_texto_minimo.mjs: 31 textos visibles por debajo de 11 px.

       8,96 px  las etiquetas del filtro de BPM ("BPM") en el catalogo
       9,28 px  "Licencia" y "Antes de comprar" en la ficha, y "Anterior"
       9,28 px  "Voces" en talento
       9,28 px  un h2 ENTERO en nosotros ("Lo que no somos")
       9,60 px  la insignia de precio y el nombre del disco de las tarjetas
       9,92 px  los chips de genero del catalogo ("Todos", "Cumbia")
       9,92 px  el kicker de la ficha ("Narcorap, Vol. I · KW-BEAT-003")
      10,24 px  la etiqueta del boton de compra, el "USD" y las etiquetas de datos
      10,88 px  el contador de resultados y la meta de las tarjetas de disco

   Eso es microtipografia de escritorio: cabe, pero no se lee, y es la mitad del
   motivo por el que la pagina parecia encogida. Aqui se pone un suelo de 11,2 px
   (0,7rem) para todo el texto que se lee. Las piezas que SI deben seguir
   pequeñas son las que no son texto corrido: los numeros de pista de los chips
   de filtro ya eran botones, asi que suben con el resto.
   ========================================================================== */
@media (max-width: 899px) {

  /* Etiquetas y kickers, todos al mismo suelo. */
  :is(.kicker, .hero-kicker, .page-head .kicker, .dossier-kicker, .license-kicker,
      .compose-kicker, .notes-kicker, .filter-label, .range-value, .tools-kicker,
      .beat-nav a, .beat-nav span, .talent-group dt, .talent-group dd) {
    font-size: .7rem;
  }

  /* Los chips de filtro son botones: si no se leen, no se saben pulsar. */
  .chip-filter, .chip { font-size: .7rem; }
  .chip { padding: 3px 8px; }

  /* El numero de pista de cada fila y las insignias de las tarjetas. */
  .beat-card-track { font-size: .7rem; min-width: 24px; height: 22px; }
  .beat-card-badge, .beat-card-album-name { font-size: .7rem; }
  .beat-card-price small, .beat-card-actions .js-add span,
  .beat-card-actions .js-add, .track-price small { font-size: .7rem; }
  .results, .album-meta, .disc-card-body small { font-size: .7rem; }

  /* Un h2 no puede ser mas pequeño que el texto que titula. */
  .about-head, .about-body h2 { font-size: 1.05rem; }

  /* En la ficha, las etiquetas de los seis recuadros de datos. */
  .beat-page .spec-list dt { font-size: .7rem; }

  /* Cualquier `small` que se haya quedado sin dueño. */
  small { font-size: .7rem; }
}


/* ==========================================================================
   SUELO, SEGUNDA PASADA (fase 6b)

   El suelo de la fase 6 bajo los textos de 31 a 7, pero siete se resistian porque
   otra regla mas especifica ganaba la cascada. Aqui van con la especificidad
   necesaria, cada una con su medida de partida:

     .hero-release-tag small            "Ultimo lanzamiento"   8,96 px
     .talent-group-head span            "Voces"                9,28 px
     #catalog .beat-card-price small    "USD"                 10,24 px
     #catalog .beat-card-track          "02"                  10,56 px
     #catalog .chip                     "87 BPM"              10,88 px
     .filters-inner .results            "42 beats"            10,88 px
     .breadcrumb a                      "Inicio"              10,88 px
   ========================================================================== */
@media (max-width: 899px) {
  .hero-release-tag small, .talent-group-head span { font-size: .7rem; }
  #catalog .beat-card-price small,
  #catalog .beat-card-track,
  #catalog .chip,
  #catalog .beat-card-actions .js-add span { font-size: .7rem; }
  #catalog .beat-card-track { min-width: 1.5rem; height: 1.4rem; }
  .filters-inner .results { font-size: .7rem; }
  .breadcrumb, .breadcrumb a, .breadcrumb span { font-size: .7rem; }
}


/* ==========================================================================
   CARRUSELES Y BOTONES DE DEDO (fase 7)

   Medido con tools/radiografia_controles.mjs en las ocho paginas de movil.

   CARRUSELES. Solo habia UN carril en todo el movil (la seleccion de la portada).
   El carrusel de relacionados de la ficha seguia siendo la rejilla de escritorio
   con flechas de 38x38: no se podia deslizar, que es como se recorre un carrusel
   en un telefono. Y la tarjeta del carril de la portada estaba ROTA: su boton de
   compra medía 20 px de ancho con el texto cortado, porque dentro del carril la
   tarjeta conservaba la maqueta horizontal de escritorio.

   BOTONES. Por debajo de los 44 px que pide el dedo:
       34x34  reproducir del catalogo
       38x38  reproducir de las pistas del disco
       38x38  flechas de relacionados
       38 px  de alto en los chips de filtro y en el boton de compra del catalogo
       20x44  el boton de compra del carril, con el texto cortado
   ========================================================================== */
@media (max-width: 899px) {

  /* ---------- 1. Reproducir, a tamaño de dedo --------------------------- */
  /* El boton de reproducir es LA accion de un beat: 34 px se falla con el pulgar,
     sobre todo centrado encima de una portada de 80 px. */
  #catalog .play-btn { width: max(2.75rem, 44px); height: max(2.75rem, 44px); }
  #catalog .play-btn svg { width: 18px; height: 18px; }
  /* 84 px de portada y 96 de boton: con 88 y 104 la columna de texto se quedaba en
     126 y los dos chips necesitan 143, asi que partian la fila en dos lineas. */
  /* El reparto del ancho, medido: los dos chips necesitan 140 px y la columna de
     texto tenia 128, asi que partian la fila en dos lineas y todas las filas
     crecian a 130 px. Con la portada en 78 y el boton en 96 la columna sube a 144
     y los chips entran en una linea. */
  #catalog .beat-card { grid-template-columns: 4.875rem minmax(0, 1fr) auto; }
  #catalog .beat-card-media, #catalog .beat-card-media img { width: 4.875rem; height: 4.875rem; }
  #catalog .beat-card-actions .js-add { min-width: max(6rem, 96px); }
  #catalog .chip { padding: 2px 5px; }

  .track-row { grid-template-columns: max(2.75rem, 44px) minmax(0, 1fr) auto auto; }
  .track-row .play-btn { width: max(2.75rem, 44px); height: max(2.75rem, 44px); }
  .track-row .play-btn svg { width: 17px; height: 17px; }

  /* ---------- 2. Chips de filtro y compra, 44 de alto ------------------- */
  .chip-filter { min-height: max(2.75rem, 44px); padding: 0 .9rem; }
  .filters-inner .chip-filters { padding-block: 1px; }
  #catalog .beat-card-actions .js-add,
  .track-row .js-add,
  .catalog.view-list .beat-card-actions .js-add {
    min-height: max(2.75rem, 44px); min-width: max(6rem, 96px);
  }
  .btn-sm { min-height: max(2.75rem, 44px); }

  /* ---------- 3. Relacionados: de rejilla con flechas a carril ---------- */
  /* Las flechas son un mecanismo de escritorio: en el telefono el carrusel se
     recorre deslizando, con enganche por tarjeta y asomando la siguiente. */
  .related .beat-grid {
    display: grid;
    /* grid-template-columns: none es IMPRESCINDIBLE: sin esto el carril conserva
       la columna explicita que traia la rejilla (minmax(0, 1fr)) y las columnas
       automaticas del 74% se comen todo el ancho, asi que la columna 1fr se queda
       en 2 px y la PRIMERA tarjeta del carril sale colapsada. */
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 68%;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -ms-overflow-style: none;
    gap: 12px;
    padding-bottom: 2px;
  }
  .related .beat-grid::-webkit-scrollbar { display: none; }
  .related .beat-card { scroll-snap-align: start; }
  .related-arrow { display: none; }
  .related-head { margin-bottom: 12px; }
  /* El aviso de que se puede deslizar: el borde derecho se desvanece. */
  .related .beat-grid, .beat-grid.picks {
    mask-image: linear-gradient(90deg, #000 92%, transparent);
    -webkit-mask-image: linear-gradient(90deg, #000 92%, transparent);
  }

  /* ---------- 4. La tarjeta de un carril -------------------------------- */
  /* Dentro de un carril la tarjeta se apila en vertical y el boton va a lo ancho.
     Antes conservaba la fila de escritorio y el boton quedaba en 20 px con el
     texto CORTADO. */
  .beat-grid.picks .beat-card-actions,
  .related .beat-card-actions {
    display: flex; flex-direction: column; align-items: stretch; gap: 9px;
  }
  /* lex: 0 0 auto es imprescindible: el boton trae flex:1 1 0% y en flex el
     flex-basis MANDA sobre el width, asi que un width:100% no hacia nada y el
     boton se quedaba en los 20 px de su contenido, con el texto cortado. El
     contenedor tambien tiene que estirarse: medía 32 px. */
  .beat-grid.picks .beat-card-actions,
  .related .beat-card-actions { width: 100%; }
  .beat-grid.picks .beat-card-actions .js-add,
  .related .beat-card-actions .js-add {
    flex: 0 0 auto; width: 100%; min-width: 0; min-height: 44px; justify-content: center;
  }
  /* El precio vuelve a mostrarse: en la rejilla de escritorio el precio de estas
     tarjetas era la insignia sobre la portada, y al quitarla la tarjeta se quedaba
     SIN PRECIO. Ahora el precio va en su sitio, debajo del titulo. */
  .beat-grid.picks .beat-card-price,
  .related .beat-card-price { display: block; align-self: flex-start; font-size: 1.05rem; }
  /* La insignia de precio sobre la portada sobra cuando el precio ya esta debajo. */
  .beat-grid.picks .beat-card-badge,
  .related .beat-card-badge { display: none; }
  /* Los datos de la tarjeta, con el suelo de siempre. */
  .beat-grid.picks .chips, .related .chips { flex-wrap: wrap; gap: 6px; }
  .beat-grid.picks .chip, .related .chip { font-size: .7rem; }
  .beat-grid.picks .beat-card-title, .related .beat-card-title { font-size: 1.05rem; }
  .beat-grid.picks .beat-card-body, .related .beat-card-body { padding-bottom: 2px; }

  /* ---------- 5. Misma accion, mismo boton ------------------------------ */
  /* El mismo «Comprar» salia ROJO en el catalogo y GRIS en las tarjetas de los
     carriles, porque son dos variantes distintas del componente (.btn-primary y
     .btn-ghost) segun la vista con la que se genero la tarjeta. En un telefono,
     donde no hay hover que explique la diferencia, eso se lee como un descuido:
     aqui la accion de compra lleva el color de accion en toda tarjeta. */
  .beat-grid.picks .beat-card-actions .js-add,
  .related .beat-card-actions .js-add {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-blood);
  }
}


/* ==========================================================================
   ANIMACIONES Y EFECTOS DE TOQUE (fase 8)

   En un telefono no existe «pasar el puntero por encima»: el :hover no ocurre, y
   cuando el navegador lo aplica al tocar se queda PEGADO hasta que se toca en otro
   sitio. Lo que se siente de verdad es otra cosa, y es lo que se construye aqui:

     1. RESPUESTA AL TOQUE: que algo cambie bajo el dedo en el instante en que se
        apoya, antes de que llegue el resultado.
     2. DESLIZAMIENTO: los carriles enganchan, y ahora se nota cual quedo enganchada.
     3. SOMBREADO DE LO CENTRADO: al desplazarse en vertical, lo que queda en el
        centro de la pantalla se resalta y el resto se apaga un poco. Es lo mas
        parecido a «pasar el dedo por encima» que existe en un telefono, y sirve
        para saber en que fila estas sin tener que leer.

   Inventario de partida (tools/inventario_hover.py): 130 reglas :hover, de las que
   solo TRES estaban sueltas —96 ya vivian dentro de @media (hover: ...) y por tanto
   no disparan en tactil—. Habia 36 reglas :active, pero su unica señal era un 3% de
   escala, que bajo el pulgar no se ve: hay que cambiar COLOR, no solo tamaño.
   ========================================================================== */
@media (max-width: 899px) {

  /* ---------- 1. Respuesta al toque ------------------------------------- */
  /* Fuera el destello del sistema (el rectangulo gris o azul que pinta el
     navegador al tocar): tapa la respuesta propia y se ve viejo. */
  a, button, .beat-card, .track-row, .chip-filter, .beat-nav-link, label {
    -webkit-tap-highlight-color: transparent;
  }

  /* Transicion cortisima: la respuesta tiene que llegar ANTES que el resultado.
     90 ms es lo que tarda el dedo en notar que algo respondio. */
  :is(.btn, .chip-filter, .play-btn, .cart-btn, .tool-btn, .menu-btn, .index-btn,
      .view-toggle button, .beat-nav-link, .lang button, .notes-tool, .tool-tab,
      .mix-play, .cart-qty button, .drawer-close, .notes-close, .link-more) {
    transition: transform .09s var(--ease-soft), background-color .12s linear,
                border-color .12s linear, color .12s linear, box-shadow .12s linear;
  }

  :is(.btn, .chip-filter, .play-btn, .cart-btn, .tool-btn, .menu-btn, .index-btn,
      .view-toggle button, .beat-nav-link, .lang button, .notes-tool, .tool-tab,
      .mix-play, .cart-qty button, .drawer-close, .notes-close):active {
    transform: scale(.93);
  }
  /* El boton de reproducir necesita su propia regla: en el catalogo y en las
     pistas lleva un selector con ID que fija `transform: none` (#catalog .play-btn
     y .track-row .play-btn, especificidad 1,1,0) y gana a la regla general de
     arriba (0,2,0). Medido: al forzar el estado pulsado NO cambiaba nada. */
  #catalog .play-btn:active,
  .track-row .play-btn:active,
  .beat-grid.picks .play-btn:active,
  .related .play-btn:active {
    transform: scale(.9);
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-blood);
  }
  #catalog .play-btn:active svg,
  .track-row .play-btn:active svg { transform: none; }

  /* El color es lo que se ve bajo el dedo (el 3% de escala no). Cada familia de
     boton se oscurece o se enciende segun su papel. */
  .btn-primary:active, .js-add:active, .cart-btn:active {
    filter: brightness(.88);
    box-shadow: none;
  }
  .btn-outline:active, .btn-ghost:active, .index-btn:active, .tool-btn:active,
  .menu-btn:active, .link-more:active {
    background: var(--surface-2);
    border-color: var(--line-strong);
    color: var(--text);
  }
  .chip-filter:active {
    background: var(--surface-2);
    border-color: var(--accent);
    color: var(--text);
  }
  .beat-nav-link:active, .lang button:active { color: var(--accent); }

  /* ---------- 2. Tarjetas y filas --------------------------------------- */
  :is(#catalog .beat-card, .track-row, .beat-grid.picks .beat-card, .related .beat-card) {
    transition: transform .12s var(--ease-soft), background-color .16s linear,
                border-color .16s linear, opacity .18s linear;
  }
  :is(#catalog .beat-card, .track-row):active {
    background: var(--surface-2);
    border-color: var(--line-strong);
  }
  /* La portada de una fila se inclina un pelo al pulsar: es lo que confirma que
     el toque entro en la tarjeta y no en el hueco de al lado. */
  :is(#catalog .beat-card, .track-row):active .beat-card-media img,
  :is(#catalog .beat-card, .track-row):active .beat-card-visual img {
    transform: scale(.94);
    transition: transform .09s var(--ease-soft);
  }

  /* ---------- 3. Sombreado de lo que queda en el centro ------------------ */
  /* Las clases las pone app.js (initToque) con un observador sobre la banda
     central de la pantalla. Solo en el telefono: en el escritorio no se marca.

     Fase 8d: el resalte se hace con FONDO, BORDE Y SOMBRA, no bajando la opacidad
     del resto. Dos reglas de la casa (`.has-js .beat-card` y `.animations-done`)
     fijan `opacity: 1 !important` en toda tarjeta, porque con JavaScript activo
     los elementos se revelan a plena luz al acabar su animacion de entrada; un
     apagado por opacidad pierde contra ellas, y responder con otro !important es
     como se pudren las hojas de estilo. Ademas asi el desplazamiento no obliga al
     navegador a componer una capa nueva por fila. */
  body.kw-resalta :is(#catalog .beat-card, .track-row).is-centro {
    background: var(--surface-3, var(--surface-2));
    border-color: var(--line-strong);
    /* La barra de acento pegada al borde izquierdo es lo que se lee de un vistazo;
       solo con el fondo, la diferencia entre rgb(28,22,19) y rgb(20,16,13) no se
       percibia en la captura. Es la misma idea que el indicador de «pista actual»
       de una app de musica. */
    box-shadow: inset 3px 0 0 var(--accent), var(--shadow-soft);
  }
  /* En los carriles el centro es horizontal: manda la tarjeta enganchada. */
  body.kw-resalta :is(.beat-grid.picks, .related .beat-grid) .beat-card.is-activa {
    border-color: var(--accent);
    box-shadow: var(--shadow-soft);
  }
  body.kw-resalta :is(.beat-grid.picks, .related .beat-grid) .beat-card {
    transition: border-color .2s linear, box-shadow .2s linear;
  }

  /* ---------- 4. El reproductor, al aparecer ---------------------------- */
  /* El reproductor de abajo entra deslizando en vez de aparecer de golpe. */
  #player { transition: transform .22s var(--ease-soft), opacity .22s linear; }
}

/* Con «reducir movimiento» activado no se anima nada: los cambios son inmediatos,
   que es lo que pide quien marca esa preferencia. */
@media (max-width: 899px) and (prefers-reduced-motion: reduce) {
  :is(.btn, .chip-filter, .play-btn, .cart-btn, .tool-btn, .menu-btn, .index-btn,
      .view-toggle button, .beat-nav-link, .lang button, .notes-tool, .tool-tab,
      .mix-play, .cart-qty button, .drawer-close, .notes-close, .link-more,
      #catalog .beat-card, .track-row, .beat-grid.picks .beat-card, .related .beat-card) {
    transition-duration: .01ms;
  }
  #catalog .beat-card:active .beat-card-media img,
  #catalog .beat-card:active .beat-card-visual img { transform: none; }
  /* OJO: aqui NO se pone opacity: 1. Resaltar lo que esta en el centro no es una
     animacion, es informacion: con esta preferencia hay que quitar el movimiento
     (las transiciones, arriba), no el resalte. Poniendolo, el apagado desaparecia
     y el efecto se quedaba en nada — que es justo lo que se midio. */
}

/* ==========================================================================
   AJUSTES MEDIDOS DEL REPARTO DE LA FILA (fase 8e)

   Van al FINAL del archivo a proposito. Las mismas propiedades estaban antes en
   el bloque del catalogo, pero una regla posterior de ese mismo bloque
   (min-width: 104px) volvia a ganarles: medido, el boton seguia en 104 px.

   El reparto, con numeros: de los 362 px de la fila, 20 son de relleno, 78 de
   portada, 24 de los dos huecos y 96 del boton; a la columna de texto le quedan
   144. Los dos chips (BPM y tonalidad) necesitan 132 con este apretado. Con 128
   de columna partian la fila en dos lineas y TODAS las filas crecian a 130 px.
   ========================================================================== */
@media (max-width: 899px) {
  #catalog .beat-card { grid-template-columns: 4.875rem minmax(0, 1fr) auto; }
  #catalog .beat-card-media, #catalog .beat-card-media img { width: 4.875rem; height: 4.875rem; }
  #catalog .beat-card-actions .js-add { min-width: 96px; }
  #catalog .chips { gap: .2rem; }
  #catalog .chip { padding: .12rem .25rem; }
}


/* ==========================================================================
   LAS VENTANAS FLOTANTES, POR ENCIMA DEL REPRODUCTOR COMPLETO (fase 10)

   Medido: al tocar el boton de herramientas DENTRO del reproductor a pantalla
   completa, el panel del compositor se abria pero no se veia. Las capas estaban:

       #player-panel  (reproductor completo)   z=300
       #notes-panel   (compositor)             z=260   <- por debajo

   y en el centro de la pantalla quedaba `div.full-stage`, o sea el reproductor.
   Al carrito le pasaba lo mismo: el reproductor completo tiene su propio boton de
   carrito (.full-cart) y el cajon tambien estaba en 260.

   La regla es simple: una ventana que se abre SOBRE otra tiene que estar por
   encima en el orden de capas. El reproductor completo es la superficie mas alta
   de la navegacion normal (300), asi que las ventanas van en 340 y su telon en
   335 (justo debajo, para oscurecer lo de atras sin taparse a si mismas).

   Escala completa de movil, ya en un solo sitio:
       60  cabecera
       65  barra de compra (bajo el reproductor basico, para poder esconderse)
       70  reproductor basico
      260  cajon del carrito y compositor (cuando NO hay reproductor completo)
      300  reproductor a pantalla completa
      340  las ventanas cuando se abren sobre el
      360  avisos
   ========================================================================== */
@media (max-width: 899px) {
  #cart-drawer, #notes-panel { z-index: 340; }
  .drawer-overlay { z-index: 335; }
  #toast { z-index: 360; }
}


/* ==========================================================================
   LA ESTRUCTURA DE LA FILA ESCALA CON LA LETRA (fase 11)

   Khris: «las listas del catalogo en movil estan desproporcionales, se agrandan
   con el texto grande». Medido emulando la preferencia de tamaño de letra del
   navegador (que es lo que hace crecer el rem):

       letra base   fila    portada   portada/fila   chips
          16 px     109 px    78 px       0,72        1 linea
          20 px     166 px    78 px       0,47        3 lineas
          24 px     189 px    78 px       0,41        3 lineas

   El texto crecia y la portada no: el texto va en `rem` (sigue la preferencia del
   usuario) y la estructura iba en `px` (no la sigue). De ahi la desproporcion.

   Ahora la portada, el boton de compra, el de reproducir y los huecos van en
   `rem`, asi que crecen CON la letra y la fila mantiene su forma. Los objetivos
   tactiles llevan ademas un minimo en px —`max(2.75rem, 44px)`— para que nunca
   bajen de los 44 px del dedo aunque el usuario tenga la letra pequeña.

   A 16 px (el valor de siempre) no cambia nada: 4.875rem son 78 px, 2.75rem son
   44 px, 6rem son 96 px y .625rem son 10 px.
   ========================================================================== */
@media (max-width: 899px) {
  /* El numero de pista de la fila y los datos, para que acompañen. */
  .track-row .beat-card-track { min-width: 1.5rem; height: 1.4rem; }
  .track-row .chips { gap: .2rem; }

  /* Cuando la letra es MUY grande respecto a la pantalla, la fila se parte en dos
     plantas en vez de apretujar el texto contra la portada. Se mide en `em`, que
     en una consulta de medios vale el tamaño de letra del usuario: 390 px con
     letra de 16 px son 24,4em, y con letra de 24 px son 16,2em. Asi la consulta
     se activa sola cuando la letra ha crecido, sin preguntar nada al navegador. */
  /* 21em: con letra de 16 px, 390 px de pantalla son 24,4em y la fila va en una
     linea; con letra de 20 px son 19,5em y con 24 px son 16,2em, asi que en esos
     dos casos se parte en dos plantas. */
  @media (max-width: 21em) {
    #catalog .beat-card {
      grid-template-columns: 4.875rem minmax(0, 1fr);
      grid-template-areas:
        "art body"
        "actions actions";
      row-gap: .5rem;
    }
    #catalog .beat-card-actions {
      flex-direction: row; align-items: center; justify-content: space-between;
    }
    #catalog .beat-card-actions .js-add { width: auto; }
  }
}


/* ==========================================================================
   EL CARRIL SE QUEDABA PEGADO (fase 12)

   Lo que se veia: en la ficha, el carril de «Mas de este album» mostraba tarjetas
   cortadas por la izquierda y al deslizar no se movia. Medido con un arrastre de
   dedo de verdad: tras arrastrar 260 px se quedaba en scrollLeft=316 y el primer
   hijo estaba en offsetLeft=-975, o sea el contenido desbordaba HACIA LA
   IZQUIERDA, que es la direccion en la que un carril no se puede desplazar.

   La causa esta en site.css:

       .related .beat-grid { justify-content: center; }

   En escritorio es correcto —el carrusel pinta 4 tarjetas de 228 px en un carril
   de 966, y centrarlas no desborda—, pero el carril de movil mete NUEVE tarjetas
   de 246 px en 362: al centrar 2.215 px de columnas, el desborde se reparte entre
   los dos lados y las primeras tarjetas quedan a -975 px, fuera del alcance del
   deslizamiento.

   En un carril el contenido se alinea al PRINCIPIO: asi el desborde queda a la
   derecha, que es hacia donde se desliza, y se recorren las nueve.
   ========================================================================== */
@media (max-width: 899px) {
  .related .beat-grid,
  .beat-grid.picks {
    justify-content: start;
    align-content: start;
  }
}


/* ==========================================================================
   EL AVISO TAPABA EL BOTON DE COMPRAR (fase 13)

   Visto en la captura del carrito con dos articulos: el aviso de «añadido al
   carrito» sale justo encima de «Finalizar compra», asi que el boton principal
   del carrito queda tapado mientras el aviso dura — unos segundos, y justo en el
   momento en que el usuario va a pulsarlo.

   El aviso tiene su sitio abajo, donde confirma lo que acabas de hacer sin tapar
   nada; pero con una ventana abierta ese sitio lo ocupa su pie de acciones. Asi
   que con una ventana abierta el aviso pasa ARRIBA, debajo de la cabecera, donde
   no estorba a nada.
   ========================================================================== */
@media (max-width: 899px) {
  body:has(.drawer.is-open) #toast,
  body:has(.notes.is-open) #toast {
    top: calc(var(--header-h, 73px) + 10px);
    bottom: auto;
  }
}


/* ==========================================================================
   INICIO, PASO 1 (fase 14)

   Medido con tools/revisar_pagina.mjs inicio 390 844:

   1. LOS CHIPS DE UN CARRIL NO SE PARTEN. «87 BPM» salia en una caja de 60 px con
      dos lineas. Un chip es una etiqueta: se le prohibe partirse y se le impide
      encogerse dentro de su fila.
   2. LA ETIQUETA DEL BOTON DE COMPRAR DEL CARRIL iba a 11,2 px mientras el resto de
      botones van a 13,44. El suelo de 11,2 px es para DATOS, no para la etiqueta de
      una accion: un boton se lee al tamaño de boton.
   3. LOS BOTONES DE SECCION quedaban escalonados (180 px y 219 px, los dos a la
      izquierda). En el telefono la accion va a lo ancho, como en el heroe.
   ========================================================================== */
@media (max-width: 899px) {
  /* 1. chips enteros */
  .beat-grid.picks .chip,
  .related .chip,
  .beat-card .chip { white-space: nowrap; flex: 0 0 auto; }

  /* 2. la etiqueta de un boton, al tamaño de boton */
  .beat-grid.picks .beat-card-actions .js-add span,
  .related .beat-card-actions .js-add span,
  .beat-card-actions .js-add span { font-size: .84rem; }
  #catalog .beat-card-actions .js-add span { font-size: .84rem; }

  /* 3. las acciones de seccion, a lo ancho */
  .section-cta { flex-direction: column; align-items: stretch; gap: 10px; margin-top: 24px; }
  .section-cta .btn { width: 100%; justify-content: center; min-height: 50px; }
}


/* ==========================================================================
   EFECTO DE CURSOR QUE SE QUEDA PEGADO (fase 15, detalle de Inicio)

   Inventario a 390: de las 45 reglas :hover que tocan elementos de Inicio, 44 ya
   viven dentro de @media (hover: ...) y no disparan en tactil. Quedaba UNA suelta,
   la del halo de los botones de compra (theme.css L3565):

       .buy-cta:hover, .buy-cta:focus-visible { box-shadow: 0 0 0 4px rgba(...) }

   En un telefono el navegador aplica :hover al tocar y NO lo suelta hasta que se
   toca en otro sitio, asi que despues de comprar el boton se quedaba con el halo
   encendido, como si siguiera pulsado. Se quita SOLO el hover: el foco de teclado
   se conserva, que es accesibilidad y no un efecto de raton.

   Las otras dos sueltas del sitio se dejan a proposito: la del desplegable nativo
   no se pinta, y la del boton de reproducir no cambia nada porque en tactil ese
   boton ya esta siempre visible.
   ========================================================================== */
@media (max-width: 899px) {
  .buy-cta:hover:not(:focus-visible) { box-shadow: none; }
}


/* ==========================================================================
   DETALLES FINOS DE INICIO (fase 16)

   1. EL ENCABEZADO DE SECCION NO SE APILA. Estaba en `flex-direction: column` en
      movil, asi que «Ver todos» caia DEBAJO del titulo y se leia como un subtitulo.
      Medido: titulo 65 px y enlace 79; en 362 hay sitio para los dos en una linea.
   2. EL NUMERO ROMANO DE LAS TARJETAS DE DISCO NO SE PONE ENCIMA DEL ARTE. La
      pastilla de 34x34 va en la esquina superior izquierda de la portada, que es
      justo donde el arte de cada disco ya trae su titulo: en la captura a doble
      resolucion se leia «II NARCORAP, VOL. II», como si el numero formara parte del
      titulo. El nombre del disco ya va escrito debajo de la portada.
   3. RITMO. Los huecos del heroe eran 18 / 20 / 32, y los dos primeros son el MISMO
      tipo de hueco (de una linea de texto a la siguiente). Se unifican a 16, y los
      numeros sueltos (9 entre los botones del heroe, 10 entre las acciones de
      seccion) pasan a 12. La rejilla de discos, de 14 a 16.
   4. LINEAS HUERFANAS. La entradilla del heroe acababa en una linea de 87 px frente
      a 314 de media, y un paso con una de 37 frente a 337 (11%). `text-wrap: pretty`
      reparte el texto para que la ultima linea no quede sola; donde no se soporta,
      se envuelve igual que antes.
   ========================================================================== */
@media (max-width: 899px) {

  /* 1. Titulo a la izquierda y enlace a la derecha, en la misma linea. */
  .section-head {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 16px;
    margin-bottom: 18px;
  }

  /* 2. La pastilla del numero romano no compite con el titulo del arte. */
  .disc-card-numeral { display: none; }

  /* 3. El ritmo del heroe, en una sola escala. */
  .hero-kicker { margin-bottom: 16px; }
  .hero-sub { margin-top: 16px; }
  .hero-actions { margin-top: 28px; gap: 12px; }
  .section-cta { gap: 12px; }
  .disc-grid { gap: 16px; }

  /* 4. Que la ultima linea de un parrafo no quede sola. */
  p, li, .hero-sub, .section-lead { text-wrap: pretty; }
}


/* ==========================================================================
   CARRUSEL CENTRADO, ESTILO PLAYSTATION (fase 17)

   Lo que pide Khris: mas compacto y mas chico, la tarjeta del centro a tamaño
   completo y las de los lados mas pequeñas, y que al arrastrar el dedo la
   siguiente se vaya centrando MIENTRAS crece y la que estaba centrada se vaya al
   otro lado MIENTRAS encoge.

   Como queda montado:

   - El carril declara columnas del 64% y un relleno del 18% a cada lado, con el
     MISMO `scroll-padding`. Ese relleno es lo que permite que la primera y la
     ultima tambien puedan quedar centradas: sin el, no habria recorrido para
     llevarlas al medio.
   - El enganche pasa de `start` a `center`, asi que al soltar el dedo siempre hay
     una tarjeta en el centro.
   - Cada tarjeta lleva `transform: scale(var(--esc, 1))` con el origen en su
     centro, y app.js calcula `--esc` en cada fotograma segun lo lejos que este su
     centro del centro del carril: de 1 (centrada) a 0,78 (en el borde).

   El escalado es desde el centro, asi que encoger no desplaza el centro de la
   tarjeta: lo que se mide (distancias) y lo que se pinta (escala) no se
   realimentan. Se quita el desvanecido del borde: con las tarjetas de los lados a
   la vista y mas pequeñas, el carril ya avisa de que hay mas.
   ========================================================================== */
@media (max-width: 899px) {
  .beat-grid.picks,
  .related .beat-grid {
    /* OJO con los porcentajes: en una rejilla, grid-auto-columns: 64% se calcula
       sobre la CAJA DE CONTENIDO, y con 18% de relleno a cada lado esa caja ya es el
       64% del carril: la tarjeta salia de 148 px en vez de 232, y por eso ademas la
       primera no quedaba centrada (el relleno y la columna no sumaban el carril).
       Con el relleno puesto, la columna tiene que ser el 100% de la caja. */
    grid-auto-columns: 100%;
    padding-inline: 18%;
    scroll-padding-inline: 18%;
    mask-image: none;
    -webkit-mask-image: none;
    gap: 10px;
  }

  .beat-grid.picks .beat-card,
  .related .beat-grid .beat-card {
    scroll-snap-align: center;
    transform: scale(var(--esc, 1));
    transform-origin: 50% 50%;
  }

  /* El borde de la tarjeta centrada lleva el COLOR DE SU ALBUM (fase 19). Aqui
     ponia un borde neutro porque la escala ya decia cual estaba en el centro; ahora
     el color es parte del enfoque, que es lo que pide Khris. */
  body.kw-resalta :is(.beat-grid.picks, .related .beat-grid) .beat-card.is-activa {
    border-color: var(--accent);
    box-shadow: none;
  }

  /* Mas compacto: menos aire dentro de la tarjeta y entre sus piezas. */
  .beat-grid.picks .beat-card,
  .related .beat-grid .beat-card { padding: 8px; }
  .beat-grid.picks .beat-card-body,
  .related .beat-grid .beat-card-body { padding: 8px 2px 2px; gap: 0; }
  .beat-grid.picks .chips,
  .related .beat-grid .chips { margin-top: 0; }
  /* Precio y boton en la MISMA linea: la tarjeta del carril baja unos 50 px de
     alto y se ve mas compacta, que es lo que pide Khris. El boton conserva sus 44
     px de alto y de ancho le basta con el texto. */
  .beat-grid.picks .beat-card-actions,
  .related .beat-grid .beat-card-actions {
    flex-direction: row; align-items: center; justify-content: space-between;
    gap: 8px;
  }
  .beat-grid.picks .beat-card-actions .js-add,
  .related .beat-grid .beat-card-actions .js-add {
    width: auto; min-width: max(5.5rem, 88px); min-height: max(2.75rem, 44px);
    padding-inline: 12px;
  }
  .beat-grid.picks .beat-card-title,
  .related .beat-grid .beat-card-title { font-size: 1rem; }
}


/* ==========================================================================
   LA TARJETA LATERAL NO SE MEDIO-PULSA, SE CENTRA (fase 18)

   La escala del carrusel encoge TAMBIEN los controles: medido, el boton de comprar
   de una tarjeta lateral baja a 34 px de alto y el de reproducir a 41, por debajo
   de los 44 que pide el dedo.

   Agrandarlos en la maqueta obligaria a ponerlos de 57 px en la tarjeta centrada
   (44 / 0,78) y eso engorda la tarjeta justo cuando se pide mas compacta. Se
   resuelve como funciona un carrusel de este tipo: los controles de una tarjeta que
   no esta centrada no reciben el toque, y el toque CENTRA la tarjeta. Cuando esta
   centrada, sus botones funcionan con su tamaño completo.
   ========================================================================== */
@media (max-width: 899px) {
  .beat-grid.picks .beat-card:not(.is-activa) .js-add,
  .beat-grid.picks .beat-card:not(.is-activa) .play-btn,
  .related .beat-grid .beat-card:not(.is-activa) .js-add,
  .related .beat-grid .beat-card:not(.is-activa) .play-btn {
    pointer-events: none;
  }
}


/* ==========================================================================
   EL CARRIL: COLOR DEL ALBUM Y EFECTOS AL CENTRARSE (fase 19)

   Khris: el sombreado tiene que concordar con el color de la portada de cada album
   (como en otras secciones); al centrarse debe aparecer el boton de reproducir; y
   los efectos que hoy son de ARRASTRAR EL PUNTERO deben pasar a ser del ENFOQUE, o
   sea de la tarjeta centrada. El titulo del beat, centrado por defecto.

   Los cinco efectos de puntero que se trasladan al estado centrado:

     site.css  L461   la portada se acerca            (transform: scale(1.04))
     theme.css L1118  aparece el boton de reproducir  (opacity: 1)
     site.css  L987   la tarjeta se levanta con halo  (transform + box-shadow)
     theme.css L1088  el borde se tiñe                (border-color: var(--accent))
     site.css  L512   se ilumina el nombre            (color)

   El COLOR sale de la portada de cada album: el generador lo extrae y ahora lo
   reparte a todas las tarjetas de ese album con `--accent`.

   La PALPITACION es un anillo de un pseudo-elemento que anima OPACIDAD y ESCALA,
   no box-shadow: box-shadow no se compone en la GPU y obligaria a repintar en cada
   fotograma. Es la misma decision que ya tomo la casa con el latido de la compra.
   ========================================================================== */
@media (max-width: 899px) {
  /* El CARRIL tiene que ser el origen de coordenadas: app.js mide los centros con
     offsetLeft, y sin position: relative en el carril esa medida sale referida al
     body y arrastra el margen de la pagina (14 px). Con esos 14 px de mas, la tarjeta
     centrada se quedaba en 0,98 en vez de 1,00. */
  .beat-grid.picks, .related .beat-grid { position: relative; }
  .beat-grid.picks .beat-card,
  .related .beat-grid .beat-card { position: relative; }

  /* ---------- La portada se acerca, pero solo en la centrada -------------- */
  .beat-grid.picks .beat-card-media img,
  .related .beat-grid .beat-card-media img {
    transition: transform .42s var(--ease-soft);
    transform: scale(1);
  }
  .beat-grid.picks .beat-card.is-activa .beat-card-media img,
  .related .beat-grid .beat-card.is-activa .beat-card-media img { transform: scale(1.06); }

  /* ---------- El boton de reproducir: solo lo enseña la centrada ---------- */
  .beat-grid.picks .play-btn,
  .related .beat-grid .play-btn { opacity: 0; transition: opacity .3s var(--ease-soft); }
  .beat-grid.picks .beat-card.is-activa .play-btn,
  .related .beat-grid .beat-card.is-activa .play-btn { opacity: 1; }

  /* ---------- El borde se tiñe con el color del album --------------------- */
  .beat-grid.picks .beat-card.is-activa,
  .related .beat-grid .beat-card.is-activa {
    border-color: var(--accent);
    transform: translateY(-2px) scale(var(--esc, 1));
  }

  /* ---------- La palpitacion de color alrededor de la tarjeta ------------- */
  .beat-grid.picks .beat-card.is-activa::after,
  .related .beat-grid .beat-card.is-activa::after {
    content: "";
    position: absolute; inset: 0;
    border-radius: inherit;
    border: 1px solid var(--accent);
    pointer-events: none;
    opacity: .3;
    animation: kwLatidoTarjeta 2.8s ease-in-out infinite;
  }
  @keyframes kwLatidoTarjeta {
    0%, 100% { opacity: .26; transform: scale(1); }
    50%      { opacity: .62; transform: scale(1.014); }
  }

  /* ---------- Se ilumina el nombre del beat ------------------------------ */
  .beat-grid.picks .beat-card-title,
  .related .beat-grid .beat-card-title {
    text-align: center;
    transition: color .3s var(--ease-soft);
  }
  .beat-grid.picks .beat-card.is-activa .beat-card-title,
  .related .beat-grid .beat-card.is-activa .beat-card-title { color: var(--accent); }

  /* ---------- El titulo centrado por defecto, y su bloque con el --------- */
  .beat-grid.picks .beat-card-body,
  .related .beat-grid .beat-card-body { align-items: center; text-align: center; }
  .beat-grid.picks .beat-card-album,
  .related .beat-grid .beat-card-album { justify-content: center; }
  .beat-grid.picks .chips,
  .related .beat-grid .chips { justify-content: center; }

  /* ---------- El precio, alineado con el boton --------------------------- */
  /* Tenia `align-self: flex-start` de cuando iba ENCIMA del boton; al pasar los dos
     a la misma linea eso lo dejaba pegado arriba mientras el boton quedaba centrado:
     es el desalineado que se veia. */
  .beat-grid.picks .beat-card-price,
  .related .beat-grid .beat-card-price {
    align-self: center;
    line-height: 1;
  }
  .beat-grid.picks .beat-card-actions,
  .related .beat-grid .beat-card-actions { align-items: center; }
  .beat-grid.picks .beat-card .disc-card-numeral,
  .related .beat-grid .beat-card .disc-card-numeral { display: inline-flex; }

  /* Con «reducir movimiento»: el resalte se queda, el latido no. */
  @media (prefers-reduced-motion: reduce) {
    .beat-grid.picks .beat-card.is-activa::after,
    .related .beat-grid .beat-card.is-activa::after { animation: none; opacity: .5; }
  }
}


/* ==========================================================================
   LA ACCION NO CAMBIA DE COLOR CON EL ALBUM (fase 19b)

   Al poner el color del album en la tarjeta (--accent), el boton de comprar se
   teñia tambien, porque usa esa misma variable. El sombreado debe concordar con la
   portada, pero la accion de compra tiene que ser la misma en todas partes
   (KW-MOV-022): aqui se le devuelve su color de accion. Si algun dia se quiere el
   boton del color del album, basta con quitar estas cuatro lineas.
   ========================================================================== */
@media (max-width: 899px) {
  .beat-grid.picks .beat-card-actions .js-add,
  .related .beat-grid .beat-card-actions .js-add {
    background: var(--blood);
    border-color: var(--blood);
    color: var(--on-blood);
  }
}


/* ==========================================================================
   PULSADO SIN HUNDIRSE, PANTALLA CHICA, PULSO LENTO Y FLUIDEZ (fase 20)

   1. EL BOTON DE REPRODUCIR SE HUNDIA. Esta centrado sobre la portada con
      `transform: translate(-50%, -50%)`, y la regla del estado pulsado ponia
      `transform: scale(.93)`, que BORRA ese translate: al tocarlo el boton saltaba
      26 px abajo y a la derecha. Medido: su centro coincidia con el de la portada
      (160, 3912) y al pulsar se iba. Lo mismo con los botones de la cabecera, que se
      centran con `translateY(-50%)` (-22 px): al pulsarlos saltaban 22 px y parecian
      cortados por arriba. El estado pulsado tiene que CONSERVAR el translate.

   2. EN UNA PANTALLA DE 320 EL BOTON DE COMPRA SE SALIA DE LA TARJETA. El precio
      (78 px) mas el boton (88 de minimo) mas el hueco (8) son 174, y dentro de una
      tarjeta de 187 con 16 de relleno caben 171. Ahora el precio es fijo y el boton
      se queda con lo que sobra (`flex: 1 1 auto`), asi que la fila entra siempre.

   3. EL PULSO ERA MUY MARCADO Y RAPIDO. Pasa de 0,26-0,62 en 2,8 s a 0,14-0,30 en
      4,5 s: un filo que respira despacio en vez de un parpadeo.

   4. FLUIDEZ. La escala se calculaba en JavaScript en cada fotograma, leyendo la
      posicion de cada tarjeta: eso obliga al navegador a recalcular la maqueta
      mientras el dedo arrastra. Donde el navegador sabe hacerlo, la escala, la
      aparicion del play y el color se atan a la LINEA DE TIEMPO DEL DESPLAZAMIENTO
      (`animation-timeline: view(inline)`), que corre en la tarjeta de video y no
      pasa por JavaScript. El calculo de JavaScript se queda como respaldo para
      navegadores que no lo soportan.
   ========================================================================== */
@media (max-width: 899px) {

  /* ---------- 1. Pulsado que conserva el centrado ------------------------- */
  .beat-grid.picks .play-btn:active,
  .related .beat-grid .play-btn:active,
  .beat-page-art .play-btn:active,
  .beat-card .play-btn:active { transform: translate(-50%, -50%) scale(.9); }

  .menu-btn:active, #menu-open:active,
  .cart-btn:active, #cart-open:active,
  .index-btn:active, .tool-btn:active { transform: translateY(-50%) scale(.9); }

  /* ---------- 2. La fila del precio y la compra, que siempre entre -------- */
  .beat-grid.picks .beat-card-actions .js-add,
  .related .beat-grid .beat-card-actions .js-add {
    flex: 1 1 auto; min-width: 0; width: auto;
  }
  .beat-grid.picks .beat-card-price,
  .related .beat-grid .beat-card-price { flex: 0 0 auto; }

  /* ---------- 3. El pulso, lento y sutil --------------------------------- */
  .beat-grid.picks .beat-card.is-activa::after,
  .related .beat-grid .beat-card.is-activa::after { animation-duration: 4.5s; }
  @keyframes kwLatidoTarjeta {
    0%, 100% { opacity: .14; transform: scale(1); }
    50%      { opacity: .3;  transform: scale(1.008); }
  }

  /* Aqui vivia la escala atada a la linea de tiempo del desplazamiento
     (`animation-timeline: view(inline)`). NO funciono: el navegador dice soportar la
     propiedad pero la animacion no se aplicaba nunca (medido: animation-name seguia
     en none, incluso en forma larga con `animation-duration: auto`). La escala se
     calcula en app.js, que ademas ahora no lee la maqueta en cada fotograma. */
}


/* ==========================================================================
   SIN RETRASO EN LA ESCALA, Y EL CARRIL UNOS PIXELES MAS ABAJO (fase 23)

   1. LA ESCALA DEL CARRIL NO LLEVA TRANSICION. La tarjeta tenia
      `transition: transform .12s` (la puse para el estado pulsado, y ahi esta bien).
      Pero el carril escribe la escala en CADA fotograma mientras el dedo arrastra:
      con una transicion encima, la escala va 120 ms por detras del dedo y entra a
      trozos. Esa es la causa de que se vea entrecortado y de que no haya animaciones
      suaves. La escala tiene que seguir al dedo exactamente; las transiciones de
      color y borde se quedan, que esas si son cambios de estado.
   2. El carril baja unos pixeles respecto al encabezado de seccion.
   ========================================================================== */
@media (max-width: 899px) {
  /* Con !important a proposito: la regla de la fase 8 que puso esta transicion usa
     un :is() que lleva un id dentro (#catalog .beat-card), y el peso de un :is()
     es el de su argumento MAS especifico, asi que aquella regla pesa como un id y gana
     a cualquier selector de clases por mucho que venga despues. Comprobado: sin el
     !important, 	ransition-property seguia empezando por 	ransform. */
  .beat-grid.picks .beat-card,
  .related .beat-grid .beat-card {
    transition-property: background-color, border-color, opacity !important;
    transition-duration: .16s, .16s, .18s !important;
  }
  /* El carril, unos pixeles mas abajo del encabezado. El margen del carril NO sirve:
     se junta con el del encabezado y el navegador se queda con el mayor, asi que el
     carril no bajaba nada (medido: el hueco seguia en 18). Se sube el del encabezado
     de la seccion que lleva el carril, que si suma. */
  .section:has(.beat-grid.picks) .section-head { margin-bottom: 22px; }
}


/* ==========================================================================
   ARRASTRE LIBRE Y TARJETA SIN SALIRSE DE SU CAJA (fase 24)

   1. FUERA EL ENGANCHE DEL NAVEGADOR. `scroll-snap-type: x mandatory` hace que el
      navegador vaya RECOLOCANDO el carril MIENTRAS el dedo esta apoyado: en Android se
      siente como si el carril se peleara con el dedo, a tirones. El centrado lo hace
      ahora app.js al levantar el dedo, con un desplazamiento suave: el arrastre queda
      libre y solo se asienta al final.

   2. LA TARJETA NO SE SALE DE SU CAJA. La centrada llevaba `translateY(-2px)`, que la
      saca hacia arriba, y el anillo crece un 1,4%: entre los dos asomaban por encima de
      la seccion y la cabecera fija se los comia («el techo se come un poco de la
      tarjeta»). Se quita el levantamiento —la escala ya destaca la tarjeta— y las
      secciones dejan el alto de la cabecera como margen de desplazamiento.
   ========================================================================== */
@media (max-width: 899px) {
  .beat-grid.picks,
  .related .beat-grid { scroll-snap-type: none; }
  .beat-grid.picks .beat-card,
  .related .beat-grid .beat-card { scroll-snap-align: none; }

  /* La centrada ya no se levanta: la escala y el color la destacan de sobra. */
  .beat-grid.picks .beat-card.is-activa,
  .related .beat-grid .beat-card.is-activa { transform: scale(var(--esc, 1)); }

  /* El anillo crece hacia fuera: se queda dentro del relleno de la seccion. */
  .beat-grid.picks, .related .beat-grid { padding-block: 4px; }

  /* Nada de la seccion queda por debajo de la cabecera fija. */
  section[id], .section { scroll-margin-top: calc(var(--alto-cabecera, 73px) + 8px); }
}


/* ==========================================================================
   LA DISCOGRAFIA, CON EL MISMO CARRUSEL CENTRADO (fase 25)

   La discografia de la portada estaba en una rejilla de dos columnas. Pasa al mismo
   carrusel que la seleccion: la del centro a tamaño completo, las de los lados mas
   pequeñas, el color del album en el borde y en el nombre, el anillo palpitando
   despacio y el asentamiento suave al levantar el dedo.

   La maquinaria de app.js ya es generica, asi que aqui solo van las piezas propias
   del disco (`.disc-card`, que es un enlace, no un `article.beat-card`) y las cuatro
   lecciones de las rondas anteriores: el carril es el origen de coordenadas de las
   medidas, la escala no lleva transicion, el enganche del navegador se queda fuera, y
   la tarjeta centrada no se levanta de su caja.
   ========================================================================== */
@media (max-width: 899px) {
  .disc-grid {
    display: grid;
    grid-auto-flow: column;
    /* El porcentaje de una columna se calcula sobre la CAJA DE CONTENIDO: con el 18%
       de relleno a cada lado, la caja ya es el 64% del carril, asi que la columna
       tiene que ser el 100% para que la tarjeta mida el 64% del carril. */
    grid-auto-columns: 100%;
    padding-inline: 18%;
    padding-block: 4px;
    gap: 10px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: none;
    /* Origen de coordenadas: app.js mide los centros con `offsetLeft`. */
    position: relative;
    /* La barra de desplazamiento no pinta nada en un carril. */
    scrollbar-width: none;
  }
  .disc-grid::-webkit-scrollbar { display: none; }

  .disc-grid .disc-card {
    scroll-snap-align: none;
    transform: scale(var(--esc, 1));
    transform-origin: 50% 50%;
    will-change: transform;
    /* La escala se escribe en cada fotograma: una transicion la retrasaria. */
    transition-property: border-color, background-color !important;
    transition-duration: .16s !important;
  }

  /* El nombre, centrado, y encendido con el color del album cuando esta centrada. */
  .disc-grid .disc-card-body { align-items: center; text-align: center; }
  .disc-grid .disc-card-body strong { transition: color .3s var(--ease-soft); }
  .disc-grid .disc-card-body small { justify-content: center; }

  /* Dentro del carril TODAS las tarjetas miden lo mismo. La casa marca el disco
     destacado con is-activa, y ese estilo le cambia la caja: medido, la primera
     tarjeta media 159 px de maqueta frente a los 232 de las demas, asi que su centro
     caia 36 px a la izquierda del centro del carril y nunca quedaba centrada. En el
     carril los siete discos son iguales: el color del album ya lo lleva el borde de la
     tarjeta centrada. */
  /* LA REJILLA CONSERVABA SUS COLUMNAS EXPLICITAS. La casa define .disc-grid como
     rejilla de DOS columnas, y grid-auto-columns solo manda en las columnas
     AUTOMATICAS: las dos primeras tarjetas caian en las columnas explicitas y salian
     mas estrechas (medido: 159 px frente a los 232 de las demas), asi que la primera
     nunca quedaba centrada. Es el MISMO fallo que ya aparecio en el carril de la
     seleccion. Se quitan las columnas explicitas. */
  .disc-grid { grid-template-columns: none; }
  .disc-grid .disc-card,
  .disc-grid .disc-card.is-activa { width: 100%; }

  .disc-grid .disc-card.is-centrada { border-color: var(--accent); }
  .disc-grid .disc-card.is-centrada .disc-card-body strong { color: var(--accent); }

  /* El anillo, con el mismo latido lento que el carril de la seleccion. */
  .disc-grid .disc-card.is-centrada::after {
    content: "";
    position: absolute; inset: 0;
    border-radius: inherit;
    border: 1px solid var(--accent);
    pointer-events: none;
    opacity: .14;
    animation: kwLatidoTarjeta 4.5s ease-in-out infinite;
  }
  @media (prefers-reduced-motion: reduce) {
    .disc-grid .disc-card.is-centrada::after { animation: none; opacity: .26; }
  }
}


/* ==========================================================================
   MENOS HUECO, DESVANECIDO Y ARRANQUE EN LA SEGUNDA (fase 28)

   1. MENOS HUECO. No es solo el `gap`: con la tarjeta del centro a 232 y las de los
      lados encogidas al 0,78, entre el borde de la centrada y el de su vecina quedaban
      unos 36 px de aire. El `gap` baja de 10 a 4 y la escala de los lados sube de 0,78
      a 0,84 (el 0,16 de la formula esta en app.js): el aire queda en unos 23 px.

   2. LAS DE LOS LADOS SE DESVANECEN. La casa bloquea la opacidad de las tarjetas con
      `.has-js .beat-card { opacity: 1 !important }`, asi que hay que ganarle con mas
      peso: entre dos `!important` gana el selector mas especifico, y este lleva dos
      clases y un `:is()` de dos clases mas.

   3. El arranque en la segunda tarjeta lo hace app.js al montar.
   ========================================================================== */
@media (max-width: 899px) {
  .beat-grid.picks,
  .related .beat-grid,
  .disc-grid { gap: 4px; }

  .beat-grid.picks .beat-card,
  .related .beat-grid .beat-card,
  .disc-grid .disc-card { opacity: .72 !important; }

  .beat-grid.picks .beat-card.is-centrada,
  .related .beat-grid .beat-card.is-centrada,
  .disc-grid .disc-card.is-centrada { opacity: 1 !important; }

  /* En los carriles de pistas la clase de la centrada se sigue llamando is-activa. */
  .beat-grid.picks .beat-card.is-activa,
  .related .beat-grid .beat-card.is-activa { opacity: 1 !important; }
}


/* ==========================================================================
   SOLO LAS TARJETAS CERCA DE LA VISTA CARGAN CAPA (fase 32)

   El carril marcaba `will-change: transform` en las SIETE tarjetas a la vez: siete capas
   de 232x490 multiplicadas por la densidad de pantalla del telefono. En un aparato de
   verdad eso pesa, y las que estan fuera de la vista no necesitan capa ninguna.

   app.js marca `is-cerca` solo a las que estan dentro del carril o a un margen corto, y
   a esas se les escribe la escala. Las de fuera no se tocan.
   ========================================================================== */
@media (max-width: 899px) {
  .beat-grid.picks .beat-card.is-cerca,
  .related .beat-grid .beat-card.is-cerca,
  .disc-grid .disc-card.is-cerca { will-change: transform; }
}


/* ==========================================================================
   FILAS DE LISTA UNIFORMES (fase 33)

   Khris: «el tamaño de las tarjetas en la lista no es adecuado, el texto las expande» y
   «al hacer play se agrandan».

   MEDIDO: con titulo de una linea la fila mide 109 px; con dos, 120; la mas alta llega a
   147. Son 38 px de diferencia entre la mas baja y la mas alta, y la lista sale
   deshilachada. Al reproducir se suma la clase `is-playing` y la fila vuelve a crecer
   (109 -> 120, medido).

   Se reserva el alto de DOS LINEAS de titulo en todas las filas, calculado en `em` para
   que escale con la letra que haya puesto el usuario, y los chips se quedan en UNA linea
   sin envolverse. Asi todas las filas miden lo mismo, crecen juntas si el usuario
   agranda la letra, y el estado de reproduccion ya no cambia el tamaño.
   ========================================================================== */
@media (max-width: 899px) {
  /* Dos lineas de titulo reservadas: 1,15 de interlinea x 2. El numero sale de la
     medida real (una linea 19 px, dos 37 px con la letra por defecto). */
  /* Con el id: el catalogo define sus reglas de lista con #catalog ..., y esas
     pesan mas que cualquier selector de clases. */
  #catalog.view-list .beat-card-title {
    min-height: 2.3em;
    display: flex;
    align-items: center;
  }

  /* Los chips, en una sola linea: antes se envolvian y estiraban la fila. */
  #catalog.view-list .chips {
    flex-wrap: nowrap;
    overflow: hidden;
    min-height: 1.6em;
  }

  /* Y la fila no cambia de alto al reproducir. */
  #catalog.view-list .beat-card.is-playing { min-height: 0; }
}

/* ==========================================================================
   EL «COMPRAR» DE LA LISTA, AL SUELO (fase 33b)

   La auditoria del catalogo midio el boton de compra de las filas a 10,24 px: el texto
   mas pequeño de todo el sitio, por debajo del suelo de 11,2 que fijamos. Dentro de un
   boton de 96x44 la palabra queda diminuta.
   ========================================================================== */
@media (max-width: 899px) {
  #catalog.view-list .beat-card-actions .btn,
  #catalog.view-list .js-add,
  #catalog .beat-card-actions .btn { font-size: .7rem; }
}


/* ==========================================================================
   LA FILA DEL CATALOGO: MAS PEQUEÑA, CENTRADA Y CON EL RESALTE PAREJO (fase 35)

   Khris: «las tarjetas deben ser mas pequeñas, y la caratula junto con el boton de play
   deben estar centrados; al desplazarse, primero se mueve la linea del costado izquierdo
   y despues el sombreado, deben ir parejos; tambien sombrearse el nombre del beat y
   agrandarse un poco la portada, como en el carrusel; el boton de play debe ser mas
   visible».

   MEDIDO antes (390, vista de lista): fila de 121 px con la portada 11 px por encima del
   centro y el boton 15 px a la derecha del centro de la portada; el boton con fondo
   transparente y un icono de 18 px; la transicion de la fila SIN el `box-shadow` —que es
   la linea de acento—, por eso la linea entraba de golpe y el fondo llegaba 0,16 s
   despues; y el nombre y la portada iguales en reposo y en el centro.
   ========================================================================== */
@media (max-width: 899px) {

  /* ---------- 1. Mas pequeña: una linea de titulo, con puntos suspensivos -------- */
  /* La reserva de dos lineas era para que todas las filas midieran lo mismo. Una sola
     linea, cortada con puntos suspensivos, consigue lo mismo y ocupa la mitad. El
     titulo completo se lee en la ficha del beat. */
  #catalog.view-list .beat-card-title {
    min-height: 0;
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  #catalog.view-list .beat-card-title a {
    display: block;
    max-width: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* La portada baja de 78 a 66 px: con el titulo en una linea, era ella la que mandaba
     en el alto de la fila. */
  #catalog.view-list .beat-card { padding: 8px; grid-template-columns: 4.125rem minmax(0, 1fr) auto; }
  #catalog.view-list .beat-card-media,
  #catalog.view-list .beat-card img { width: 4.125rem; height: 4.125rem; }
  #catalog.view-list .beat-card-media { align-self: center; }
  #catalog.view-list .beat-card-body { gap: 2px; }
  #catalog.view-list .chips { min-height: 0; }

  /* ---------- 2. La portada y el boton, centrados -------------------------------- */
  /* La portada se centra en su columna... */
  /* Centrar TODAS las piezas de la fila: el lign-self suelto de la portada no entraba
     (algo mas especifico lo fijaba), y con lign-items en la rejilla se centran de una
     vez la portada, el boton y el bloque de texto. */
  #catalog.view-list .beat-card { align-items: center; }
  /* La fila mide 105 px pero su contenido solo 89: hay 18 px de mas que no vienen de
     ninguna pieza visible, y por eso la portada quedaba 10 px alta con lign-self y con
     lign-items. Los margenes automaticos SI centran dentro de la celda, sea cual sea
     el alto que sobre. */
  #catalog.view-list .beat-card img { margin-block: auto; }
  #catalog.view-list .beat-card-body,
  #catalog.view-list .beat-card-actions { margin-block: auto; }
  #catalog.view-list .beat-card-body { align-self: center; }
  #catalog.view-list .beat-card-actions { align-self: center; }
  /* ...y el boton se coloca en LA MISMA CELDA que la portada y se centra ahi: asi
     coinciden por construccion, sin cuentas de pixeles que se rompan al cambiar el
     relleno. */
  #catalog.view-list .play-btn {
    position: static;
    grid-column: 1;
    grid-row: 1;
    place-self: center;
    z-index: 2;
  }

  /* ---------- 3. La linea y el sombreado, parejos -------------------------------- */
  /* El `box-shadow` es la linea de acento: sin el en la transicion entraba de golpe
     mientras el fondo llegaba despues. Ahora los dos duran lo mismo. */
  #catalog.view-list .beat-card {
    transition: transform .12s var(--ease-soft), background-color .16s var(--ease-soft),
                border-color .16s var(--ease-soft), box-shadow .16s var(--ease-soft),
                opacity .18s var(--ease-soft);
  }

  /* ---------- 4. El nombre se enciende con el color de su album ------------------ */
  #catalog.view-list .beat-card-title { transition: color .16s var(--ease-soft); }
  #catalog.view-list .beat-card.is-centro .beat-card-title { color: var(--accent); }

  /* ---------- 5. La portada crece un poco al centrarse -------------------------- */
  #catalog.view-list .beat-card img { transition: transform .28s var(--ease-soft); }
  #catalog.view-list .beat-card.is-centro img { transform: scale(1.06); }

  /* ---------- 6. El boton de reproducir, que se vea ----------------------------- */
  #catalog.view-list .play-btn {
    background: rgba(5, 4, 3, .66);
    border-color: rgba(241, 234, 221, .42);
    color: var(--text);
    box-shadow: 0 1px 6px rgba(0, 0, 0, .5);
  }
  #catalog.view-list .play-btn svg { width: 20px; height: 20px; }
  /* Y cuando la fila esta en el centro, el filo del color de su album. */
  #catalog.view-list .beat-card.is-centro .play-btn {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-blood);
  }
}

/* ========================================================================== 
   CIERRE DEL CATALOGO MOVIL: DOS FILAS UTILES EN VEZ DE TRES (fase 36)

   A 390 px la cabecera de filtros media 207 px: buscador, chips y recuento
   ocupaban tres filas, ademas del relleno heredado de escritorio. El buscador
   y «Filtros» caben juntos; los chips y el recuento tambien. Se conserva cada
   control y se gana casi una fila completa antes del primer beat.
   ========================================================================== */
@media (max-width: 899px) {
  .filters { padding-block: 0; margin-bottom: 10px; }
  .filters-inner {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "search actions"
      "chips  results";
    gap: 8px 10px;
    padding: 8px 0;
  }
  .filters-inner .results { justify-self: end; white-space: nowrap; }

  /* Las dos etiquetas eran las únicas piezas de página por debajo del suelo
     móvil de 11,2 px. */
  .disc-nav-link span,
  .track-row .track-specs { font-size: .7rem; }

  /* Los paneles también son parte del producto: texto legible y controles que
     alcanzan los 44 px cómodos para el dedo. */
  :is(.cart-lic-kicker, .cart-field > span, .cart-lic-hint, .drawer-total,
      .cart-item-info span, .cart-item-remove, .tool-tab, .pane-title,
      .notes-count, .notes-saved, .notes-strip-meta, .notes-tool) {
    font-size: .7rem;
  }
  .drawer-close,
  .notes-close,
  .notes-strip .notes-transport button,
  .mix-play {
    width: 44px;
    height: 44px;
    min-width: 44px;
    min-height: 44px;
  }
  .cart-field input,
  .tool-tab,
  .notes-tool { min-height: 44px; }

  /* ---------- El cajón del carrito se lee como un solo documento --------- */
  /* Medido el 2026-10-04 en 390x844: el pie (datos de licencia + notas +
     subtotal + los dos botones) se quedaba 696 px de los 844 del cajón, así
     que la lista de artículos recibía 74 px para 196 px de contenido y la
     línea del carrito salía CORTADA a media tarjeta: no se veían ni la
     cantidad, ni el precio unitario, ni «Quitar». Ahora se desplaza el cajón
     entero —primero lo que compras, después tus datos y el pago— y la
     cabecera se queda pegada arriba con el botón de cerrar a mano.
     Va en movil.css a propósito: en escritorio el pie cabe y este cambio no
     se aplica (el cuerpo mide 211 px ahí). */
  #cart-drawer { overflow-y: auto; }
  #cart-drawer .drawer-body { flex: 0 0 auto; overflow: visible; }
  #cart-drawer .drawer-head {
    position: sticky; top: 0; z-index: 2;
    background: var(--bg-deep);
  }

  .brand { min-height: 44px; display: inline-flex; align-items: center; }
  .breadcrumb a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 2px;
  }

  /* El pie conserva toda la información legal, con menos aire muerto en las
     páginas cortas. Sus enlaces mantienen una zona táctil de 44 px. */
  .site-footer { margin-top: 24px; padding: 32px 0 20px; }
  .footer-grid { gap: 22px; }
  .site-footer :is(h2, h3) { margin-bottom: 8px; }
  .site-footer li { margin-bottom: 2px; }
  .site-footer li a,
  .site-footer p a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding-block: 0;
  }
  .footer-bottom { margin-top: 24px; padding-top: 16px; }
}

/* ==========================================================================
   EL BOTON DE COMPRAR LLEGABA TARDE (fase 36)

   Khris: «el color del boton de comprar tambien llega despues que el sombreado».

   Es el mismo fallo que la linea del costado, con otra pieza: el boton tiene su propia
   transicion de 0,34 s (la de los botones del sitio) mientras el sombreado de la fila
   entra en 0,16 s, asi que el color del boton llegaba 0,18 s despues que el resto del
   resalte. Aqui se le pone la MISMA duracion que al sombreado.
   ========================================================================== */
@media (max-width: 899px) {
  /* Y el boton de reproducir tenia el mismo problema, con 0,34 s: su color tambien
     cambia con el resalte, asi que entra en la misma duracion. (Se comprobo midiendo:
     la sonda de duraciones lo delato.) */
  #catalog.view-list .beat-card .play-btn {
    transition: background-color .16s var(--ease-soft), border-color .16s var(--ease-soft),
                color .16s var(--ease-soft), box-shadow .16s var(--ease-soft),
                opacity .16s var(--ease-soft), transform .16s var(--ease-soft);
  }

  #catalog.view-list .beat-card-actions .btn,
  #catalog.view-list .beat-card-actions .js-add {
    transition: background-color .16s var(--ease-soft), border-color .16s var(--ease-soft),
                color .16s var(--ease-soft), box-shadow .16s var(--ease-soft),
                transform .12s var(--ease-soft);
  }
}


/* ==========================================================================
   LA PORTADA, CENTRADA DE VERDAD, Y LOS NOMBRES QUE NO SE COMEN (fase 37)

   1. EL CENTRADO. Medido: yo centraba la `img`, pero quien estaba descolocado es su
      ENVOLTORIO, `a.beat-card-media` (78x78 en y=9..87 con `align-self: start`) dentro de
      una caja de contenido de 103 px. La `img` ya estaba bien DENTRO de su envoltorio; el
      envoltorio era el que estaba arriba. Por eso `align-self`, `align-items` y los
      margenes automaticos sobre la `img` no movian nada.
      Se centra el envoltorio en la fila y la portada dentro del envoltorio.

   2. LOS NOMBRES. Medido: la caja del titulo mide 108 px y el texto necesita 114, y NO
      CABE NINGUNO de los 42 —ni «Fugitivo», 62 px en una caja de 59—. La causa: el titulo
      vive en un contenedor flex que lo encoge en vez de darle el ancho que sobra.
      Se le da el ancho (flex: 1 1 auto + min-width: 0) y los puntos suspensivos por
      CARACTERES se ponen en app.js (20 caracteres), con el corte por ancho como red.
   ========================================================================== */
@media (max-width: 899px) {
  /* ---------- La portada centrada ------------------------------------------ */
  /* Las filas de la rejilla estaban FIJADAS en 78 px mientras la caja de contenido mide
     82: la rejilla no llenaba la fila y quedaban 4 px abajo, que es justo lo que faltaba
     para centrar. Con la primera fila elastica, la rejilla llena la caja. */
  /* La segunda fila era de 0 px, pero el `row-gap` seguía contando 8 px. Eso
     encogía la fila útil y dejaba la portada exactamente 4 px por encima del
     centro. Una sola fila llena toda la caja y elimina ese último desfase. */
  #catalog.view-list .beat-card { grid-template-rows: 1fr; }
  #catalog.view-list .beat-card a.beat-card-media {
    align-self: center;          /* el envoltorio, en la fila */
    display: grid;
    place-items: center;         /* y la portada, dentro del envoltorio */
    width: 4.125rem;
    height: 4.125rem;
  }
  #catalog.view-list .beat-card a.beat-card-media img { width: 100%; height: 100%; }

  /* ---------- El titulo, con el ancho que sobra ---------------------------- */
  #catalog.view-list .beat-card-body { min-width: 0; }
  #catalog.view-list .beat-card-title { flex: 1 1 auto; min-width: 0; max-width: 100%; }
  #catalog.view-list .beat-card-album,
  #catalog.view-list .chips { min-width: 0; max-width: 100%; }
}

/* ========================================================================== 
   ENLACES PEQUENOS CON ZONA DE DEDO COMPLETA (fase 38)

   Los textos se leian, pero diecinueve enlaces utiles seguian midiendo entre
   15 y 23 px de alto. La caja tactil crece a 44 px sin agrandar la letra ni
   cambiar el aspecto de las tarjetas.
   ========================================================================== */
@media (max-width: 899px) {
  .beat-grid:not(#catalog) .beat-card-title a,
  .track-row .track-title,
  .license-foot a,
  .legal-text a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .cart-accept a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding-inline: 4px;
  }

  /* Metadatos sobre superficie: el tono secundario global queda apenas por
     debajo de AA en estas tres piezas. Aquí se usa el secundario claro. */
  .track-row .track-specs,
  .track-row .track-time,
  .track-row .track-price small { color: var(--muted); }

  /* El acento cambia con cada álbum y algunos tonos son demasiado oscuros para
     texto. El rojo claro de la interfaz conserva la señal activa y supera AA. */
  .beat-grid.picks .beat-card.is-activa .beat-card-title,
  .related .beat-grid .beat-card.is-activa .beat-card-title,
  #catalog.view-list .beat-card.is-centro .beat-card-title {
    color: var(--blood-text);
  }
}

/* Talentos: lectura directa y controles cómodos en pantallas pequeñas. */
@media (max-width: 899px) {
  .talent-group-head {
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 6px 10px;
    padding-bottom: 12px;
    margin-bottom: 14px;
  }
  .talent-group-head h2 { min-width: 0; }
  .talent-cards { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .talent-card { width: 100%; padding: 19px 18px 18px; }
  .talent-card h3 { font-size: 1.12rem; line-height: 1.3; }
  .talent-card > p { font-size: .9rem; line-height: 1.65; margin-bottom: 16px; }
  .talent-card .btn {
    align-self: stretch;
    justify-content: center;
    width: 100%;
    min-height: 48px;
    margin-top: 2px;
  }

  .talent-detail-hero { padding-top: 34px; }
  .talent-detail-path { gap: 7px; margin-bottom: 23px; font-size: .78rem; }
  .talent-detail-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .talent-detail-block { padding: 20px 18px; }
  .talent-detail-block h2 { margin-bottom: 9px; font-size: 1rem; }
  .talent-detail-block p { font-size: .92rem; line-height: 1.7; }
  .talent-detail-actions { align-items: stretch; flex-direction: column; gap: 10px; margin-top: 18px; }
  .talent-detail-actions .btn { justify-content: center; width: 100%; min-height: 48px; }
}

/* Ajustes finales para las fichas de beat y las acciones en móvil. */
@media (max-width: 899px) {
  /* Mantiene el último lanzamiento centrado y reduce su área visual un 20 %. */
  .hero-release { width: 80%; max-width: 420px; margin-inline: auto; }

  /* En móvil, el salto entre discos mantiene ambas direcciones en una fila. */
  .disc-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .disc-nav-link { min-width: 0; padding-inline: 12px; }

  /* La ficha de beat ofrece las dos direcciones en una misma fila. */
  .beat-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .beat-nav-link { min-width: 0; }

  /* El enlace se puede copiar con un toque cómodo y el estado queda legible. */
  .beat-page-extra { align-items: stretch; flex-direction: column; gap: 8px; }
  #share-btn { width: 100%; min-height: 48px; justify-content: center; }
  #share-note { min-height: 1.25em; text-align: center; }

  /* Aumenta iconos SVG de la interfaz sin tocar arte ni el reproductor. */
  .mobile-ui-icon-upscale { scale: 1.15; transform-origin: center; }
}


/* Mesa de composición: ajustes finos en pantallas pequeñas. Se usa la id del
   panel para ganar a las reglas generales de móvil que vienen antes. */
@media (max-width: 899px) {
  #notes-panel .notes-top {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "title close" "context context";
    gap: 8px 12px;
    padding: 12px 14px 10px;
  }
  #notes-panel .notes-title { grid-area: title; }
  #notes-panel .notes-top .drawer-close { grid-area: close; position: static; }
  #notes-panel .notes-context { grid-area: context; max-width: none; }
  #notes-panel .notes-strip { width: 100%; }
  #notes-panel .tool-tabs { padding: 6px 14px 0; gap: 2px; overflow-x: auto; }
  #notes-panel .tool-tab { padding: 9px 10px 11px; font-size: .62rem; gap: 5px; }
  #notes-panel .notes-body { display: block; padding: 12px 14px 14px; }
  #notes-panel .notes-side { display: none; }
  #notes-panel .editor-bar { flex-direction: column; align-items: stretch; gap: 8px; }
  #notes-panel .section-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  #notes-panel .section-chips::-webkit-scrollbar { display: none; }
  #notes-panel .section-chip { flex: 0 0 auto; }
  #notes-panel .editor-actions { margin-left: 0; justify-content: space-between; }
  #notes-panel .editor-actions .notes-tool { flex: 1; justify-content: center; }
  #notes-panel .notes-text { padding: 14px; }
  #notes-panel .notes-foot { padding: 8px 0 0; }
  #notes-panel .tool-pane .pane-scroll { padding: 12px; }
}


/* Etiquetas de secciones/acciones en la mesa de composición móvil. */
@media (max-width: 899px) {
  #notes-panel .editor-bar { align-items: stretch; }
  #notes-panel .editor-block-actions { margin-left: 0; align-items: stretch; }
  #notes-panel .editor-actions { justify-content: space-between; }
  #notes-panel .editor-label { margin-bottom: 1px; }
}


/* Carrito: el cajón no scrollea entero; scrollea su cuerpo y el pie queda fijo. */
@media (max-width: 899px) {
  #cart-drawer.cart-drawer { overflow: hidden; }
  #cart-drawer .drawer-scroll { padding: 14px; }
  #cart-drawer .drawer-head {
    position: sticky; top: 0; z-index: 3;
    background: var(--bg-deep);
  }
  #cart-drawer #cart-items { flex: 0 0 auto; overflow: visible; }
  #cart-drawer .drawer-foot {
    padding: 14px 14px calc(14px + env(safe-area-inset-bottom, 0px));
  }
  #cart-drawer .cart-item { padding: 10px; gap: 10px; }
  #cart-drawer .cart-item img { width: 56px; height: 56px; }
}
