/* =================================================================
   album-grid.css — Album cards, grids, grouped views (composer /
   artist / genre / etc), coverflow, and all audio-format/quality
   badge styling plus associated gradient classes.
   ================================================================= */

.albums-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(calc(160px * var(--grid-zoom)), 1fr));
    gap: calc(20px * var(--grid-zoom));
}

/* =============================================================
   Loading state — polished album-grid skeleton + status spinner.
   Active whenever <body data-loading-library="1"> is set; cleared
   automatically by loadLibrary's `finally` block. The skeleton
   auto-vanishes the instant renderAllViews inserts real cards
   (it's keyed off `:empty` which stops matching).
   ============================================================= */

/* Skeleton album tiles — pure CSS shimmer that mimics the real
   .album-card layout (square cover slot + two text-line slots).
   Fills the grid container with placeholder tiles via repeated
   linear-gradients on a single ::before, so we don't need to inject
   real DOM nodes. The shimmer sweep gives a sense of progress. */
body[data-loading-library] .albums-grid:empty {
    min-height: calc(280px * var(--grid-zoom));
    position: relative;
    /* Inherit the real grid layout for the skeleton tiles. */
    grid-auto-rows: calc(220px * var(--grid-zoom));
}

body[data-loading-library] .albums-grid:empty::before {
    content: '';
    /* Span the entire grid as a giant overlay. */
    grid-column: 1 / -1;
    grid-row: 1 / span 3;
    border-radius: 15px;
    /* Repeated background pattern: each "tile" is a card-shaped
       block with a subtle radial highlight. The repeat-x / repeat-y
       behavior tracks the actual grid layout via background-size. */
    background:
        /* Shimmer sweep — moves left to right under the tiles. */
        linear-gradient(110deg,
            transparent 30%,
            rgba(255, 255, 255, 0.06) 50%,
            transparent 70%) 0 0 / 200% 100% no-repeat,
        /* Tile fill — solid card colour repeated. */
        var(--bg-card);
    border-radius: 15px;
    /* The ::before is one big block; we use background-size to
       suggest individual tiles via the shimmer animation, while
       the visual breakdown into cards is handled by box-shadow
       inset stripes below. */
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.02);
    animation:
        auditura-skeleton-shimmer 1.6s ease-in-out infinite,
        auditura-skeleton-pulse   2.8s ease-in-out infinite;
    opacity: 0.55;
}

@keyframes auditura-skeleton-pulse {
    0%, 100% { opacity: 0.32; }
    50%      { opacity: 0.62; }
}

@keyframes auditura-skeleton-shimmer {
    0%   { background-position: -50% 0, 0 0; }
    100% { background-position: 150% 0, 0 0; }
}

/* Spinner ring next to the "Loading library…" status text.
   Pure CSS — no extra DOM. Only renders while the loading flag
   is set; the spin animation picks up the user's accent colour
   so it inherits theme changes for free. */
body[data-loading-library] #library-status {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
body[data-loading-library] #library-status::after {
    content: '';
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.18);
    border-top-color: var(--accent-primary, #5af);
    animation: auditura-loading-spin 0.75s linear infinite;
    /* Keep the baseline aligned with the status text. */
    flex: 0 0 auto;
}

@keyframes auditura-loading-spin {
    to { transform: rotate(360deg); }
}

.album-card {
    /* Artwork-first album tile shared by the desktop app and desktop web.
       The cover itself is the card; title/artist are overlaid on the art
       instead of living in a second panel underneath it. */
    background: transparent;
    border-radius: 0;
    padding: 0;
    cursor: pointer;
    transition: transform 0.22s ease, box-shadow 0.22s ease, outline-color 0.22s ease;
    user-select: none;
    position: relative;
    overflow: hidden;
    aspect-ratio: 1;
    /* Off-screen tiles skip layout/paint. aspect-ratio keeps the
       intrinsic size stable so the scrollbar does not jump. This is what
       makes Home→Library instant and scrolling smooth with hundreds of cards. */
    content-visibility: auto;
    contain-intrinsic-size: auto 180px;
}

