/*
 * Lyra web — la misma identidad visual que la app Android.
 *
 * Los colores no son aproximaciones: salen de `core/ui/theme/Theme.kt`, uno a uno. Que la web y
 * la app se vean iguales importa porque son el mismo producto para la misma persona, y una
 * diferencia de tono se lee como "esto es otra cosa".
 *
 * Regla heredada de la app: el morado se reserva para lo ACCIONABLE — botones, lo que suena,
 * lo seleccionado. Los fondos son grises muy oscuros con una pizca de violeta. Cuando todo es
 * morado, nada destaca.
 */
:root {
    --background: #0B0910;
    --surface: #15121C;
    --surface-variant: #1F1A2B;
    --surface-elevated: #272235;

    --primary: #8B5CF6;
    --primary-bright: #9F7AEA;
    --secondary: #B79CFF;

    --on-background: #F4F1FA;
    --on-surface-variant: #A9A0BF;
    --error: #FF6B81;

    --bottom-player-height: 88px;
    /* Ancho del panel "En reproduccion" de la derecha, en escritorio. */
    --ancho-panel-derecho: 360px;
    --radius: 12px;
}

/*
 * Manrope, la tipografia de Lyrapp.
 *
 * # Por que una fuente propia
 * Antes se usaba la del sistema, asi que la pagina se veia distinta en cada sitio —Segoe UI en
 * Windows, San Francisco en un iPhone, Roboto en Android— y **no coincidia con la app**. Una
 * familia propia es lo que hace que las dos mitades se reconozcan como el mismo producto. Es lo
 * mismo que hace Spotify con su Spotify Mix.
 *
 * # Por que Manrope y no otra
 * Tiene el aire geometrico de la Circular que usa Spotify, pero con la letra algo mas estrecha y
 * abierta, que aguanta mejor en los tamanos pequenos donde vive casi todo el texto de un
 * reproductor: titulos de cancion, nombres de artista, duraciones. Y es libre (OFL), asi que se
 * puede servir sin pagar licencia.
 *
 * # Por que desde nuestro servidor
 * El fichero viaja dentro del jar, como el resto de la web. Enlazar a Google Fonts sumaria una
 * dependencia externa, una conexion mas antes de poder pintar, y le contaria a Google quien
 * visita la pagina.
 *
 * Es **variable**: un solo archivo de 24 KB cubre de peso 200 a 800. Con cortes sueltos harian
 * falta cuatro o cinco descargas.
 */
@font-face {
    font-family: 'Manrope';
    src: url('/fonts/manrope.woff2') format('woff2-variations'),
         url('/fonts/manrope.woff2') format('woff2');
    font-weight: 200 800;
    font-style: normal;
    /*
     * `swap`: el texto se pinta ya con la fuente del sistema y cambia a Manrope en cuanto llega.
     * Con el valor por defecto habria un parpadeo con el texto invisible, y en una conexion mala
     * la pagina pareceria vacia durante segundos.
     */
    font-display: swap;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    /*
     * Nada puede desplazar la pagina en horizontal.
     *
     * Los paneles de cola y letra descansan fuera del borde derecho para poder deslizarse hacia
     * dentro. En iOS Safari ese hueco se volvia area desplazable y la pagina entera se movia,
     * dejando los titulos cortados por la izquierda.
     */
    overflow-x: hidden;
    width: 100%;
    background: var(--background);
    color: var(--on-background);
    /* Manrope primero; detras, la pila del sistema por si el fichero no llegara. */
    font-family: 'Manrope', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    /* El reproductor va fijo abajo; sin esto la última fila de cada lista queda debajo. */
    overscroll-behavior: none;
}

button { font-family: inherit; cursor: pointer; border: 0; background: none; color: inherit; }
a { color: inherit; text-decoration: none; }
img { display: block; }

/* ---------------------------------------------------------------- disposición */

.app {
    display: grid;
    grid-template-columns: 240px 1fr;
    height: 100dvh;
}

.sidebar {
    background: var(--surface);
    padding: 20px 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    overflow-y: auto;
    padding-bottom: calc(var(--bottom-player-height) + 20px);
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 10px 18px;
    font-size: 20px;
    font-weight: 700;
}

.brand-mark {
    width: 34px; height: 34px;
    border-radius: 10px;
    background: linear-gradient(135deg, var(--primary), var(--secondary));
    display: grid; place-items: center;
    font-weight: 800; color: #fff;
}

.nav-item {
    display: flex; align-items: center; gap: 12px;
    padding: 11px 14px;
    border-radius: 999px;
    color: var(--on-surface-variant);
    font-size: 15px;
    width: 100%;
    text-align: left;
}
.nav-item:hover { background: var(--surface-variant); color: var(--on-background); }
.nav-item.active { background: var(--surface-variant); color: var(--secondary); font-weight: 600; }

.main {
    overflow-y: auto;
    padding: 24px 28px calc(var(--bottom-player-height) + 32px);
}

/* ---------------------------------------------------------------- búsqueda */

.search-bar {
    display: flex; align-items: center; gap: 10px;
    background: var(--surface);
    border: 1px solid transparent;
    border-radius: 999px;
    padding: 12px 18px;
    max-width: 560px;
    margin-bottom: 22px;
}
.search-bar:focus-within { border-color: var(--primary); background: var(--surface-variant); }
.search-bar input {
    flex: 1; background: none; border: 0; outline: none;
    color: var(--on-background); font-size: 15px;
}
.search-bar input::placeholder { color: var(--on-surface-variant); }
/* El navegador pinta una X propia en los `type=search`; con el botón al lado sobra. */
.search-bar input::-webkit-search-cancel-button { display: none; }
.search-bar button { flex-shrink: 0; padding: 7px 16px; font-size: 13px; }

/* Los filtros no llevan el número de resultados: al elegir "Álbumes" lo que importa es ver
   álbumes, no cuántos hay. Es la misma decisión que se tomó en la app. */
