/* =================================================================
   composer-view.css — the redesigned "By Composer" view.
   Grid of composer cards, each with a header + 3-way switcher
   (Works / Albums / Songs) + scrollable body.
   ================================================================= */

.composer-cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
    gap: 20px;
    padding: 20px 24px 40px;
    align-items: start;
}

/* =================================================================
   New entity view layout — grid of tiles → full-row detail.
   Tiles show name + avatar prominently with a small teaser strip of
   album art; clicking opens a detail view that reuses the existing
   `.composer-card-body` renderers in a full-width container.
   ================================================================= */

.entity-tiles-grid {
    display: grid;
    /* Tile width + gap scale with --entity-zoom (settings → Appearance →
       Entity grid zoom). 240px at zoom 1.0 is the original (largest)
       size; smaller zoom values shrink tiles + spacing proportionally. */
    grid-template-columns: repeat(auto-fill, minmax(calc(240px * var(--entity-zoom, 1)), 1fr));
    gap: calc(18px * var(--entity-zoom, 1));
    padding: 20px 24px 40px;
    align-items: start;
}

/* Per-view favourites toolbar — sits above the tiles grid. The toggle
   pill flips the per-kind "show favourites only" scope; state is
   persisted, so each entity view (Composers, Genres, …) remembers its
   own preference independently. */
.entity-grid-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 24px 0;
}

/* "Sort: …" dropdown shared by every library view (entity grids + All
   Albums grid). Pill shape mirrors .entity-fav-toggle for visual
   consistency in the same toolbar. The <select> is unstyled-ish — we
   keep the OS native chevron to make it obviously interactive without
   reinventing a custom dropdown. */
.library-sort-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    padding: 5px 6px 5px 14px;
    font-size: 13px;
    color: var(--text-secondary);
    transition: border-color 0.15s ease, color 0.15s ease;
}
.library-sort-pill:hover,
.library-sort-pill:focus-within {
    border-color: var(--accent-primary);
    color: var(--text-primary);
}
.library-sort-label {
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    font-size: 10.5px;
    letter-spacing: 0.06em;
}
.library-sort-select {
    background: transparent;
    border: none;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    padding: 2px 24px 2px 6px;
    cursor: pointer;
    outline: none;
}
.library-sort-select:focus {
    color: var(--accent-primary);
}
.library-sort-select option {
    background: var(--bg-card);
    color: var(--text-primary);
}

/* Desktop library sorting — the old native WebKit/GTK <select> painted
   a grey inset box inside the dark pill. Keep a real select (keyboard,
   screen readers, persisted settings and mobile's own picker) but remove
   all platform chrome and give it one Auditura surface + accent focus.
   Shared by All Albums and every By Composer/Artist/Genre/etc grid on
   Linux, Windows and desktop web. Mobile is deliberately unchanged. */