.album-card:hover {
    background: transparent;
    transform: translateY(-4px);
    box-shadow: var(--shadow-md);
}
html.platform-linux .album-card:hover {
    /* NVIDIA/WebKitGTK: per-tile transform+shadow layers stutter on scroll. */
    transform: none;
    box-shadow: none;
}

/* Selection must read as a selection, not four tiny corner ticks. Paint
   ABOVE the cover art (inset shadows on .album-card were hidden by its img),
   and use the configured accent rather than a hard-coded yellow. This shared
   style also reaches the web/mobile album grid. */
.album-card.selected,
.coverflow-item.selected {
    outline: none;
    transform: none;
}
.album-card.selected::after,
.coverflow-item.selected::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 11;
    border: 3px solid var(--accent-primary, #f5c94d);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4),
                inset 0 0 28px rgba(var(--accent-primary-rgb), 0.19);
    pointer-events: none;
    box-sizing: border-box;
}
.album-card.selected::before,
.coverflow-item.selected::before {
    content: '✓';
    position: absolute;
    z-index: 12;
    right: 8px;
    top: 8px;
    width: 25px;
    height: 25px;
    border-radius: 50%;
    background: var(--accent-primary, #f5c94d);
    color: var(--bg-dark, #151515);
    border: 1px solid rgba(0, 0, 0, 0.30);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.55);
    display: grid;
    place-items: center;
    font: 800 16px/1 sans-serif;
    pointer-events: none;
}
/* Don't cover an existing partial-library badge on selected albums. */
.album-card.selected .album-partial-badge { top: 40px; }

.album-cover {
    width: 100%;
    height: 100%;
    aspect-ratio: 1;
    border-radius: 0;
    margin-bottom: 0;
    position: relative;
    overflow: hidden;
    background-size: cover;
    background-position: center;
    /* bg-card behind the <img> so the rounded square shows a subtle
       surface tint while the image decodes — no more empty-rectangle
       gap between layout and decode. The same colour is what the card
       uses, so the seam is invisible. */
    background-color: var(--bg-card);
}

/* Universal album / entity-art image. Used inside any cover wrapper
   (.album-cover, .detail-cover, .qh-cover, .entity-tile-avatar, etc.)
   to fill the wrapper while preserving aspect ratio. The wrapper owns
   the rounding / shadow / badges; the image is purely visual.
   `display: block` keeps the inline-baseline whitespace from leaking
   below the rounded corners, and `pointer-events: none` lets clicks
   reach the wrapper's data-* attributes (album id, etc.). */
/* Auto-position any wrapper that contains a cover image. Without this,
   wrappers using `width: auto` or `height: auto` (e.g. .hnp-cover with
   aspect-ratio + height:100%) would let the img's intrinsic dimensions
   bleed back through and blow the wrapper up to 1200x1200. With absolute
   positioning the img sizes to the wrapper's box regardless of how that
   box was computed; this rule guarantees the wrapper is the positioned
   ancestor that absolute targets. Wrappers that already declare
   position:relative are unaffected (this just confirms it). */
*:has(> img.cover-img) {
    position: relative;
}

.cover-img {
    /* Fill the wrapper exactly. Absolute + inset:0 sidesteps every
       percentage-resolution quirk (aspect-ratio parents, auto width
       parents, flex containers); the wrapper's existing layout decides
       the box, the img fills it. */
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    display: block;
    /* Clicks reach the wrapper's data-* attributes (album id, etc.) — the
       img is purely visual. */
    pointer-events: none;
    /* Inherit the wrapper's border-radius so the image clips itself to
       rounded corners even when the wrapper doesn't declare
       overflow:hidden (e.g. .tag-cover-preview). Wrappers that DO clip
       are unaffected — matching the same rounding twice is a no-op. */
    border-radius: inherit;
    /* Hidden until the image actually decodes — the wrapper's
       background-color shows through during the wait. JS adds the
       .cover-img-loaded class on the img's `load` event so the fade
       is tied to actual byte arrival, not to the moment `src` was
       assigned. (If we faded on [src] alone, an opaque-but-empty
       img would obscure the bg-card tint while bytes were still
       in flight.) */
    opacity: 0;
    transition: opacity 180ms ease;
}
.cover-img.cover-img-loaded {
    opacity: 1;
}
/* Browser-cache-hit short-circuit. softRefreshLibrary() rebuilds every
   album-card on tag writes, which creates fresh <img> elements with the
   same URLs as the just-rendered ones. Those URLs are hot in the
   browser's image cache and resolve synchronously, but the freshly-
   inserted img starts at opacity:0 — without this class, every tag write
   triggers a full-grid fade-in flash. cover-img-instant disables the
   transition so the loaded class snaps to opacity:1 with no animation:
   visually, the cover never disappeared. */
.cover-img.cover-img-instant {
    transition: none;
}

.album-partial-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    background: rgba(var(--accent-cyan-rgb), 0.9);
    color: var(--bg-dark);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-weight: 700;
    padding: 3px 8px;
    border-radius: 10px;
    pointer-events: none;
    box-shadow: var(--shadow-sm);
}