.chips { display: flex; gap: 8px; margin-bottom: 20px; flex-wrap: wrap; }
.chip {
    padding: 9px 18px;
    border-radius: 999px;
    background: var(--surface-variant);
    color: var(--on-surface-variant);
    font-size: 14px;
}
.chip.active { background: var(--primary); color: #fff; font-weight: 600; }

/* ---------------------------------------------------------------- listas */

h1 { font-size: 26px; margin: 0 0 6px; }
h2 { font-size: 19px; margin: 26px 0 12px; }
.subtitle { color: var(--on-surface-variant); font-size: 14px; margin: 0 0 18px; }

/*
 * Fila de cancion.
 *
 * Flexbox y no rejilla de columnas fijas. Con `grid-template-columns` habia que declarar un
 * numero exacto de columnas, pero la fila tiene un numero VARIABLE de hijos: el numero de pista
 * solo aparece en albumes, y album y duracion se ocultan en movil. El resultado era que los
 * botones caian en una columna distinta segun la fila, y en el telefono aparecian flotando a
 * media linea en posiciones diferentes.
 *
 * Con flex, cada elemento ocupa lo suyo y el titulo se come el espacio sobrante — que es
 * exactamente el comportamiento que se queria.
 */
.song-row {
    display: flex; align-items: center; gap: 12px;
    padding: 8px 12px;
    border-radius: var(--radius);
}
.song-meta { flex: 1; min-width: 0; cursor: pointer; }
.song-album {
    width: 24%; flex-shrink: 0;
    font-size: 13px; color: var(--on-surface-variant);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.song-time {
    width: 46px; flex-shrink: 0; text-align: right;
    font-size: 13px; color: var(--on-surface-variant);
    font-variant-numeric: tabular-nums;
}
.song-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }

/* El contenido no se estira sin fin: en un monitor ancho, una linea de 2000 px es incomoda de
   leer y deja la interfaz desangelada. */
.main > * { max-width: 1400px; }

.song-index {
    width: 26px; text-align: center;
    color: var(--on-surface-variant); font-size: 14px;
    flex-shrink: 0;
}
.art { width: 52px; height: 52px; border-radius: 8px; object-fit: cover; background: var(--surface-variant); flex-shrink: 0; }
.art.round { border-radius: 50%; }
.art.lg { width: 150px; height: 150px; border-radius: 10px; }

.song-meta { flex: 1; min-width: 0; }
.song-title, .song-sub {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.song-title { font-size: 15px; }
.song-sub { font-size: 13px; color: var(--on-surface-variant); margin-top: 2px; }

.icon-btn {
    width: 38px; height: 38px; border-radius: 50%;
    display: grid; place-items: center;
    color: var(--on-surface-variant);
    flex-shrink: 0;
}
.icon-btn:hover { background: var(--surface-variant); color: var(--on-background); }
.icon-btn.on { color: var(--primary); }

/* ---------------------------------------------------------------- rejillas */

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 18px;
}
.card { border-radius: var(--radius); padding: 8px; }
.card:hover { background: var(--surface); }
.card img { width: 100%; aspect-ratio: 1; border-radius: 10px; object-fit: cover; background: var(--surface-variant); }
.card .name { font-size: 14px; margin-top: 8px; font-weight: 600; }
.card .meta { font-size: 12px; color: var(--on-surface-variant); margin-top: 2px; }

.row-scroll { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 6px; }
.row-scroll .card { min-width: 150px; }

/* ---------------------------------------------------------------- cabecera de álbum */

.hero { display: flex; gap: 24px; align-items: flex-end; margin-bottom: 26px; flex-wrap: wrap; }
.hero img { width: 200px; height: 200px; border-radius: 12px; object-fit: cover; }
.hero h1 { font-size: 34px; }

.btn-play {
    background: var(--primary); color: #fff;
    padding: 12px 26px; border-radius: 999px;
    font-size: 15px; font-weight: 600;
    display: inline-flex; align-items: center; gap: 8px;
}
.btn-play:hover { background: var(--primary-bright); }

/* ---------------------------------------------------------------- reproductor */

.player {
    position: fixed; left: 0; right: 0; bottom: 0;
    height: var(--bottom-player-height);
    background: var(--surface);
    border-top: 1px solid rgba(255,255,255,.06);
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 16px;
    padding: 0 20px;
    /* El fondo toma el color de la portada, como en la app. Se anima al cambiar de canción. */
    transition: background 600ms ease;
}
.player.hidden { display: none; }

.player-song { display: flex; align-items: center; gap: 12px; min-width: 0; }

.player-controls { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 340px; }
.player-buttons { display: flex; align-items: center; gap: 14px; }

.btn-round {
    width: 42px; height: 42px; border-radius: 50%;
    background: var(--primary); color: #fff;
    display: grid; place-items: center;
}
.btn-round:hover { background: var(--primary-bright); }

/*
 * Barra de progreso fina, igual que en la app: 3 px en reposo y 5 al arrastrar. El área
 * sensible al ratón mide 20 px de alto, así que ser fina no la hace difícil de agarrar.
 */
.seek { width: 100%; display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--on-surface-variant); }
.seek-track {
    flex: 1; height: 20px; display: flex; align-items: center; cursor: pointer;
}
.seek-rail {
    width: 100%; height: 3px; border-radius: 999px;
    background: rgba(244,241,250,.22);
    position: relative;
    transition: height 120ms ease;
}
.seek-track:hover .seek-rail { height: 5px; }
.seek-fill { height: 100%; border-radius: 999px; background: var(--secondary); }
.seek-thumb {
    position: absolute; top: 50%; transform: translate(-50%, -50%);
    width: 10px; height: 10px; border-radius: 50%; background: #fff;
}

.player-right { display: flex; justify-content: flex-end; align-items: center; gap: 8px; }
.volume { width: 90px; accent-color: var(--primary); }

/* ---------------------------------------------------------------- varios */