.library-sort-icon { display: none; }
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill {
    position: relative;
    display: inline-flex;
    align-items: center;
    align-self: center;
    gap: 9px;
    box-sizing: border-box;
    max-width: 100%;
    min-height: 38px;
    padding: 0 12px;
    border-radius: 10px;
    border: 1px solid var(--border-subtle);
    background: var(--surface-card);
    box-shadow: none;
    color: var(--text-secondary);
    transition: border-color .16s ease, background-color .16s ease, box-shadow .16s ease;
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill:hover {
    border-color: color-mix(in srgb, var(--accent-primary) 55%, var(--border-subtle));
    background: var(--surface-card-hover);
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill:focus-within {
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-primary) 22%, transparent);
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill .library-sort-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 16px;
    color: var(--accent-primary);
    pointer-events: none;
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill .library-sort-label {
    flex: 0 0 auto;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .075em;
    color: var(--text-muted);
    white-space: nowrap;
    pointer-events: none;
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill .library-sort-select {
    /* Appearance is the important part: GTK/WebKit native select rendering
       ignores transparent backgrounds and draws its own grey button. */
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    display: block;
    flex: 0 1 auto;
    box-sizing: border-box;
    width: clamp(132px, 14vw, 194px);
    min-width: 0;
    max-width: 100%;
    height: 36px;
    margin: 0;
    padding: 0 17px 0 0;
    border: 0;
    border-radius: 0;
    outline: 0;
    background: transparent;
    background-image: none;
    box-shadow: none;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.25;
    text-overflow: ellipsis;
    cursor: pointer;
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill .library-sort-select:focus {
    color: var(--text-primary);
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill::after {
    content: '';
    position: absolute;
    right: 14px;
    top: calc(50% - 4px);
    width: 6px;
    height: 6px;
    border-right: 1.5px solid var(--text-secondary);
    border-bottom: 1.5px solid var(--text-secondary);
    transform: rotate(45deg);
    pointer-events: none;
    transition: border-color .16s ease;
}
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill:hover::after,
:is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill:focus-within::after {
    border-color: var(--accent-primary);
}
@media (max-width: 1100px) {
    :is(html:not([data-layout]), html[data-layout="desktop"]) .library-sort-pill .library-sort-select {
        width: 140px;
    }
}

/* The albums-view-header is a flex row of (title block | spacer | sort
   pill). Title + count keep their existing layout via the implicit
   block; the sort pill anchors right because it's the last child. */
.albums-view-header {
    display: flex;
    align-items: baseline;
    gap: 14px;
    flex-wrap: wrap;
}
.albums-view-header > h2 {
    flex: 0 0 auto;
}
.albums-view-header > p {
    flex: 1 1 auto;
}
.albums-view-header > .library-sort-pill {
    flex: 0 0 auto;
    margin-left: auto;
}

.entity-fav-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-card);
    border: 1px solid var(--border-subtle);
    color: var(--text-secondary);
    padding: 7px 14px;
    border-radius: 999px;
    cursor: pointer;
    font-size: 13px;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.entity-fav-toggle:hover {
    border-color: var(--accent-primary);
    color: var(--text-primary);
}
.entity-fav-toggle.active {
    background: rgba(var(--accent-primary-rgb), 0.18);
    border-color: var(--accent-primary);
    color: var(--accent-primary);
}
/* Forced-by-global state — the global Favourites switch is on, so
   the per-kind toggle is functionally redundant. Show it as still
   "active" but visually disabled so the user understands why
   clicking does nothing. */
.entity-fav-toggle.forced-by-global {
    cursor: not-allowed;
    opacity: 0.7;
}
.entity-fav-toggle-heart {
    font-size: 15px;
    line-height: 1;
}
.entity-fav-toggle-count {
    background: var(--overlay-active);
    color: var(--text-muted);
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
}
.entity-fav-toggle.active .entity-fav-toggle-count {
    background: rgba(var(--accent-primary-rgb), 0.3);
    color: var(--accent-primary);
}

.entity-fav-empty {
    padding: 22px 24px 4px;
    color: var(--text-muted);
    font-size: 13px;
}

/* Heart toggle on each tile. Positioned over the avatar's top-right
   corner so it's reachable without obscuring the name/meta block. */
.entity-tile { position: relative; }

.entity-tile-heart {
    position: absolute;
    /* Anchor inside the avatar's rounded corner. tile padding is 14px on
       all sides above the avatar, so 22px = 14px tile padding + 8px from
       the avatar's edge. */
    top: 22px;
    right: 22px;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: none;
    background: rgba(var(--surface-app-rgb), 0.55);
    color: var(--text-primary);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, color 0.15s, transform 0.1s;
    backdrop-filter: blur(2px);
}
/* Invisible hit-area expansion to ~44×44. The visible disc stays at
   28×28 but the click target is now 8px larger on every side, which
   absorbs the small aiming errors that used to hit the tile background
   (and thus open the conductor instead of toggling the heart). */
.entity-tile-heart::before {
    content: '';
    position: absolute;
    inset: -8px;
    border-radius: 50%;
}
.entity-tile-heart:hover {
    background-color: rgba(var(--surface-app-rgb), 0.85);
    color: var(--accent-primary);
    transform: scale(1.08);
}
.entity-tile-heart.liked {
    color: var(--accent-primary);
}
.entity-tile-heart.liked:hover {
    color: var(--text-on-accent);
    background-color: rgba(var(--accent-primary-rgb), 0.85);
}

/* When the cursor is inside the heart's hit area, freeze the parent
   tile's lift/border-glow effect. The tile's translateY(-2px) on
   :hover used to move the absolutely-positioned heart by 2px just as
   the user was targeting it — combined with the 28px disc this caused
   "click next to the heart, conductor opens" misses. */
.entity-tile:has(.entity-tile-heart:hover) {
    transform: none;
    border-color: var(--border-subtle);
    box-shadow: none;
}
.entity-tile:has(.entity-tile-heart:hover) .entity-tile-teaser-track {
    animation-duration: 36s;
}

.entity-tile {
    background: var(--bg-sidebar);
    border: 1px solid var(--border-subtle);
    border-radius: 14px;
    cursor: pointer;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
    outline: none;
    /* Inner padding around the avatar so the rounded-square placeholder
       doesn't run flush against the tile's outer rounded corners — gives
       the placeholder its own visual identity, like an album cover
       inside a card. */
    padding: 14px 14px 0;
    /* No content-visibility: auto here — the cached intrinsic-size cache
       drifts whenever a tile's children mutate (lazy-loaded avatar
       arriving, teaser thumbnails decoding, IntersectionObserver swaps),
       and every cache update reflows the column. That manifested as the
       page randomly nudging up/down a few px even while stationary.
       windowedGrid already caps the rendered tile count to one page
       (100) until the user scrolls, which is enough to keep paint cost
       bounded; the small extra paint bill on huge libraries is worth the
       stable layout. */
}

.entity-tile:hover,
.entity-tile:focus-visible {
    transform: translateY(-2px);
    border-color: var(--accent-primary);
    box-shadow: var(--shadow-md);
}

.entity-tile-avatar {
    /* Explicit width:100% forces the avatar to fill the tile's content
       column. Without this, aspect-ratio:1 on a flex item with no width
       only sizes the box to its text content — which made 2-letter
       initials ("AL") render a tiny square while 4-letter genre tags
       ("ANIM") rendered a bigger one. Now every tile's avatar is the
       same full-width square regardless of the avatar text length. */
    width: 100%;
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Rounded-square placeholder, matching the album-cover look. */
    border-radius: 12px;
    /* Bigger initials so the larger surface area doesn't read as "lots
       of empty paint". Specific entity types still override via their
       imgClass rule (composer-img / artist-img / genre-img / etc.) if
       they want a different scale. */
    font-size: clamp(48px, 18cqw, 88px);
    font-weight: 700;
    color: var(--text-on-accent);
    letter-spacing: 0.04em;
    text-shadow: var(--shadow-sm);
    container-type: inline-size;
    /* Subtle inset shadow so the placeholder reads as a distinct card
       layer on top of the tile, not painted-on background. */
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28),
                inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

.entity-tile-info {
    padding: 12px 14px 10px;
}

.entity-tile-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.25;
    /* Clamp to 2 lines with ellipsis. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.entity-tile-meta {
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 3px;
}

/* Album-art teaser strip: auto-scrolls horizontally via a CSS keyframe.
   The track contains the album covers twice so the translate loops seamlessly. */
.entity-tile-teaser {
    overflow: hidden;
    border-top: 1px solid var(--border-subtle);
    background: var(--overlay-active);
    height: 44px;
    mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
    -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
}

.entity-tile-teaser-track {
    display: flex;
    gap: 4px;
    padding: 5px 4px;
    width: max-content;
    animation: entity-tile-scroll 36s linear infinite;
}

.entity-tile:hover .entity-tile-teaser-track {
    animation-duration: 14s;
}

.ett-thumb {
    display: inline-block;
    width: 34px;
    height: 34px;
    background-size: cover;
    background-position: center;
    background-color: var(--bg-card);
    border-radius: 5px;
    flex: 0 0 auto;
}

@keyframes entity-tile-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* ---- Detail view (opened by clicking a tile) ----
   Takes the full width of the main column; no inner max-width cap. The
   parent `.view-section` already has the outer padding from base.css. */
.entity-detail {
    width: 100%;
    padding: 18px 24px 40px;
    box-sizing: border-box;
}

/* Breadcrumb navigator — one crumb per drill level. Each crumb has an
   uppercase role label on top and the selected value italicized below. */
.entity-nav-bar {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 22px;
    padding: 10px 14px;
    background: rgba(var(--accent-primary-rgb), 0.05);
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
}

.entity-nav-crumb {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    background: transparent;
    border: none;
    padding: 4px 10px;
    border-radius: 6px;
    color: var(--text-secondary);
    cursor: pointer;
    text-align: left;
    transition: background 0.15s, color 0.15s;
    min-width: 0;
}

.entity-nav-crumb:hover:not([disabled]) {
    background: var(--overlay-selected);
    color: var(--text-primary);
}

.entity-nav-crumb[disabled] {
    cursor: default;
    color: var(--text-primary);
}

.entity-nav-crumb .enc-label {
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--text-muted);
    line-height: 1;
}

.entity-nav-crumb[disabled] .enc-label {
    color: var(--accent-primary);
}

.entity-nav-crumb .enc-value {
    font-size: 13px;
    font-style: italic;
    line-height: 1.2;
    margin-top: 3px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 260px;
}

.entity-nav-sep {
    display: flex;
    align-items: center;
    color: var(--text-muted);
    font-size: 18px;
    user-select: none;
}

.entity-detail-header {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 8px 0 22px;
    border-bottom: 1px solid var(--border-subtle);
    margin-bottom: 22px;
}

.entity-detail-avatar {
    width: 104px;
    height: 104px;
    border-radius: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 36px;
    font-weight: 700;
    color: var(--text-on-accent);
    flex: 0 0 auto;
    box-shadow: var(--shadow-md);
}

.entity-detail-title {
    min-width: 0;
}

.entity-detail-title h2 {
    font-size: 28px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.15;
    margin: 0;
}

.entity-detail-title p {
    font-size: 13px;
    color: var(--text-muted);
    margin-top: 6px;
}

/* Mode switcher / grouping switcher — full-width pill bar. */
.entity-detail-switcher {
    margin-bottom: 24px;
    padding: 0;
    border-bottom: none;
    width: 100%;
}

.entity-detail-switcher .ccsw-btn {
    padding: 10px 14px;
    font-size: 13px;
}

/* The body grows as tall as its content — no cap. Use the full column width. */
.entity-detail-body {
    width: 100%;
    overflow: visible;
    padding: 0;
}

/* Albums grid inside the detail uses the main library-grid sizing. */
.entity-detail .composer-card-albums,
.entity-detail .albums-grid.composer-card-albums {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(calc(180px * var(--grid-zoom, 1)), 1fr));
    gap: calc(16px * var(--grid-zoom, 1));
}

/* The full-width works grid inside the detail also uses normal sizing. */
.entity-detail .works-rec-grid {
    grid-template-columns: repeat(auto-fill, minmax(calc(200px * var(--grid-zoom, 1)), 1fr));
    gap: calc(18px * var(--grid-zoom, 1));
}

/* Level 2 grouped view — big person card, small album thumbs beneath. One
   "row" per person in a responsive grid; clicking an album thumb opens
   the album detail (terminal depth). */
.work-person-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
    gap: 20px;
    align-items: start;
}