.album-quality-badge {
    position: absolute;
    top: 8px;
    left: 8px;
    bottom: auto;
    pointer-events: none;
    z-index: 4;
}

/* Quality-badge visibility modes (Settings → Playback → Audio quality badge).
   Default 'all' = no body class = badges show wherever rendered. The two
   override modes are toggled by applyQualityBadgeMode() in player.js. */

/* 'off' — hide every audio-badge across the app, plus the album-cover
   wrapper so we don't leave an empty positioned slot. */
body.quality-badge-mode-off .audio-badge,
body.quality-badge-mode-off .album-quality-badge {
    display: none !important;
}

/* 'art' — keep the badge on album covers, hide everywhere else (song
   rows, queue rows, now-playing hero, detail-panel track rows, …).
   Whitelist .album-quality-badge .audio-badge so the cover one stays
   visible while the catch-all rule blanks the rest. */
body.quality-badge-mode-art .audio-badge {
    display: none !important;
}
body.quality-badge-mode-art .album-quality-badge .audio-badge {
    display: inline-flex !important;
}

/* Booklet indicator — small PDF/book icon in the bottom-right corner of
   an album's cover when album.booklet is set. Clicking an album still
   opens the album detail panel; right-click → "View booklet" opens it. */
.album-booklet-badge {
    position: absolute;
    bottom: 8px;
    right: 8px;
    width: 24px;
    height: 24px;
    border-radius: 6px;
    background: rgba(var(--surface-app-rgb), 0.78);
    color: var(--accent-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(var(--accent-secondary-rgb), 0.4);
    cursor: pointer;
    transition: background 0.15s ease, transform 0.1s ease;
    box-shadow: var(--shadow-sm);
    z-index: 3;
}

.album-booklet-badge:hover {
    background: rgba(var(--accent-secondary-rgb), 0.4) !important;
    transform: scale(1.15) !important;
}

.album-card:hover .album-booklet-badge {
    background: rgba(var(--accent-secondary-rgb), 0.28);
    transform: scale(1.08);
}

.audio-badge {
    display: inline-flex;
    align-items: center;
    gap: 0;
    font-family: 'Consolas', 'SF Mono', monospace;
    font-weight: 700;
    letter-spacing: 0.04em;
    line-height: 1;
    border-radius: 4px;
    overflow: hidden;
    flex-shrink: 0;
    user-select: none;
    vertical-align: middle;
    box-shadow: var(--shadow-sm);
}

.audio-badge .ab-format {
    padding: 3px 6px;
    font-size: 10px;
    background: var(--bg-dark);
    color: var(--text-primary);
}

.audio-badge .ab-quality {
    padding: 3px 6px;
    font-size: 10px;
    background: var(--overlay-active);
    color: var(--text-secondary);
}

.audio-badge-md .ab-format,
.audio-badge-md .ab-quality {
    padding: 5px 10px;
    font-size: 12px;
    letter-spacing: 0.06em;
}

.audio-badge-lossy .ab-format {
    background: var(--badge-lossy-format-bg);
    color: var(--badge-lossy-format-text);
}
.audio-badge-lossy .ab-quality {
    background: var(--badge-lossy-quality-bg);
    color: var(--badge-lossy-quality-text);
}

.audio-badge-lossless .ab-format {
    background: var(--badge-lossless-format-bg);
    color: var(--badge-lossless-format-text);
}
.audio-badge-lossless .ab-quality {
    background: var(--badge-lossless-quality-bg);
    color: var(--badge-lossless-quality-text);
}

.audio-badge-hires .ab-format {
    background: var(--badge-hires-format-bg);
    color: var(--badge-hires-format-text);
}
.audio-badge-hires .ab-quality {
    background: var(--badge-hires-quality-bg);
    color: var(--badge-hires-quality-text);
}

.audio-badge-dsd .ab-format {
    background: var(--badge-dsd-format-bg);
    color: var(--badge-dsd-format-text);
}
.audio-badge-dsd .ab-quality {
    background: var(--badge-dsd-quality-bg);
    color: var(--badge-dsd-quality-text);
}

.audio-badge-hires-glow {
    box-shadow: var(--badge-hires-glow);
}

.audio-badge-dsd.audio-badge-hires-glow {
    box-shadow: var(--badge-dsd-glow);
}

.album-shine {
    position: absolute;
    top: -50%;
    left: -50%;
    width: 200%;
    height: 200%;
    background: linear-gradient(45deg, transparent, var(--overlay-active), transparent);
    transform: rotate(45deg);
    transition: all 0.5s;
}

.album-card:hover .album-shine {
    animation: shine 0.5s;
}

@keyframes shine {
    from { top: -50%; left: -50%; }
    to { top: 100%; left: 100%; }
}

.cool-summer {
    background: linear-gradient(135deg, #ff6b35, #f7c548);
}

.midnight-echo {
    background: linear-gradient(135deg, #2c3e50, #3498db);
}

.electric-soul {
    background: linear-gradient(135deg, #9b5de5, #00f5d4);
}

.urban-flux {
    background: linear-gradient(135deg, #e74c3c, #f39c12);
}

.cosmic-dawn {
    background: linear-gradient(135deg, #1a1a2e, #9b5de5);
}

.retro-haze {
    background: linear-gradient(135deg, #ff69b4, #ff9a8b);
}

.album-info {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    margin: 0;
    padding: 48px 12px 11px;
    min-width: 0;
    pointer-events: none;
    background: linear-gradient(
        to top,
        rgba(0, 0, 0, 0.88) 0%,
        rgba(0, 0, 0, 0.62) 48%,
        rgba(0, 0, 0, 0) 100%
    );
}

.album-info h3 {
    font-size: 14px;
    line-height: 1.15;
    margin: 0;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.72);
}

.album-info p {
    font-size: 12px;
    line-height: 1.15;
    margin: 3px 0 0;
    color: rgba(255, 255, 255, 0.78);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.72);
}

.aurora-borealis {
    background: linear-gradient(135deg, #00f5d4, #9b5de5, #ff6b35);
}

/* =====================================================================
   CoverFlow — falling-cover animated view (coverflow.js).
   Adapted from the standalone CardFlow prototype: covers float top-to-
   bottom on a masked stage, sway side to side, depth-blur for parallax,
   and a gentle 3D rotation. Click a cover to "select" it (scales up
   centred, animation pauses). Click again to open the album detail.

   Custom properties wired by coverflow.js:
     --w        cover width (px)
     --b        depth blur (px)
     --z        depth z-index
     --d        fall+sway duration (s)
     --delay    negative offset so each cover starts at a different
                point in its loop (avoids synchronized columns)
     --rd, --td rock-spin and face-tilt durations
     --dx0..3   sway keyframe offsets
     --sy, --ty fall start / travel distance
     --rxa..b   rotateX keyframes
     --rya..b   rotateY keyframes
     --bra..b   brightness keyframes
   The selected state replaces left/width with --selected-* so the
   cover lifts to the centre without losing its stage-relative absolute
   positioning. */
.view-section[data-view="coverflow"] {
    padding: 0;
}
.view-section[data-view="coverflow"].active {
    height: 100%;
}

.cf-wrapper {
    position: relative;
    width: 100%;
    height: 100%;
    min-height: calc(100vh - var(--player-height));
    overflow: hidden;
    isolation: isolate;
}

.cf-stage {
    position: absolute;
    inset: 0;
    overflow: hidden;
    /* Soft fade top + bottom so covers ease in / out instead of
       suddenly appearing or being clipped at the boundary. */
    -webkit-mask-image: linear-gradient(180deg,
        transparent 0,
        rgba(0,0,0,0.92) 8%,
        rgba(0,0,0,0.96) 92%,
        transparent 100%);
            mask-image: linear-gradient(180deg,
        transparent 0,
        rgba(0,0,0,0.92) 8%,
        rgba(0,0,0,0.96) 92%,
        transparent 100%);
}

.cf-stage .empty-message {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    text-align: center;
    padding: 40px;
}

/* Meta row — pinned to the bottom-right of the stage with a small
   pill background so it reads on top of busy covers. Houses the
   "X of Y albums" count + a Shuffle button to re-randomize. */
.cf-meta {
    position: absolute;
    bottom: 14px;
    right: 18px;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 10px 6px 14px;
    border-radius: 999px;
    background: rgba(var(--surface-app-rgb), 0.65);
    border: 1px solid var(--border-subtle);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    z-index: 50;
    font-size: 11.5px;
    color: var(--text-muted);
    pointer-events: auto;
}
.cf-meta-count { white-space: nowrap; }
.cf-shuffle {
    padding: 5px 12px !important;
    font-size: 11.5px !important;
    border-radius: 999px !important;
}

/* Each cover sits absolutely positioned, animated with `fall` (Y
   translation) on the outer element and `sway` (X drift) on the
   inner wrapper. Rock-spin and face-tilt animate the cover itself
   for a subtle handheld feel. */
.cf-card {
    position: absolute;
    top: 0;
    left: 0;
    width: var(--w);
    z-index: var(--z);
    filter: blur(var(--b));
    animation: cf-fall var(--d) linear infinite;
    animation-delay: var(--delay);
    will-change: transform;
    pointer-events: auto;
    cursor: pointer;
    transition: opacity 0.28s ease,
                filter 0.32s ease,
                left 0.42s ease,
                width 0.42s ease;
}
.cf-card:focus-visible {
    outline: none;
}
.cf-card:focus-visible .cf-cover3d {
    box-shadow: 0 0 0 3px var(--border-focus);
}
.cf-bob {
    animation: cf-sway var(--d) linear infinite;
    animation-delay: var(--delay);
    transform-origin: center center;
    will-change: transform;
    transition: transform 0.42s ease;
}
.cf-cover3d {
    width: 100%;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
    perspective: 624px;
    filter: drop-shadow(var(--shadow-md));
    animation: cf-rockspin var(--rd) linear infinite;
    transform-origin: center center;
    will-change: transform;
    border-radius: 12px;
    overflow: hidden;
    background: var(--surface-card);
    transform-style: preserve-3d;
    backface-visibility: hidden;
}
.cf-cover3d.cf-cover-empty {
    background: linear-gradient(135deg, var(--surface-card), var(--surface-card-hover));
    /* Subtle disc-icon mask for albums that don't have artwork — keeps
       the cover well from looking like an empty placeholder. */
    background-image:
        radial-gradient(circle at 50% 50%, var(--text-muted) 0%, var(--text-muted) 18%, transparent 19%),
        radial-gradient(circle at 50% 50%, transparent 27%, var(--surface-card-hover) 28%, var(--surface-card-hover) 60%, transparent 61%);
}
.cf-cover-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    display: block;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
    /* Brightness keyframes drive a tiny "alive" pulse — much subtler
       than the trading-card prototype's rotation since album covers
       are flat artwork, not 3D plastic. */
    animation: cf-facetilt var(--td) linear infinite;
    will-change: filter;
}

/* Selected state: pause everything, scale up to the configured
   layout, and pop above other covers with a soft halo. */
.cf-stage.cf-has-selection .cf-card:not(.cf-selected) {
    pointer-events: none;
    filter: blur(var(--b)) brightness(0.55);
    opacity: 0.55;
}
.cf-card.cf-selected {
    animation: none;
    left: var(--selected-left) !important;
    width: var(--selected-width) !important;
    z-index: 92 !important;
    filter: drop-shadow(0 26px 60px rgba(0, 0, 0, 0.45));
    transition: left 0.45s cubic-bezier(.2, .8, .2, 1),
                width 0.45s cubic-bezier(.2, .8, .2, 1),
                top 0.45s cubic-bezier(.2, .8, .2, 1);
}
.cf-card.cf-selected .cf-bob {
    animation: none;
    transform: translate3d(0, var(--selected-top), 0) !important;
    transition: transform 0.45s cubic-bezier(.2, .8, .2, 1);
}
.cf-card.cf-selected .cf-cover3d {
    animation: none;
    transform: rotate(0deg);
    box-shadow:
        0 0 0 2px rgba(var(--accent-primary-rgb), 0.65),
        0 24px 60px rgba(0, 0, 0, 0.45),
        0 0 60px rgba(var(--accent-primary-rgb), 0.25);
    transition: box-shadow 0.4s ease, transform 0.4s ease;
}
.cf-card.cf-selected .cf-cover-img {
    animation: none;
    filter: brightness(1.05);
}

/* Animation keyframes — same structure as CardFlow's `fall`, `sway`,
   `rockspin`, `facetilt` but operating on cover dimensions. The only
   notable difference is the brightness pulse is gentler since flat
   artwork doesn't have the plastic-slab specular highlights to
   exaggerate. */
@keyframes cf-fall {
    0%   { transform: translate3d(0, var(--sy), 0); }
    100% { transform: translate3d(0, var(--ty), 0); }
}
@keyframes cf-sway {
    0%   { transform: translate3d(var(--dx0), 0, 0); }
    35%  { transform: translate3d(var(--dx1), 0, 0); }
    68%  { transform: translate3d(var(--dx2), 0, 0); }
    100% { transform: translate3d(var(--dx3), 0, 0); }
}
@keyframes cf-rockspin {
    0%   { transform: rotate(-4deg); }
    25%  { transform: rotate(1.5deg); }
    50%  { transform: rotate(4.5deg); }
    75%  { transform: rotate(-1deg); }
    100% { transform: rotate(-4deg); }
}
@keyframes cf-facetilt {
    0%   { filter: brightness(var(--bra)); }
    35%  { filter: brightness(var(--brm)); }
    70%  { filter: brightness(var(--brb)); }
    100% { filter: brightness(var(--bra)); }
}

.grouped-view {
    display: flex;
    flex-direction: column;
    gap: 30px;
}

.group-header {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 20px;
    background: var(--bg-card);
    border-radius: 15px;
}

.group-image {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    font-weight: 700;
    color: white;
    flex-shrink: 0;
}

.group-info h2 {
    font-size: 24px;
    margin-bottom: 5px;
}

.group-info p {
    color: var(--text-secondary);
}

/* Per-kind imgClass hooks. Empty by default — the entity-tile-avatar
   in composer-view.css uses a clamp() that scales the initials with
   the tile width, so we don't need to override font-size per kind.
   Kept as named hooks in case a future skin wants to tint a specific
   kind (e.g. composer in accent, genre in cyan, etc.) without
   touching the JS that emits the class. */
.composer-img, .conductor-img, .artist-img, .genre-img {
    /* intentionally empty */
}

.albums-view-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 20px;
}

.albums-view-header h2 {
    font-size: 24px;
}

.albums-view-header p {
    color: var(--text-muted);
    font-size: 13px;
}

.qah-cover,
.np-cover,
.detail-cover,
.album-cover,
.cf-cover,
.queue-album-cover {
    background-size: cover;
    background-position: center;
}

.album-cover {
    width: 100%;
    aspect-ratio: 1;
    border-radius: 12px;
    margin-bottom: 15px;
    background: var(--bg-card);
    background-size: cover;
    background-position: center;
}

.cf-cover {
    width: 180px;
    height: 180px;
    border-radius: 12px;
    margin-bottom: 15px;
    background: var(--bg-card);
    background-size: cover;
    background-position: center;
}