.empty { color: var(--on-surface-variant); padding: 40px 0; text-align: center; }
.spinner {
    width: 26px; height: 26px; margin: 40px auto;
    border: 3px solid var(--surface-variant);
    border-top-color: var(--secondary);
    border-radius: 50%;
    animation: spin 800ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.toast {
    position: fixed; bottom: calc(var(--bottom-player-height) + 20px); left: 50%;
    transform: translateX(-50%);
    background: var(--surface-elevated); color: var(--on-background);
    padding: 12px 20px; border-radius: 999px; font-size: 14px;
    opacity: 0; pointer-events: none; transition: opacity 200ms ease;
}
.toast.show { opacity: 1; }

/* En móvil el menú lateral estorba: la navegación baja y el contenido ocupa todo el ancho. */
@media (max-width: 820px) {
    /*
     * El reproductor de abajo vuelve a UNA fila: caratula, titulo y play.
     *
     * Los controles completos viven ahora en la pantalla de reproduccion, asi que aqui no hace
     * falta amontonarlos. De 124 px se baja a 64: con la barra de navegacion, el cromo fijo pasa
     * de comerse 186 px de pantalla a 126.
     */
    :root { --bottom-player-height: 64px; }
    .app { grid-template-columns: 1fr; }
    .sidebar {
        position: fixed; bottom: 0; left: 0; right: 0;
        height: 62px; flex-direction: row; padding: 0; z-index: 20;
        justify-content: space-around; align-items: center;
        border-top: 1px solid rgba(255,255,255,.06);
        /*
         * Zona segura del iPhone. El `viewport-fit=cover` de la pagina hace que el contenido
         * llegue hasta el borde fisico, asi que sin esto la barra de navegacion queda por debajo
         * de la raya del indicador de inicio y sus botones son dificiles de pulsar.
         */
        height: calc(62px + env(safe-area-inset-bottom));
        padding-bottom: env(safe-area-inset-bottom);
        /*
         * Y `--tapado-abajo` sube la barra por encima de la de direcciones de Safari, que se
         * superpone al contenido en vez de empujarlo. Lo calcula `ajustarAPantallaVisible`
         * comparando el viewport de maquetacion con el visible; vale 0 en el resto de sitios.
         */
        bottom: var(--tapado-abajo, 0px);
    }
    .sidebar .brand,
    /* Las playlists y el pie no caben en una barra de 62 px: al dejarlos visibles se colaban
       dentro de la navegacion inferior y la partian. */
    .sidebar .side-section,
    .sidebar .sidebar-foot { display: none; }
    .nav-item { flex-direction: column; gap: 3px; font-size: 11px; padding: 6px; border-radius: 10px; }
    .main {
        padding: 16px 16px
                 calc(var(--bottom-player-height) + 80px + var(--tapado-abajo, 0px));
    }
    /* En movil no hay sitio para album ni duracion. */
    .song-album, .song-time { display: none; }
    .player {
        bottom: calc(62px + env(safe-area-inset-bottom) + var(--tapado-abajo, 0px));
    }
    .player-controls { min-width: 0; }
    .hero img { width: 140px; height: 140px; }
    .hero h1 { font-size: 24px; }
}

/*
 * Elementos que solo existen en el telefono: la pestana de biblioteca y el play del reproductor
 * pequeno. En escritorio estorban, porque alli las playlists ya se ven enteras en el menu
 * lateral y el play ya esta en la fila de controles.
 */
.solo-movil { display: none; }
@media (max-width: 820px) { .solo-movil { display: flex; } }

/* ---------------------------------------------------------------- iconos */

/*
 * Los iconos heredan el color del texto (`currentColor` en el SVG), asi que basta con cambiar
 * el color del contenedor para que el icono lo siga. Es lo que hace que un boton activo se
 * ponga morado sin duplicar ningun recurso.
 */
.ico { width: 22px; height: 22px; flex-shrink: 0; }
.ico.dim { color: var(--on-surface-variant); width: 18px; height: 18px; }
.nav-item .ico { width: 20px; height: 20px; }
.btn-round .ico { width: 20px; height: 20px; color: #fff; }
.icon-btn .ico { width: 20px; height: 20px; }

/* ---------------------------------------------------------------- tarjetas al estilo Spotify */

/*
 * La portada manda. Las tarjetas son casi todo imagen, con el boton de reproducir apareciendo
 * al pasar por encima — es el gesto que la gente ya conoce de Spotify y Deezer, y evita llenar
 * la rejilla de botones que compiten con las caratulas.
 */
.card { position: relative; transition: background 160ms ease; }
.card .cover { position: relative; }
.card .cover-play {
    position: absolute; right: 8px; bottom: 8px;
    width: 44px; height: 44px; border-radius: 50%;
    background: var(--primary); color: #fff;
    display: grid; place-items: center;
    opacity: 0; transform: translateY(8px);
    transition: opacity 160ms ease, transform 160ms ease;
    box-shadow: 0 8px 20px rgba(0,0,0,.45);
}
.card:hover .cover-play { opacity: 1; transform: translateY(0); }
.card .cover-play:hover { background: var(--primary-bright); }

/* En pantallas tactiles no hay "pasar por encima": el boton se queda siempre visible. */
@media (hover: none) {
    .card .cover-play { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------- cabecera de seccion */

.topbar {
    display: flex; align-items: center; gap: 14px;
    margin-bottom: 20px;
}
.btn-back {
    width: 36px; height: 36px; border-radius: 50%;
    background: rgba(0,0,0,.35); color: var(--on-background);
    display: grid; place-items: center; flex-shrink: 0;
}
.btn-back:hover { background: rgba(0,0,0,.55); }

/*
 * Cabecera de album y de artista con la portada de fondo desenfocada, como en Spotify y Deezer.
 * El degradado hacia el fondo de la app evita el corte duro con el contenido de abajo.
 */
.hero {
    position: relative;
    display: flex; gap: 24px; align-items: flex-end;
    padding: 28px; margin: -24px -28px 24px;
    overflow: hidden;
}
.hero-bg {
    position: absolute; inset: 0;
    background-size: cover; background-position: center;
    filter: blur(42px) saturate(1.5);
    transform: scale(1.25);
    opacity: .5;
}
.hero-veil {
    position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(11,9,16,.45), var(--background));
}
/*
 * Solo el contenido se eleva. La regla anterior era `.hero > *`, que con la misma
 * especificidad y estando despues en el fichero pisaba el `position: absolute` del fondo y del
 * velo: dejaban de superponerse y pasaban a ocupar sitio, descolocando la cabecera entera.
 */
.hero > img, .hero > div:not(.hero-bg):not(.hero-veil) { position: relative; z-index: 1; }
.hero img { width: 200px; height: 200px; border-radius: 8px; object-fit: cover;
            box-shadow: 0 18px 44px rgba(0,0,0,.55); }
.hero .kind { font-size: 12px; text-transform: uppercase; letter-spacing: .08em;
              color: var(--on-surface-variant); font-weight: 700; }
.hero h1 { font-size: 40px; line-height: 1.1; margin: 6px 0 10px; }

.hero-actions { display: flex; align-items: center; gap: 12px; margin-top: 18px; }
.btn-play .ico { width: 18px; height: 18px; }

@media (max-width: 820px) {
    .hero { flex-direction: column; align-items: flex-start; padding: 20px 16px; margin: -16px -16px 20px; }
    .hero img { width: 150px; height: 150px; }
    .hero h1 { font-size: 26px; }
}

/* ---------------------------------------------------------------- entrada */

.gate {
    position: fixed; inset: 0; z-index: 50;
    display: grid; place-items: center;
    background: radial-gradient(1200px 600px at 50% -10%, #221a33, var(--background));
}
.gate[hidden] { display: none; }
.gate-card { text-align: center; padding: 32px; max-width: 380px; }
.gate-card h1 { font-size: 34px; margin: 18px 0 6px; }
.gate-card p { color: var(--on-surface-variant); font-size: 15px; margin: 0 0 26px; }
.brand-mark.big {
    width: 72px; height: 72px; border-radius: 20px; font-size: 34px; margin: 0 auto;
}
.gate-note { font-size: 12px; margin-top: 18px; }
#google-btn { display: flex; justify-content: center; margin-bottom: 12px; }

.sidebar-foot { margin-top: auto; padding-top: 12px; }
.who {
    font-size: 12px; color: var(--on-surface-variant);
    padding: 0 14px 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 820px) { .sidebar-foot { display: none; } }

/* ---------------------------------------------------------------- escritorio */

/*
 * Disposición de Spotify y Deezer: menú lateral fijo, barra superior con el buscador siempre a
 * mano, contenido que hace scroll por su cuenta y reproductor de ancho completo abajo.
 *
 * La diferencia con lo que había antes: el buscador vivía DENTRO del contenido, así que
 * desaparecía al entrar en un álbum y había que volver atrás para buscar otra cosa. Sacarlo a
 * la barra superior es lo que convierte esto en una app de escritorio y no en una sucesión de
 * páginas.
 */
.content {
    display: grid;
    grid-template-rows: auto 1fr;
    min-height: 0;   /* sin esto, el hijo con scroll desborda la rejilla */
    overflow: hidden;
}

.topnav {
    display: flex; align-items: center; gap: 14px;
    padding: 14px 28px;
    background: linear-gradient(180deg, rgba(11,9,16,.96), rgba(11,9,16,.75));
    backdrop-filter: blur(12px);
    position: sticky; top: 0; z-index: 10;
}
.search-bar.compact { margin: 0; padding: 9px 16px; max-width: 420px; flex: 1; }

.avatar {
    width: 34px; height: 34px; border-radius: 50%;
    background: linear-gradient(135deg, var(--primary), var(--secondary));
    display: grid; place-items: center;
    font-size: 13px; font-weight: 700; color: #fff;
    flex-shrink: 0; cursor: pointer;
}

.logo { width: 34px; height: 34px; }
.logo.big { width: 88px; height: 88px; margin: 0 auto; }

/* Playlists en el menú lateral */
.side-section { margin-top: 18px; display: flex; flex-direction: column; min-height: 0; }
.side-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0 14px 8px;
    font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
    color: var(--on-surface-variant); font-weight: 700;
}
.icon-btn.small { width: 26px; height: 26px; font-size: 18px; line-height: 1; }
.side-list { overflow-y: auto; }
.side-list button {
    display: block; width: 100%; text-align: left;
    padding: 8px 14px; border-radius: 8px;
    color: var(--on-surface-variant); font-size: 14px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.side-list button:hover { background: var(--surface-variant); color: var(--on-background); }
.side-list button.active { color: var(--secondary); }

/* Saludo de la portada, como el "Buenas tardes" de Spotify */
.greeting { font-size: 30px; margin: 6px 0 22px; }

/* Rejilla de accesos rápidos de la portada */
.quick-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 12px; margin-bottom: 32px;
}
.quick {
    display: flex; align-items: center; gap: 14px;
    background: var(--surface-variant); border-radius: 8px;
    overflow: hidden; height: 72px;
    transition: background 160ms ease;
}
.quick:hover { background: var(--surface-elevated); }
.quick img { width: 72px; height: 72px; object-fit: cover; }
.quick .name { font-weight: 700; font-size: 15px; padding-right: 12px; }

@media (max-width: 820px) {
    .topnav { padding: 10px 16px; }
    .greeting { font-size: 22px; }

    /*
     * El avatar es la UNICA puerta a la cuenta en un movil.
     *
     * Estaba oculto aqui, y como la barra lateral tampoco se enseña —su pie es donde viven el
     * correo y «Salir»—, desde el telefono no habia forma de llegar a Ajustes ni de cerrar
     * sesion: la pestaña inferior solo lleva a Inicio, Buscar, Favoritos y Biblioteca. Se ve algo
     * mas pequeño que en el ordenador para no comerle sitio al buscador.
     */
    .avatar { width: 30px; height: 30px; font-size: 12px; }

    /* Pegado al borde, que en una pantalla estrecha 24px de margen son muchos. */
    .menu { right: 12px; left: auto; top: 56px; min-width: 200px; }
}

/*
 * Marco para las caratulas.
 *
 * Una cancion puede no tener imagen —las guardadas antes de que se sincronizara la miniatura,
 * por ejemplo— y un `<img>` sin `src` valido deja un hueco muerto. Con un fondo y una nota
 * musical detras, el sitio se entiende aunque la imagen no llegue.
 */
.art, .card img, .quick img, .hero img {
    background: var(--surface-variant)
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%23A9A0BF' fill-opacity='.35' d='M12 3v10.6A4 4 0 1 0 14 17V7h4V3z'/></svg>")
        center / 42% no-repeat;
}

/* Formulario de la pantalla de entrada */
.gate-form { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.gate-form input {
    padding: 13px 18px; border-radius: 999px; border: 1px solid transparent;
    background: var(--surface-variant); color: var(--on-background); font-size: 15px;
    font-family: inherit;
}
.gate-form input:focus { outline: none; border-color: var(--primary); }
.btn-play.wide { width: 100%; justify-content: center; }
.gate-error { color: var(--error); font-size: 13px; min-height: 18px; margin: 0 0 6px; }
.gate-switch {
    color: var(--secondary); font-size: 14px; padding: 8px;
    text-decoration: underline; text-underline-offset: 3px;
}

/* ---------------------------------------------------------------- paneles laterales */

/*
 * Cola y letra comparten comportamiento: se deslizan desde la derecha y NO tapan el reproductor
 * —terminan justo encima—, para que se pueda seguir controlando la música con el panel abierto.
 * En Spotify pasa lo mismo y es lo que evita tener que cerrarlo para pausar.
 */
.side-panel {
    position: fixed; right: 0; top: 0; bottom: var(--bottom-player-height);
    width: 360px; max-width: 92vw;
    background: var(--surface);
    border-left: 1px solid rgba(255,255,255,.06);
    padding: 18px 14px; overflow-y: auto; z-index: 15;
    transform: translateX(105%);
    transition: transform 240ms cubic-bezier(.2,.7,.3,1);
}
.side-panel.open { transform: translateX(0); }
.panel-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 14px;
}
.panel-head h2 { margin: 0; font-size: 17px; }

/* Letra: el verso que suena en morado y grande, los demás apagados. Igual que en la app. */
.lyric-line {
    padding: 7px 6px; font-size: 16px; line-height: 1.45;
    color: var(--on-surface-variant);
    transition: color 200ms ease, font-size 200ms ease;
    cursor: pointer; border-radius: 8px;
}
.lyric-line:hover { background: var(--surface-variant); }
.lyric-line.active {
    color: var(--secondary); font-size: 19px; font-weight: 700;
}
.lyric-line.plain { cursor: default; }
.lyric-line.plain:hover { background: none; }

/* Cola: la canción actual marcada, las siguientes debajo. */
.queue-current { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
                 color: var(--on-surface-variant); font-weight: 700; margin: 6px 0 8px; }

/* ---------------------------------------------------------------- menú de cuenta */

.menu {
    position: fixed; top: 60px; right: 24px; z-index: 40;
    background: var(--surface-elevated);
    border-radius: 10px; padding: 6px;
    min-width: 210px;
    box-shadow: 0 16px 40px rgba(0,0,0,.5);
}
.menu[hidden] { display: none; }
.menu-head {
    padding: 10px 12px 12px; font-size: 13px; color: var(--on-surface-variant);
    border-bottom: 1px solid rgba(255,255,255,.07); margin-bottom: 6px;
    overflow: hidden; text-overflow: ellipsis;
}
.menu-item {
    display: flex; align-items: center; gap: 12px;
    width: 100%; padding: 10px 12px; border-radius: 6px;
    font-size: 14px; text-align: left;
}
.menu-item:hover { background: var(--surface-variant); }

/* ---------------------------------------------------------------- ajustes */

.setting {
    display: flex; align-items: center; justify-content: space-between;
    gap: 20px; padding: 16px 0;
    border-bottom: 1px solid rgba(255,255,255,.06);
}
.setting-label { font-size: 15px; }
.setting-help { font-size: 13px; color: var(--on-surface-variant); margin-top: 3px; }

/* Interruptor: nativo pero con los colores de Lyra. */
.switch { width: 46px; height: 26px; appearance: none; border-radius: 999px;
          background: var(--surface-elevated); position: relative; cursor: pointer;
          transition: background 160ms ease; flex-shrink: 0; }
.switch:checked { background: var(--primary); }
.switch::after {
    content: ''; position: absolute; top: 3px; left: 3px;
    width: 20px; height: 20px; border-radius: 50%; background: #fff;
    transition: transform 160ms ease;
}
.switch:checked::after { transform: translateX(20px); }

@media (max-width: 820px) {
    .menu { right: 12px; left: 12px; top: 56px; }
    /* En móvil no caben siete botones: se ocultan los secundarios y quedan los tres de siempre. */
    #btn-shuffle, #btn-repeat { display: none; }
}

/*
 * Cursor.
 *
 * Sobre una lista de canciones el puntero salia como barra de texto (el cursor de seleccionar
 * texto), porque los titulos son texto normal dentro de un div pinchable. Aqui se dice
 * explicitamente que todo lo pinchable use la manita, y de paso se evita que un doble clic
 * rapido para reproducir acabe seleccionando el titulo.
 */
.song-row, .card, .quick, .nav-item, .chip, .side-list button, .lyric-line:not(.plain) {
    cursor: pointer;
    user-select: none;
}
.song-row .song-title, .song-row .song-sub, .card .name, .card .meta { cursor: pointer; }

/* El texto de la letra si se puede seleccionar: alguien querra copiarla. */
.lyric-line { user-select: text; }

/* Tamano de la letra, ajustable desde Ajustes. */
.lyric-line { font-size: var(--lyric-size, 16px); }
.lyric-line.active { font-size: calc(var(--lyric-size, 16px) + 3px); }

/* ---------------------------------------------------------------- movil */

@media (max-width: 820px) {
    /*
     * Hoja inferior para la letra y la cola.
     *
     * La altura se mide en `dvh` y NO en `vh`. En iOS, `100vh` es la pantalla con la barra del
     * navegador escondida, o sea MAS de lo que se ve: un panel de `62vh` anclado por abajo
     * empujaba su propia cabecera —con el boton de cerrar— fuera de la parte visible. De ahi que
     * no hubiera forma de cerrarlo. `dvh` mide lo que se ve de verdad.
     *
     * Y el panel es un contenedor flexible con la cabecera fija y solo el cuerpo con
     * desplazamiento, para que la X este SIEMPRE arriba del todo, mida lo que mida el contenido.
     */
    .side-panel {
        left: 0; right: 0; width: auto; max-width: none;
        top: auto;
        bottom: calc(var(--bottom-player-height) + 62px + var(--tapado-abajo, 0px));
        height: min(58dvh, 460px);
        display: flex; flex-direction: column;
        overflow: hidden;                 /* el que se desplaza es el cuerpo, no el panel */
        border-radius: 18px 18px 0 0;
        border-left: 0; border-top: 1px solid rgba(255,255,255,.08);
        box-shadow: 0 -14px 40px rgba(0,0,0,.5);
        /* Por encima de la navegacion inferior (z-index 20), que si no lo tapa por abajo. */
        z-index: 25;
        transform: translateY(calc(100% + var(--bottom-player-height) + 62px));
    }
    .side-panel.open { transform: translateY(0); }

    /* La cabecera no se desplaza: es la barra fija con el titulo y la X. */
    .panel-head {
        flex: 0 0 auto; position: static;
        background: var(--surface); padding: 4px 0 10px; margin: 0;
    }
    /* Area de toque mas grande para cerrar: en el movil una X de 20 px se falla. */
    .panel-head .icon-btn { padding: 10px; margin: -10px; }

    /* Solo el contenido se desplaza. */
    #queue-list { flex: 1 1 auto; overflow-y: auto; min-height: 0; }

    /*
     * Fondo oscuro detras de la hoja. Existe para poder cerrarla tocando fuera, que es lo primero
     * que intenta cualquiera antes de buscar la X.
     */
    .panel-scrim {
        position: fixed; inset: 0; z-index: 24;
        background: rgba(0,0,0,.5);
        opacity: 0; pointer-events: none;
        transition: opacity 200ms ease;
    }
    .panel-scrim.show { opacity: 1; pointer-events: auto; }

    /* Los accesos rapidos de la portada, a una columna: dos no caben sin cortar el texto. */
    .quick-grid { grid-template-columns: 1fr; }

    /* Rejilla de tarjetas mas apretada, como hace Spotify en movil. */
    .grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 14px; }

    /*
     * Reproductor pequeno: una sola fila, al estilo de Spotify.
     *
     * Caratula, titulo y play. Nada mas. Los controles completos —aleatorio, repetir, la barra
     * de progreso que se arrastra, la letra— viven en la pantalla de reproduccion, que se abre
     * tocando el titulo. Amontonarlo todo aqui era lo que hacia que el titulo desapareciera.
     */
    .player {
        display: flex; align-items: center;
        height: var(--bottom-player-height); padding: 0 10px 0 12px; gap: 10px;
    }
    .player-song { flex: 1 1 auto; min-width: 0; gap: 10px; }
    .player-song .song-meta { flex: 1; min-width: 0; cursor: pointer; }
    .player-song .song-title { font-size: 14px; }
    .player-song .song-sub { font-size: 12px; }
    .player-song .art { width: 44px; height: 44px; }

    /* Los controles de escritorio y la columna de volumen no pintan nada en el telefono. */
    .player-controls, .player-right { display: none; }

    /* Linea de progreso fina, cruzando el borde superior del reproductor. */
    .mini-progress { display: block; }

    /*
     * Zonas de toque de 44 px, que es la referencia en iOS. Antes los botones median 38 y el de
     * reproducir 42: el mas importante era de los mas dificiles de acertar.
     */
    .icon-btn { width: 44px; height: 44px; }
    .btn-round { width: 48px; height: 48px; }
    .btn-round .ico { width: 22px; height: 22px; }

    /*
     * El play del reproductor pequeno va SIN disco morado.
     *
     * Relleno de color y a ese tamano, al lado de una linea de texto, era una pelota que se
     * comia toda la atencion — la que deberia llevarse la cancion. Aqui basta el icono; el
     * boton grande y morado se queda para la pantalla de reproduccion, donde si es el control
     * principal y tiene espacio alrededor.
     */
    #btn-play-mini {
        background: none; width: 44px; height: 44px;
        color: var(--on-background);
    }
    #btn-play-mini:hover { background: var(--surface-variant); }
    #btn-play-mini .ico { width: 26px; height: 26px; color: currentColor; }
}

/* ---------------------------------------------------------------- pantalla de reproduccion */

/*
 * Base comun a movil y escritorio. Cambia el reparto del espacio, no la pieza.
 */
.pantalla-completa {
    position: fixed; inset: 0; z-index: 30;
    display: flex; flex-direction: column;
    background: var(--background);
    transition: transform 280ms cubic-bezier(.2,.7,.3,1);
}
.pantalla-completa[hidden] {
    display: flex; transform: translateY(100%);
    visibility: hidden; pointer-events: none;
    transition: transform 280ms cubic-bezier(.2,.7,.3,1), visibility 0s 280ms;
}

/* La cola y la letra se abren por encima de esta vista. */
.side-panel { z-index: 35; }
.panel-scrim { z-index: 34; }

/* ---------------------------------------------------------------- version de escritorio */

/*
 * En escritorio NO es una pantalla completa: es una columna a la derecha, como el panel "En
 * reproduccion" de Spotify.
 *
 * La diferencia importa. Tapando toda la ventana se pierde el menu lateral y la lista que se
 * estaba mirando, asi que para seguir navegando hay que cerrarla; con la columna, la musica se
 * ve en grande Y se puede seguir buscando. Por eso el contenido se estrecha en vez de quedar
 * debajo: nada queda tapado.
 *
 * Los controles no se repiten aqui. Reproducir, aleatorio, repetir, volumen y la barra de
 * progreso siguen en la barra de abajo, a la vista; duplicarlos seria mantener dos juegos
 * sincronizados para nada.
 */
@media (min-width: 821px) {
    .pantalla-completa {
        top: 0; left: auto; right: 0;
        bottom: var(--bottom-player-height);
        width: var(--ancho-panel-derecho);
        background: var(--surface);
        border-left: 1px solid rgba(255,255,255,.06);
        padding: 14px 18px 18px;
        transform: translateX(0);
    }
    /* Cerrada se va por la derecha, no por abajo. */
    .pantalla-completa[hidden] { transform: translateX(100%); }

    /* El contenido cede el ancho del panel en vez de quedarse debajo. */
    body.pc-abierta .app { padding-right: var(--ancho-panel-derecho); }

    .pc-seek, .pc-controles { display: none; }

    .pc-cabecera { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; }
    .pc-origen {
        flex: 1; text-align: center; font-size: 12px; letter-spacing: .08em;
        text-transform: uppercase; color: var(--on-surface-variant);
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }

    .pc-centro { flex: 0 0 auto; margin: 12px 0 14px; }
    .pc-caratula {
        width: 100%; aspect-ratio: 1; object-fit: cover;
        border-radius: 12px; box-shadow: 0 16px 40px rgba(0,0,0,.45);
    }

    .pc-info { flex: 0 0 auto; margin-bottom: 12px; }
    .pc-titulo { font-size: 20px; font-weight: 700; line-height: 1.25; }
    .pc-artista { font-size: 14px; color: var(--on-surface-variant); margin-top: 3px; }

    /* La letra se queda con lo que sobre y se desplaza sola. */
    .pc-letra {
        flex: 1 1 auto; min-height: 0; overflow-y: auto;
        text-align: left; padding-right: 6px;
    }

    .pc-pie { flex: 0 0 auto; padding-top: 12px; }
}

.mini-progress { display: none; position: absolute; top: 0; left: 0; right: 0; height: 2px;
                 background: rgba(255,255,255,.12); }
.mini-progress span { display: block; height: 100%; width: 0;
                      background: var(--secondary); transition: width 200ms linear; }

@media (max-width: 820px) {
    /*
     * En movil la vista ocupa TODA la pantalla y trae sus propios controles: aqui abajo solo
     * queda una barra de una linea, sin sitio para ellos.
     */
    .pantalla-completa {
        inset: 0;
        padding: env(safe-area-inset-top) 22px
                 calc(18px + env(safe-area-inset-bottom) + var(--tapado-abajo, 0px));
    }

    .pc-cabecera { display: flex; align-items: center; gap: 10px; padding: 6px 0 4px; }
    .pc-origen {
        flex: 1; text-align: center; font-size: 12px; letter-spacing: .08em;
        text-transform: uppercase; color: var(--on-surface-variant);
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }

    /* La caratula manda: se queda con todo el hueco que sobra, pero siempre cuadrada. */
    .pc-centro {
        flex: 1 1 auto; min-height: 0;
        display: flex; align-items: center; justify-content: center;
        margin: 8px 0 18px;
    }
    .pc-caratula {
        max-width: 100%; max-height: 100%; aspect-ratio: 1;
        object-fit: cover; border-radius: 14px;
        box-shadow: 0 20px 50px rgba(0,0,0,.55);
    }
    .pc-letra {
        width: 100%; height: 100%; overflow-y: auto;
        text-align: center; padding: 10px 0;
    }

    .pc-info { margin-bottom: 14px; }
    .pc-titulo {
        font-size: 21px; font-weight: 700; line-height: 1.25;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .pc-artista { font-size: 15px; color: var(--on-surface-variant); margin-top: 3px;
                  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

    /* Barra de progreso grande: aqui si hay sitio para arrastrarla con el dedo. */
    .pc-seek { margin-bottom: 10px; }
    .pc-seek .seek-track { padding: 14px 0; }
    .pc-seek .seek-rail { height: 5px; }
    .pc-seek .seek-thumb { width: 14px; height: 14px; opacity: 1; }

    .pc-controles {
        display: flex; align-items: center; justify-content: space-between;
        margin: 6px 0 18px;
    }
    .pc-controles .btn-round.grande { width: 68px; height: 68px; }
    .pc-controles .btn-round.grande .ico { width: 30px; height: 30px; }
    .pc-controles .icon-btn { width: 48px; height: 48px; }

    .pc-pie { display: flex; align-items: center; justify-content: space-between; }

    /* Con la pantalla completa abierta, lo de detras no se desplaza ni se toca. */
    body.pc-abierta { overflow: hidden; }
}

#pc-letra .empty, #queue-list .empty { padding: 30px 10px; }

/* ---------------------------------------------------------------- dialogos */

/*
 * Sustituyen a `prompt` y `confirm` del navegador.
 *
 * En escritorio son una tarjeta centrada, como en Spotify; en movil suben desde abajo, como en
 * Deezer, porque una tarjeta en el centro de un telefono deja el dedo lejos de los botones.
 */
.modal { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; }
.modal[hidden] { display: none; }

.modal-fondo { position: absolute; inset: 0; background: rgba(0,0,0,.6); }

.modal-caja {
    position: relative;
    width: min(420px, calc(100vw - 32px));
    max-height: min(70vh, 620px);
    display: flex; flex-direction: column;
    background: var(--surface-variant);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 16px;
    padding: 22px;
    box-shadow: 0 30px 70px rgba(0,0,0,.6);
}
.modal-titulo { margin: 0 0 14px; font-size: 19px; }
.modal-cuerpo { overflow-y: auto; min-height: 0; }
.modal-acciones { display: flex; justify-content: flex-end; gap: 10px; padding-top: 18px; }

.modal input[type="text"] {
    width: 100%;
    background: var(--surface); border: 1px solid rgba(255,255,255,.12);
    border-radius: 8px; padding: 12px 14px;
    color: var(--on-background); font-size: 15px; font-family: inherit;
    outline: none;
}
.modal input[type="text"]:focus { border-color: var(--primary); }

.btn-texto { padding: 10px 18px; border-radius: 999px; font-size: 14px; font-weight: 600;
             color: var(--on-surface-variant); }
.btn-texto:hover { color: var(--on-background); background: var(--surface-elevated); }
.btn-peligro { color: var(--error); }

/* Cada playlist como una fila pulsable: se elige tocando, no escribiendo un numero. */
.modal-opcion {
    display: flex; align-items: center; gap: 12px;
    width: 100%; text-align: left;
    padding: 10px 12px; border-radius: 10px;
}
.modal-opcion:hover { background: var(--surface-elevated); }
.modal-opcion .ico { color: var(--on-surface-variant); }
.modal-opcion.destacada .ico, .modal-opcion.destacada b { color: var(--secondary); }
.modal-opcion b { font-weight: 600; font-size: 15px; }
.modal-opcion span { display: block; font-size: 13px; color: var(--on-surface-variant); margin-top: 2px; }

@media (max-width: 820px) {
    .modal { place-items: end stretch; }
    .modal-caja {
        width: auto; max-width: none; max-height: 80dvh;
        border-radius: 18px 18px 0 0;
        padding-bottom: calc(22px + env(safe-area-inset-bottom) + var(--tapado-abajo, 0px));
    }
}

/* ---------------------------------------------------------------- bienvenida */

/*
 * Se ve una sola vez, al crear la cuenta: elegir generos y luego artistas.
 *
 * Tapa la pantalla entera a proposito. Es el unico momento de la aplicacion en que interesa que
 * no haya nada mas que hacer: son dos decisiones cortas que determinan como se vera el inicio a
 * partir de entonces, y con la interfaz detras la mitad de la gente se va sin elegir.
 */
.bienvenida {
    position: fixed; inset: 0; z-index: 55;
    background: var(--background);
    overflow-y: auto;
    padding: env(safe-area-inset-top) 20px calc(20px + env(safe-area-inset-bottom));
}
.bienvenida[hidden] { display: none; }

.bv-caja { max-width: 900px; margin: 0 auto; padding: 40px 0 24px; }
.bv-paso {
    font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
    color: var(--secondary); font-weight: 700; margin-bottom: 10px;
}
.bv-titulo { font-size: clamp(26px, 4vw, 38px); margin: 0 0 8px; line-height: 1.15; }
.bv-ayuda { color: var(--on-surface-variant); font-size: 15px; margin: 0 0 28px; }

.bv-rejilla {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 14px; margin-bottom: 90px;
}

/* Genero: tarjeta de color. Sin imagen, porque una foto generica de "rock" no dice nada y
   obligaria a buscarla; el color y el nombre bastan y cargan al instante. */
.bv-genero {
    position: relative; aspect-ratio: 16 / 10;
    border-radius: 12px; padding: 12px;
    display: flex; align-items: flex-end;
    font-weight: 700; font-size: 15px; color: #fff;
    text-align: left; overflow: hidden;
    border: 2px solid transparent;
    transition: transform 140ms ease;
}
.bv-genero:hover { transform: scale(1.03); }
.bv-genero.elegido { border-color: #fff; }
.bv-genero.elegido::after {
    content: '✓'; position: absolute; top: 8px; right: 10px;
    font-size: 16px; font-weight: 800;
}

/* Artista: foto redonda, como en Spotify y Deezer. */
.bv-artista { text-align: center; }
.bv-artista img {
    width: 100%; aspect-ratio: 1; border-radius: 50%; object-fit: cover;
    background: var(--surface-variant);
    border: 3px solid transparent;
    transition: transform 140ms ease;
}
.bv-artista:hover img { transform: scale(1.04); }
.bv-artista.elegido img { border-color: var(--primary); }
.bv-artista span {
    display: block; margin-top: 8px; font-size: 14px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* La barra de acciones se queda fija abajo: con una rejilla larga, un boton al final del
   desplazamiento es un boton que no se encuentra. */
.bv-pie {
    position: fixed; left: 0; right: 0;
    bottom: calc(var(--tapado-abajo, 0px));
    display: flex; align-items: center; justify-content: center; gap: 14px;
    padding: 16px 20px calc(16px + env(safe-area-inset-bottom));
    background: linear-gradient(180deg, transparent, var(--background) 45%);
}

/* ---------------------------------------------------------------- panel de cola */

/* De donde sale lo que suena: album, busqueda, playlist... */
.queue-origen {
    font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
    color: var(--on-surface-variant);
    padding: 2px 4px 12px;
}
.queue-origen b { color: var(--secondary); font-weight: 700; text-transform: none;
                  letter-spacing: 0; font-size: 13px; }

/*
 * En el panel no cabe la duracion: son 360 px y el titulo es lo unico que de verdad hay que
 * poder leer. Con ella puesta, «Glorioso Rey» se quedaba en «Gloriosos R...».
 */
.side-panel .song-time { display: none; }
.side-panel .song-row { padding: 7px 8px; gap: 10px; }
.side-panel .art { width: 44px; height: 44px; }

/*
 * Portada de respaldo: una nota sobre el degradado de la marca.
 *
 * Ocupa lo mismo que la imagen a la que sustituye, para que la cabecera no cambie de forma segun
 * haya caratula o no. Las medidas salen de `.hero img`.
 */
.portada-vacia {
    width: 200px; height: 200px; flex-shrink: 0;
    border-radius: 12px;
    background: linear-gradient(135deg, var(--primary), #4C1D95);
    display: grid; place-items: center;
    box-shadow: 0 16px 40px rgba(0,0,0,.45);
    position: relative; z-index: 1;
}
.portada-vacia .ico {
    width: 64px; height: 64px;
    color: rgba(255,255,255,.85);
}

@media (max-width: 820px) {
    .portada-vacia { width: 140px; height: 140px; }
    .portada-vacia .ico { width: 46px; height: 46px; }
}

/*
 * Hueco de imagen sin imagen.
 *
 * Toma el tamano del sitio donde se ponga —una fila, una tarjeta, un acceso rapido— en lugar de
 * imponer el suyo, para que no haya que declarar medidas en cada caso.
 */
.sin-imagen {
    width: 100%; height: 100%;
    aspect-ratio: 1;
    border-radius: inherit;
    background: linear-gradient(135deg, var(--surface-elevated), var(--surface-variant));
    display: grid; place-items: center;
    flex-shrink: 0;
}
.sin-imagen .ico { width: 45%; height: 45%; color: var(--on-surface-variant); opacity: .7; }

/* En la fila de cancion hereda las medidas de `.art`, que ya son 52x52. */
.song-row .art.sin-imagen { width: 52px; height: 52px; border-radius: 8px; }

/* En los accesos rapidos de la portada, el hueco es cuadrado y pequeno. */
.quick-vacia { border-radius: 6px 0 0 6px; }