.work-person-card {
    background: var(--bg-sidebar);
    border: 1px solid var(--border-subtle);
    border-radius: 14px;
    padding: 16px 18px 18px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.wpc-header {
    display: flex;
    align-items: center;
    gap: 14px;
}

.wpc-avatar {
    width: 72px;
    height: 72px;
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    font-weight: 700;
    color: var(--text-on-accent);
    flex: 0 0 auto;
    box-shadow: var(--shadow-sm);
}

.wpc-info {
    min-width: 0;
    flex: 1;
}

.wpc-name {
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wpc-meta {
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 3px;
}

/* Row of small album thumbs under the person header. Wraps when there
   are more recordings than fit in one row. */
.wpc-albums {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.wpa-thumb {
    width: 62px;
    height: 62px;
    border-radius: 8px;
    background-color: var(--bg-card);
    background-size: cover;
    background-position: center;
    cursor: pointer;
    flex: 0 0 auto;
    position: relative;
    transition: transform 0.12s, box-shadow 0.12s;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
}

.wpa-thumb:hover {
    transform: scale(1.06);
    box-shadow: 0 4px 14px rgba(var(--accent-primary-rgb), 0.4);
}

.wpa-thumb-placeholder {
    opacity: 0.7;
}

.composer-card {
    background: var(--bg-sidebar);
    border: 1px solid var(--border-subtle);
    border-radius: 16px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    max-height: 640px;
}

.composer-card-header {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px 18px;
    border-bottom: 1px solid var(--border-subtle);
    background: linear-gradient(180deg, rgba(var(--accent-primary-rgb), 0.05), transparent 80%);
}

.composer-card-header .group-image {
    width: 56px;
    height: 56px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 18px;
    color: var(--text-on-accent);
    flex: 0 0 auto;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.composer-card-title {
    min-width: 0;    /* let h2 truncate */
    flex: 1 1 auto;
}

.composer-card-title h2 {
    font-size: 17px;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.2;
    margin: 0;
}

.composer-card-title p {
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 2px;
}

/* ---- 3-way switcher pill ---- */
.composer-card-switcher {
    display: flex;
    gap: 0;
    padding: 10px 18px 6px;
    border-bottom: 1px solid var(--border-subtle);
}

.composer-card-switcher .ccsw-btn {
    flex: 1;
    background: transparent;
    border: 1px solid var(--border-subtle);
    color: var(--text-secondary);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    padding: 6px 10px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.composer-card-switcher .ccsw-btn:first-child {
    border-radius: 6px 0 0 6px;
}

.composer-card-switcher .ccsw-btn:last-child {
    border-radius: 0 6px 6px 0;
}

.composer-card-switcher .ccsw-btn + .ccsw-btn {
    border-left: none;
}

.composer-card-switcher .ccsw-btn:hover {
    color: var(--text-primary);
    background: rgba(255, 255, 255, 0.04);
}

.composer-card-switcher .ccsw-btn.active {
    background: var(--accent-primary);
    color: var(--text-on-accent);
    border-color: var(--accent-primary);
}

/* ---- Body ---- */
.composer-card-body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 14px 18px 18px;
    min-height: 0;
}

.composer-card-empty {
    padding: 20px 0;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
}

/* Albums grid inside a composer card — smaller than the main library grid
   so more fit per card. */
.composer-card-albums {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
    gap: 12px;
    padding: 0;
}

.composer-card-albums .album-card {
    font-size: 12px;
}

/* Works list — dense masonry packing that still READS row-major
   (left → right, top → bottom). CSS multi-column packs densely but fills
   column-first; grid rows leave gaps under short cards. So the JS below
   splits the sorted rows into explicit column divs (column c holds items
   c, c+C, c+2C…): each column stacks tightly like masonry, while visual
   rows read in sorted order. Column count follows the same 460px minimum
   and re-splits on resize. */
.composer-card-works {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

.cwr-col {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.composer-work-row {
    background: var(--bg-card);
    border-radius: 8px;
    transition: background 0.15s;
    border-left: 3px solid transparent;
}

.composer-work-row:hover {
    background: var(--bg-card-hover);
    border-left-color: var(--accent-primary);
}

.cwr-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    cursor: pointer;
    user-select: none;
}

.cwr-head:active {
    transform: scale(0.998);
}

/* Chevron is its own button so its click doesn't bubble into the row's
   drill-into-work handler — the user can expand without leaving the page. */
.cwr-chevron {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 0;
    padding: 0;
    color: var(--text-muted);
    font-size: 10px;
    cursor: pointer;
    border-radius: 3px;
    transition: transform 0.18s ease, color 0.15s, background 0.15s;
    transform-origin: 50% 50%;
}

.cwr-chevron:hover {
    color: var(--accent-primary);
    background: rgba(var(--accent-primary-rgb), 0.10);
}

.cwr-chevron-placeholder {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
}

.composer-work-row.expanded .cwr-chevron {
    transform: rotate(90deg);
    color: var(--accent-primary);
}

.cwr-head-text {
    flex: 1 1 auto;
    min-width: 0;
}

.cwr-title {
    font-size: 13px;
    color: var(--text-primary);
    font-weight: 500;
    line-height: 1.3;
}

.cwr-meta {
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 3px;
    font-variant-numeric: tabular-nums;
}

/* Body — collapsed by default, slides in via expanded class. The max-
   height ceiling fits a long work (Goldberg Variations' 30+ entries)
   without clipping. */
.cwr-body {
    overflow: hidden;
    max-height: 0;
    transition: max-height 0.25s ease;
}

.composer-work-row.expanded .cwr-body {
    max-height: 2400px;
    padding: 2px 12px 8px 38px;
}

/* Movement rows — pure drill targets. Clicking pushes a 'movement'
   frame onto the nav stack, same as a work click but one level deeper.
   No file/track surface here; the Songs tab is where playable rows
   live. */
.cwr-movement-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 5px 8px;
    border-radius: 5px;
    cursor: pointer;
    color: var(--text-secondary);
    transition: background 0.12s, color 0.12s;
}

.cwr-movement-row:hover {
    background: var(--overlay-hover);
    color: var(--text-primary);
}

.cwr-movement-row:active {
    transform: scale(0.998);
}

.cwr-movement-title {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 11.5px;
    font-weight: 500;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cwr-movement-meta {
    flex: 0 0 auto;
    font-size: 10px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
}

/* Songs list — compact rows. */
.composer-card-songs {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.composer-song-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 12px;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s;
}

/* =================================================================
   All Songs view — uses the album-detail track-row visual but
   sectioned per (album, disc). Each section reads as a mini album
   block: small cover thumbnail + album title (with disc suffix when
   the album has more than one) + meta line, followed by the actual
   tracks rendered with `.detail-track-item`.
   ================================================================= */
.all-songs-list {
    display: flex;
    flex-direction: column;
    gap: 26px;
}
.all-songs-section {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.all-songs-section-head {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 6px 4px 8px;
    border-bottom: 1px solid var(--border-subtle);
}
.all-songs-section-cover {
    width: 64px;
    height: 64px;
    border-radius: 6px;
    background-color: var(--bg-card);
    background-size: cover;
    background-position: center;
    flex: 0 0 auto;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
}
.all-songs-section-title {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.25;
}
.all-songs-section-meta {
    margin-top: 4px;
    font-size: 12px;
    font-weight: 400;
    color: var(--text-muted);
}
.all-songs-disc {
    color: var(--text-muted);
    font-weight: 500;
    font-size: 14px;
}
.all-songs-tracks {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* Force the all-songs rows onto a single line — the album-detail
   panel's own .detail-track-item wraps in a narrow side panel; here
   we have full-width and the track number / title / duration should
   sit on one row. */
.all-songs-track {
    flex-wrap: nowrap;
}

.composer-song-row:hover {
    background: var(--bg-card-hover);
}

.csr-title {
    font-size: 13px;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1 1 auto;
    min-width: 0;
}

.csr-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.csr-album {
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Playlists body — rows of matching playlists. */
.composer-card-playlists {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.composer-playlist-row {
    padding: 10px 12px;
    background: var(--bg-card);
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s;
    border-left: 3px solid transparent;
}

.composer-playlist-row:hover {
    background: var(--bg-card-hover);
    border-left-color: var(--accent-cyan);
}

.cpr-title {
    font-size: 13px;
    color: var(--text-primary);
    font-weight: 500;
}

.cpr-meta {
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 3px;
}

/* Per-entity default-mode rows in Settings — label left, dropdown right. */
.prefs-entity-row {
    display: grid;
    grid-template-columns: 1fr 180px;
    align-items: center;
    gap: 12px;
}

.prefs-entity-row .prefs-label {
    margin: 0;
}

/* All Playlists grid — top-level view that lists every playlist as a card. */
.all-playlists-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 14px;
    padding: 20px 24px 40px;
}

.all-playlist-card {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    background: var(--bg-sidebar);
    border: 1px solid var(--border-subtle);
    border-radius: 12px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, transform 0.12s;
}

.all-playlist-card:hover {
    border-color: var(--accent-primary);
    transform: translateY(-1px);
}

.all-playlist-card .apc-icon {
    width: 48px;
    height: 48px;
    border-radius: 10px;
    color: var(--text-on-accent);
    font-weight: 700;
    font-size: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.all-playlist-card .apc-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.all-playlist-card .apc-meta {
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 2px;
}

/* Track-list-view title used by All Songs and similar flat lists. */
.track-list-view .track-list-title {
    font-size: 22px;
    font-weight: 700;
    color: var(--text-primary);
    padding: 18px 24px 6px;
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.track-list-view .track-list-count {
    font-size: 12px;
    color: var(--text-muted);
    font-weight: 500;
}

.track-list-view .track-list-rows {
    padding: 4px 24px 40px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Conductor / Composer list body — used by the Label card's "Conductor"
   and "Composer" modes. Each row navigates to the corresponding By-X view
   and scrolls to that person's card. */
.composer-card-people {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.composer-person-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    background: var(--bg-card);
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s;
    border-left: 3px solid transparent;
}

.composer-person-row:hover {
    background: var(--bg-card-hover);
    border-left-color: var(--accent-primary);
}

.cpr-avatar {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    color: var(--text-on-accent);
    font-size: 12px;
    flex: 0 0 auto;
}

.cpr-text {
    min-width: 0;
    flex: 1;
}

.cpr-name {
    font-size: 13px;
    color: var(--text-primary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cpr-meta {
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 1px;
}

/* Brief highlight when a card is navigated to from a cross-view click. */
@keyframes composer-card-flash {
    0%   { box-shadow: 0 0 0 3px rgba(var(--accent-primary-rgb), 0.8); }
    100% { box-shadow: 0 0 0 0 rgba(var(--accent-primary-rgb), 0); }
}

.composer-card.composer-card-flash {
    animation: composer-card-flash 1.2s ease-out;
}

/* Work drill-down inside an entity card — takes the place of the works list
   after a click on a work row. Replaces the composer-card body content. */
.composer-work-drilldown {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.composer-work-drilldown .cwd-back-btn {
    align-self: flex-start;
    background: transparent;
    border: 1px solid var(--border-subtle);
    color: var(--text-secondary);
    font-size: 12px;
    padding: 4px 10px;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.composer-work-drilldown .cwd-back-btn:hover {
    background: var(--bg-card-hover);
    color: var(--text-primary);
}

.composer-work-drilldown .cwd-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.25;
}

/* Shrink the in-card pill switcher so four pills fit comfortably in a
   narrow card body. */
.composer-work-drilldown .works-group-switcher {
    margin: 0;
}

.composer-work-drilldown .works-group-switcher .wgs-btn {
    font-size: 10.5px;
    padding: 6px 6px;
    letter-spacing: 0.02em;
}

/* The inner album-cards grid inside a drill-down uses smaller cards than
   the full-screen By Works view — the parent card body is already narrow. */
.composer-work-drilldown .works-rec-grid {
    grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
    gap: 10px;
}

.composer-work-drilldown .works-rec-card {
    padding: 6px;
}

.composer-work-drilldown .works-rec-card .works-rec-title {
    font-size: 12px;
}

.composer-work-drilldown .works-rec-card .works-rec-sub {
    font-size: 10.5px;
}

/* When the user groups by conductor/performer/artist inside a drill-down,
   the group headers + nested grids follow the same smaller scale. */
.composer-work-drilldown .works-group-block {
    margin-bottom: 16px;
}

.composer-work-drilldown .works-group-header h3 {
    font-size: 13px;
}

.composer-work-drilldown .works-group-header p {
    font-size: 11px;
}

.composer-work-drilldown .works-group-avatar {
    width: 34px;
    height: 34px;
    font-size: 12px;
}

/* ============================================================
   Per-page search box (F3) — one compact input at the grid level
   of every entity view and on every drill-down frame. Sits between
   the toolbar / mode pill bar and the body. Queries persist per
   drill path (see filterPage.js) and filter the page in place.
   ============================================================ */
.entity-page-search {
    display: flex;
    align-items: center;
    padding: 12px 24px 0;
}

.entity-page-search .eps-wrap {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 560px;
    max-width: 560px;
}

.entity-page-search .eps-icon {
    position: absolute;
    left: 14px;
    display: inline-flex;
    align-items: center;
    color: var(--text-muted);
    pointer-events: none;
}

.entity-page-search-input {
    flex: 1;
    width: 100%;
    padding: 10px 16px 10px 40px;
    border-radius: 999px;
    border: 1px solid var(--border-subtle);
    background: var(--bg-card);
    color: var(--text-primary);
    font-size: 13.5px;
    font-family: inherit;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.entity-page-search-input::placeholder {
    color: var(--text-muted);
}

.entity-page-search-input:focus {
    outline: none;
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 2px rgba(var(--accent-primary-rgb), 0.18);
}

.entity-page-search-none {
    padding: 20px 24px;
    color: var(--text-muted);
    font-size: 13px;
    font-style: italic;
}

/* Works-tab toolbar: collapse-all / expand-all, right-aligned above the
   work cards. Ghost-button styling matches the view's quiet chrome. */
.cwr-toolbar {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 12px;
    padding: 10px 24px 0;
}

.cwr-hint {
    margin-right: auto;
    font-size: 11.5px;
    font-style: italic;
    color: var(--text-muted);
}

.cwr-collapse-all {
    border: 1px solid var(--border-color, rgba(255,255,255,0.12));
    background: transparent;
    color: var(--text-secondary, #9aa0ac);
    font-size: 12px;
    border-radius: 8px;
    padding: 5px 12px;
    cursor: pointer;
    transition: all 0.15s;
    font-family: inherit;
}

.cwr-collapse-all:hover {
    color: var(--text-primary, #fff);
    border-color: var(--text-secondary, #9aa0ac);
    background: rgba(255,255,255,0.04);
}

/* Works rows carry a first-recording thumbnail for the phone list layout
   (web-mobile.css); the desktop row keeps its text-only design. */
.cwr-thumb {
    display: none;
}
/* Optional entity description (filterPage.js, getEntityDescription hook). */
.entity-detail-desc {
    margin: 6px 0 0;
    color: var(--text-secondary);
    font-size: 0.85rem;
    line-height: 1.4;
}

/* =====================================================================
   Phase 2 — Entity descriptions (ONLY the grouped-library detail pages).
   Descriptions never render in the album-detail sidebar or for movements.
   ===================================================================== */
.entity-description-slot {
    max-width: min(760px, 100%);
    margin-top: 10px;
    min-width: 0;
}
.entity-description-slot:empty { display: none; }
.entity-description-slot .entity-desc-preview {
    color: var(--text-secondary);
    font-size: 13px;
    line-height: 1.6;
    white-space: pre-line;
    overflow-wrap: anywhere;
    margin: 0;
}
.entity-description-slot [hidden], .entity-desc-modal [hidden] { display: none !important; }
.entity-desc-actions { display: flex; align-items: center; gap: 14px; margin-top: 5px; }
.entity-desc-link {
    border: 0;
    background: none;
    padding: 2px 0;
    cursor: pointer;
    color: var(--accent-primary);
    font-size: 12px;
    font-weight: 600;
    text-align: left;
}
.entity-desc-link:hover { text-decoration: underline; }
.entity-desc-link:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 3px; }
.entity-desc-add { color: var(--text-secondary); }
.entity-desc-edit { color: var(--text-secondary); }
.entity-desc-rich { font-size: 13px; line-height: 1.65; color: var(--text-secondary); overflow-wrap: anywhere; }
.entity-desc-rich p { color: inherit; font-size: inherit; line-height: inherit; margin: 0 0 8px; }
.entity-desc-rich h2 { font-size: 17px; line-height: 1.4; color: var(--text-primary); margin: 14px 0 6px; }
.entity-desc-rich h3 { font-size: 15px; line-height: 1.4; color: var(--text-primary); margin: 12px 0 5px; }
.entity-desc-rich ul, .entity-desc-rich ol { padding-left: 23px; margin: 5px 0 12px; }
.entity-desc-rich blockquote { border-left: 3px solid var(--accent-primary); padding-left: 12px; margin: 10px 0; }
.entity-desc-rich hr { border: 0; border-top: 1px solid var(--border-subtle); margin: 12px 0; }
.entity-desc-rich a { color: var(--accent-primary); text-decoration: underline; }

.entity-desc-modal {
    position: fixed;
    inset: 0;
    z-index: 17000;
    background: var(--surface-overlay);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
}
.entity-desc-dialog {
    background: var(--surface-elevated);
    color: var(--text-primary);
    width: min(780px, 100%);
    max-height: min(90vh, 960px);
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border-strong);
    border-radius: 12px;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}
.entity-desc-modal-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 20px 22px 14px;
}
.entity-desc-modal-header h2 { font-size: 20px; margin: 0; }
.entity-desc-modal-header .ed-subtitle { font-size: 12px; margin-top: 5px; color: var(--text-secondary); }
.entity-desc-modal button {
    cursor: pointer;
    border-radius: 5px;
    color: var(--text-primary);
    background: transparent;
    border: 1px solid transparent;
}
.entity-desc-modal button:hover:not(:disabled) { background: var(--overlay-hover); }
.entity-desc-modal button:focus-visible { outline: 2px solid var(--border-focus); outline-offset: 1px; }
.entity-desc-modal button:disabled { opacity: .45; cursor: wait; }
.entity-desc-modal .ed-close { font-size: 25px; padding: 0 9px; color: var(--text-secondary); }
.entity-desc-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 3px;
    padding: 8px 17px;
    border-top: 1px solid var(--border-subtle);
    border-bottom: 1px solid var(--border-subtle);
}
.entity-desc-toolbar button { min-width: 33px; height: 32px; padding: 5px 8px; font-size: 12px; }
.entity-desc-toolbar .ed-separator { height: 23px; width: 1px; background: var(--border-strong); margin: 0 4px; }
.entity-desc-editable {
    margin: 0;
    padding: 20px 24px;
    overflow: auto;
    min-height: 210px;
    flex: 1;
    outline: none;
    font-size: 14px;
    line-height: 1.7;
    overflow-wrap: anywhere;
    user-select: text;
    -webkit-user-select: text;
}
.entity-desc-editable:focus { box-shadow: inset 0 0 0 1px var(--border-focus); }
.entity-desc-editable:empty::before { content: attr(data-placeholder); color: var(--text-muted); pointer-events: none; }
.entity-desc-editable p { margin: 0 0 9px; }
.entity-desc-editable h2 { font-size: 20px; margin: 12px 0; }
.entity-desc-editable h3 { font-size: 17px; margin: 12px 0; }
.entity-desc-editable ul, .entity-desc-editable ol { padding-left: 26px; margin: 9px 0; }
.entity-desc-editable blockquote { padding-left: 13px; margin: 11px 0; border-left: 3px solid var(--accent-primary); }
.entity-desc-editable a { color: var(--accent-primary); }
.entity-desc-message { min-height: 22px; color: var(--text-secondary); font-size: 12px; padding: 3px 22px; }
.entity-desc-modal-footer {
    display: flex;
    gap: 10px;
    align-items: center;
    border-top: 1px solid var(--border-subtle);
    padding: 14px 22px;
}
.entity-desc-modal-footer button { padding: 9px 14px; font-size: 13px; border: 1px solid var(--border-strong); }
.entity-desc-modal-footer .ed-delete { color: var(--state-danger); border-color: transparent; }
.entity-desc-modal-footer .ed-save { background: var(--accent-primary); color: var(--text-on-accent); border-color: transparent; }
.entity-desc-modal-footer .ed-save:hover:not(:disabled) { filter: brightness(1.1); background: var(--accent-primary); }
.entity-desc-modal-footer .ed-grow { flex: 1; }
@media (max-width: 650px) {
    .entity-desc-modal { padding: 0; }
    .entity-desc-dialog { width: 100%; height: 100%; max-height: 100%; border-radius: 0; }
    .entity-desc-modal-header { padding: 15px 16px 10px; }
    .entity-desc-editable { padding: 14px 16px; min-height: 100px; }
    .entity-desc-toolbar { padding: 7px; }
    .entity-desc-modal-footer { padding: 12px; }
}


/* ================================================================
   Desktop entity detail — match Auditura's underlined navigation.
   No segmented yellow fill: Works / Albums / Songs / Playlists and
   every other entity facet share one quiet tab rail. The phone layout
   retains its own rules in tiny-mobile.css / web-mobile.css.
   ================================================================ */
:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-detail-switcher {
    display: flex;
    align-items: stretch;
    width: 100%;
    gap: 0;
    padding: 0;
    margin: 10px 0 23px;
    border: 0;
    border-bottom: 1px solid var(--border-subtle);
    border-radius: 0;
    background: transparent;
    overflow-x: auto;
    scrollbar-width: thin;
}

:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-detail-switcher .ccsw-btn {
    flex: 1 0 auto;
    position: relative;
    min-width: 110px;
    min-height: 45px;
    padding: 10px 18px;
    margin: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    color: var(--text-secondary);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    cursor: pointer;
    transition: color 150ms ease;
}

:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-detail-switcher .ccsw-btn + .ccsw-btn {
    border-left: 0;
}

:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-detail-switcher .ccsw-btn:hover {
    background: transparent;
    color: var(--text-primary);
}

:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-detail-switcher .ccsw-btn.active {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    color: var(--accent-primary);
    font-weight: 700;
}

:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-detail-switcher .ccsw-btn.active::after {
    content: "";
    position: absolute;
    left: 22%;
    right: 22%;
    bottom: 0;
    height: 3px;
    border-radius: 3px 3px 0 0;
    background: var(--accent-primary);
    pointer-events: none;
}

:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-detail-switcher .ccsw-btn:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: -4px;
}

/* Search current view (header) is the only VISIBLE desktop search field.
   The entity renderer still owns an internal input to filter virtualised
   entity grids and nested detail tabs correctly. search.js forwards the
   header query to it, so hiding its chrome does not lose functionality.
   Mobile keeps its existing layout-specific visibility and search wiring. */
:is(html:not([data-layout]), html[data-layout="desktop"]) .entity-page-search {
    display: none !important;
}
