/*
 * The look of each <nessie-…> component (js/components/), in the order they appear on screen.
 * Colours come only from theme variables (themes.css), so every theme reaches every component.
 */

/* Custom elements are inline by default: these are blocks, so wide content inside them (a
   scrolling row of cards) scrolls instead of stretching the page */
nessie-view-header,
nessie-track-list,
nessie-media-grid,
nessie-pager,
nessie-empty-state,
nessie-sidebar,
nessie-queue,
nessie-now-playing,
nessie-folder-picker,
nessie-scan-progress,
nessie-dialog,
nessie-description {
    display: block;
    min-width: 0;
}

/* --- <nessie-artwork>: a square cover, or an icon on a surface when there isn't one --- */

nessie-artwork {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    aspect-ratio: 1;
    overflow: hidden;
    border-radius: var(--bs-border-radius);
    background: linear-gradient(135deg, rgba(var(--bs-secondary-rgb), 0.55), rgba(var(--bs-primary-rgb), 0.25));
    color: var(--bs-primary-text-emphasis);
    container-type: inline-size;  /* so the icon below can size itself to the cover */
}

/* Pinned to the box's edges: Safari doesn't resolve height: 100% inside an aspect-ratio box,
   and drew a 40×300 image there, cropped to a zoomed-in strip */
nessie-artwork img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

nessie-artwork .bi {
    font-size: 40cqi;  /* 40% of the cover's width */
    line-height: 1;
    opacity: 0.85;
}

/* --- <nessie-sidebar> --- */

.app-nav {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    width: 100%;
}

.app-nav-list {
    list-style: none;
    margin: 0 0 0.75rem;
    padding: 0;
}

.app-nav-heading {
    margin: 0.75rem 0.75rem 0.25rem;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
}

/* Other libraries (a profile's not-mine ones): a heading that folds them away */
.app-nav-toggle {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: calc(100% - 1.5rem);
    padding: 0;
    border: 0;
    background: none;
    text-align: start;
}

.app-nav-toggle:hover {
    color: var(--bs-body-color);
}

.app-nav-toggle .bi-chevron-right {
    transition: transform 0.15s ease;
}

.app-nav-toggle[aria-expanded="true"] .bi-chevron-right {
    transform: rotate(90deg);
}

.app-nav-link {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.45rem 0.75rem;
    border-radius: var(--bs-border-radius-lg);
    color: var(--bs-body-color);
    text-decoration: none;
    transition: background-color 0.15s;
}

.app-nav-link:hover {
    background-color: var(--bs-secondary-bg-subtle);
    color: var(--bs-body-color);
}

.app-nav-link.active {
    background-color: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    font-weight: 600;
}

.app-nav-link .bi {
    font-size: 1.1rem;
    width: 1.25rem;
    text-align: center;
}

.app-nav-count {
    margin-left: auto;
    padding: 0 0.5rem;
    border-radius: 50rem;
    font-size: 0.75rem;
    background-color: var(--bs-secondary-bg-subtle);
    color: var(--bs-secondary-color);
}

.app-nav-empty {
    padding: 0.75rem;
    color: var(--bs-secondary-color);
}

.app-nav-footer {
    margin-top: auto;
    padding-top: 0.75rem;
    border-top: var(--bs-border-width) solid var(--bs-border-color);
}

/* --- <nessie-view-header> --- */

.view-header {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin-bottom: 1.25rem;
}

.view-header-hero {
    flex-direction: row;
    align-items: flex-end;
    gap: 1.5rem;
    margin-bottom: 1.75rem;
}

.view-header-art {
    width: clamp(7rem, 28vw, 14rem);
    box-shadow: 0 1rem 2.5rem rgba(0, 0, 0, 0.35), var(--nessie-glow);
}

nessie-view-header.view-header-round .view-header-art {
    border-radius: 50%;
}

.view-header-text {
    min-width: 0;
}

.view-header-eyebrow {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bs-primary-text-emphasis);
    text-shadow: var(--nessie-text-glow);
}

.view-header-title {
    margin: 0.15rem 0 0.35rem;
    font-weight: 800;
    font-size: clamp(1.6rem, 4vw, 2.75rem);
    line-height: 1.1;
    overflow-wrap: anywhere;
}

.view-header-title:focus {
    outline: none;
}

.view-header-subtitle {
    color: var(--bs-secondary-color);
}

.view-header-subtitle a {
    color: var(--bs-body-color);
    font-weight: 600;
    text-decoration: none;
}

.view-header-subtitle a:hover {
    text-decoration: underline;
}

.view-header-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1rem;
}

/* A phone: the cover above the text, full width actions */
@media (max-width: 575.98px) {
    .view-header-hero {
        flex-direction: column;
        align-items: center;
        text-align: center;
    }

    .view-header-hero .view-header-actions {
        justify-content: center;
    }
}

/* Who took a photo, where its source asks for credit (Wikimedia Commons, Fanart.tv) */
.image-credit {
    margin-top: -1rem;
    margin-bottom: 1.5rem;
    font-size: 0.75rem;
    color: var(--bs-tertiary-color, var(--bs-secondary-color));
}

.view-description {
    max-width: 48rem;
    color: var(--bs-secondary-color);
}

/* --- Lists: toolbar, section headings, loading, empty --- */

.list-toolbar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.75rem;
}

.list-sort {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--bs-secondary-color);
}

.list-sort .form-select {
    width: auto;
}

.home-section {
    margin-bottom: 2rem;
}

.section-heading {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.75rem;
}

.section-heading h2 {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 700;
}

.section-heading a {
    font-size: 0.875rem;
    text-decoration: none;
}

.view-loading {
    display: flex;
    justify-content: center;
    padding: 4rem 0;
}

/* Profiles: initials in a circle, each profile its own colour (nessie-profile-picker.js's avatar()) */
.profile-avatar {
    display: inline-grid;
    place-items: center;
    flex: none;
    border-radius: 50%;
    font-weight: 700;
    color: #fff;
    background: hsl(var(--profile-hue, 200) 55% 42%);
}

.profile-avatar-sm { width: 2rem; height: 2rem; font-size: 0.95rem; }
.profile-avatar-md { width: 2.5rem; height: 2.5rem; font-size: 1.1rem; }
.profile-avatar-lg { width: 5.5rem; height: 5.5rem; font-size: 2.25rem; }

.profile-menu-button {
    padding: 0.15rem;
}

/* "Who's listening?": over everything until a profile is picked */
.profile-picker {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: grid;
    place-items: center;
    padding: 1.5rem;
    overflow-y: auto;
    background: var(--bs-body-bg);
}

.profile-picker[hidden] {
    display: none;
}

.profile-picker-inner {
    width: min(100%, 40rem);
    text-align: center;
}

.profile-picker-logo {
    border-radius: 1rem;
    margin-bottom: 1.25rem;
}

.profile-picker-list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
    padding: 0;
    margin: 1.5rem 0 0;
    list-style: none;
}

.profile-picker-choice {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem;
    border: 0;
    border-radius: 1rem;
    background: transparent;
    color: var(--bs-body-color);
}

.profile-picker-choice:hover,
.profile-picker-choice:focus-visible {
    background: var(--bs-tertiary-bg);
}

.profile-picker-lock {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    color: var(--bs-secondary-color);
}

.profile-picker-form {
    max-width: 20rem;
    margin: 1rem auto 0;
    text-align: start;
}

.profile-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    max-width: 36rem;
    padding: 0;
    list-style: none;
}

.profile-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.profile-row-text {
    flex: 1 1 auto;
    min-width: 0;
}

/* Search results (views/search.js): the library menu, the libraries with what this one hasn't,
   and the chips choosing all or one kind */
.search-library {
    margin-bottom: 0.75rem;
}

.search-library .form-select {
    max-width: 100%;
}

.search-elsewhere {
    margin-bottom: 1.25rem;
    color: var(--bs-secondary-color);
}

.search-chips {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
    overflow-x: auto;
    scrollbar-width: none;
}

.search-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.9rem;
    border-radius: 50rem;
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    text-decoration: none;
    font-size: 0.9rem;
}

.search-chip:hover {
    background: var(--bs-secondary-bg);
    color: var(--bs-body-color);
}

.search-chip.active {
    background: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    box-shadow: inset 0 0 0 1px var(--bs-primary-border-subtle);
    font-weight: 600;
}

.search-chip-count {
    font-size: 0.75rem;
    opacity: 0.75;
}

/* Lidarr's albums and artists (views/lidarr.js): Get music, and an artist's Missing albums */
.lidarr-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
    gap: 1.25rem 1rem;
    padding: 0;
    margin: 0;
    list-style: none;
}

.lidarr-card {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-width: 0;
}

.lidarr-cover {
    aspect-ratio: 1;
    border-radius: 0.5rem;
    overflow: hidden;
    background: var(--bs-tertiary-bg);
    display: grid;
    place-items: center;
    margin-bottom: 0.25rem;
}

.lidarr-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.lidarr-cover .bi,
.lidarr-artist-photo .bi {
    font-size: 2rem;
    color: var(--bs-secondary-color);
}

.lidarr-title {
    font-size: 0.95rem;
    font-weight: 600;
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lidarr-details {
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lidarr-status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
    margin-top: 0.25rem;
}

.lidarr-status .badge {
    font-weight: 500;
    text-decoration: none;
}

.lidarr-artists {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 0;
    margin: 0;
    list-style: none;
    max-width: 48rem;
}

.lidarr-artist {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.lidarr-artist-photo {
    flex: none;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    overflow: hidden;
    background: var(--bs-tertiary-bg);
    display: grid;
    place-items: center;
}

.lidarr-artist-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.lidarr-artist-name {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

.lidarr-artist .lidarr-status {
    margin-top: 0;
    flex: none;
}

.lidarr-invite {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    max-width: 48rem;
}

/* Under a library's search results: "Not in your library? Look for … with Lidarr" */
.get-music-hint {
    margin-top: 1rem;
    color: var(--bs-secondary-color);
}

/* Settings → Server: a section's button (Test connection) and what it said */
.server-action,
.about-android {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
}

/* Settings → Offline (views/settings/offline.js) */
.offline-usage,
.offline-limit,
.offline-ahead {
    max-width: 28rem;
}

.offline-usage .progress {
    height: 0.5rem;
}

/* Settings → Server (views/settings/server.js): one block per setting */
.server-settings {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    max-width: 40rem;
}

.server-setting {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.server-setting.is-muted {
    opacity: 0.6;
}

.server-setting-input {
    max-width: 28rem;
}

.server-secret {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.server-secret-mask {
    font-family: var(--bs-font-monospace);
    min-width: 8rem;
}

.server-secret-form {
    max-width: 28rem;
}

/* The AI playlist view (views/ai.js): its loading message, and the line about it under the header */
.ai-loading {
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

.ai-playlist-about {
    max-width: 48rem;
    margin-bottom: 1rem;
}

/* Its filters ("Not played in 2 weeks"): what every song in it meets */
.ai-playlist-rules {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    padding: 0;
    margin: 0 0 0.5rem;
    list-style: none;
}

.ai-playlist-rules .badge {
    font-weight: 500;
    white-space: normal;
    text-align: start;
}

.empty-state {
    max-width: 28rem;
    margin: 3rem auto;
    text-align: center;
    color: var(--bs-secondary-color);
}

.empty-state > .bi {
    display: block;
    margin-bottom: 0.75rem;
    font-size: 2.75rem;
    color: var(--bs-primary-text-emphasis);
    text-shadow: var(--nessie-text-glow);
}

.empty-state h2 {
    color: var(--bs-body-color);
}

/* --- <nessie-track-list> --- */

/* The markers lists watch to draw more rows as the end comes near (nessie-track-list, nessie-queue) */
.track-list-end,
.queue-end {
    height: 1px;
}

.queue-earlier {
    display: block;
    margin: 0.25rem auto;
}

.track-table {
    --bs-table-bg: transparent;
    --bs-table-hover-bg: var(--bs-secondary-bg-subtle);
    --bs-table-border-color: transparent;
    table-layout: fixed;
}

.track-table thead th {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
    border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.track-table td,
.track-table th {
    padding: 0.4rem 0.5rem;
}

.track-table .track-number {
    width: 2.75rem;
    text-align: right;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

.track-table .track-time {
    width: 4rem;
    text-align: right;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

.track-table .track-menu {
    width: 2.75rem;
    text-align: right;
}

/* The heart (likes.js): a full-height 44px target, in the teal once liked */
.track-table .track-like {
    width: 2.75rem;
    padding-left: 0;
    padding-right: 0;
    text-align: center;
}

.track-like .like-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 2.75rem;
    padding: 0;
}

.like-button {
    font-size: 1.1rem;
    color: var(--bs-secondary-color);
}

.like-button.liked,
.dropdown-item[data-like] .bi-heart-fill {
    color: var(--bs-primary-text-emphasis);
}

/* On a phone the heart takes the length's place, leaving the title more room than before */
@media (max-width: 575.98px) {
    .track-table .track-time {
        display: none;
    }
}

/* A playlist's Date added: as wide as "12 Sept 2026" (or the heading) */
.track-table .track-added {
    width: 8rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.track-table td.track-added {
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.track-row {
    cursor: pointer;
}

.track-row td:first-child {
    border-top-left-radius: var(--bs-border-radius);
    border-bottom-left-radius: var(--bs-border-radius);
}

.track-row td:last-child {
    border-top-right-radius: var(--bs-border-radius);
    border-bottom-right-radius: var(--bs-border-radius);
}

/* Bootstrap paints a table cell's state (hover, active) from this variable, the same in every cell */
.track-row:hover > td,
.track-row:focus-visible > td {
    --bs-table-bg-state: var(--bs-secondary-bg-subtle);
}

.track-row:focus-visible {
    outline: 2px solid rgba(var(--bs-primary-rgb), 0.6);
    outline-offset: -2px;
}

.track-title-cell {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
}

.track-art {
    width: 2.5rem;
}

.track-art-wrap {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
}

/* In a list without numbers, the playing song's wave, over its cover */
.track-art-wave {
    position: absolute;
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    border-radius: var(--bs-border-radius);
    background: rgb(0 0 0 / 0.55);
    color: #fff;
    font-size: 1.25rem;
}

.track-row.current .track-art-wave {
    display: flex;
}

.track-title {
    font-weight: 500;
}

.track-artist,
.track-table .track-album {
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.track-artist a,
.track-album a {
    color: inherit;
    text-decoration: none;
}

.track-artist a:hover,
.track-album a:hover {
    color: var(--bs-body-color);
    text-decoration: underline;
}

/* The song playing now, as in the queue: the row tinted, its title bold in the bright teal (or
   neon), and a wave in place of its number (or, in a list without numbers, over its cover:
   .track-art-wave). After the hover rule, so the tint stays while it's hovered */
.track-row.current > td {
    --bs-table-bg-state: var(--bs-primary-bg-subtle);
}

.track-row.current .track-title {
    color: var(--bs-primary-text-emphasis);
    font-weight: 600;
    text-shadow: var(--nessie-text-glow);
}

.track-playing-icon {
    display: none;
    color: var(--bs-primary-text-emphasis);
}

.track-row.current .track-playing-icon {
    display: inline;
}

.track-row.current .track-number-value {
    display: none;
}

.track-row.missing {
    cursor: default;
    opacity: 0.5;
}

.track-menu-button {
    font-size: 1.1rem;
    color: var(--bs-secondary-color);
}

/* With a mouse, the ⋮ and an empty heart only show on the row under it (a liked song's heart
   always does); touch screens always show them */
@media (hover: hover) {
    .track-row .track-menu-button,
    .track-row .like-button:not(.liked) {
        opacity: 0;
    }

    .track-row:hover .track-menu-button,
    .track-row:focus-within .track-menu-button,
    .track-menu-button[aria-expanded="true"],
    .track-row:hover .like-button,
    .track-row:focus-within .like-button {
        opacity: 1;
    }
}

/* --- <nessie-media-grid> --- */

.media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
    gap: 1.25rem 1rem;
    margin: 0 0 1rem;
    padding: 0;
    list-style: none;
}

@media (min-width: 992px) {
    .media-grid {
        grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    }
}

/* One scrolling row (the home page), instead of wrapping */
.media-grid-row .media-grid {
    grid-auto-flow: column;
    grid-auto-columns: minmax(9.5rem, 11rem);
    grid-template-columns: none;
    overflow-x: auto;
    padding-bottom: 0.5rem;
    scroll-snap-type: x mandatory;
}

.media-grid-row .media-card {
    scroll-snap-align: start;
}

/* Small tiles with no real cover (genres) */
.media-grid-compact .media-grid {
    grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
}

.media-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
    padding: 0.6rem;
    border-radius: var(--bs-border-radius-lg);
    transition: background-color 0.15s, transform 0.15s;
}

.media-card:hover,
.media-card:focus-within {
    background-color: var(--bs-secondary-bg-subtle);
}

.media-card-art {
    position: relative;
    display: block;
    margin-bottom: 0.5rem;
}

.media-card-art nessie-artwork {
    width: 100%;
    display: flex;
    box-shadow: 0 0.5rem 1.25rem rgba(0, 0, 0, 0.25);
}

.media-card-round nessie-artwork {
    border-radius: 50%;
}

.media-card-title {
    display: block;
    font-weight: 600;
    color: var(--bs-body-color);
    text-decoration: none;
}

.media-card-title:focus-visible {
    outline: none;
}

.media-card:has(.media-card-title:focus-visible) {
    outline: 2px solid rgba(var(--bs-primary-rgb), 0.6);
}

.media-card-subtitle {
    display: block;
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

/* The play button floats on the cover, above the card's stretched link */
.media-card-play {
    position: absolute;
    z-index: 2;
    right: 0.5rem;
    bottom: 0.5rem;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    border-radius: 50%;
    font-size: 1.4rem;
    line-height: 1;
    opacity: 0;
    transform: translateY(0.4rem);
    transition: opacity 0.15s, transform 0.15s;
}

.media-card:hover .media-card-play,
.media-card:focus-within .media-card-play,
.media-card-play:focus-visible {
    opacity: 1;
    transform: none;
}

@media (hover: none) {
    .media-card-play {
        opacity: 1;
        transform: none;
        width: 2.25rem;
        height: 2.25rem;
        font-size: 1.15rem;
    }
}

/* --- <nessie-pager> --- */

.pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-top: 1rem;
}

.pager-summary {
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* --- <nessie-player-bar> --- */

.player-bar {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem calc(0.75rem + env(safe-area-inset-right)) 0.5rem calc(0.75rem + env(safe-area-inset-left));
}

@media (min-width: 768px) {
    .player-bar {
        grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 1fr);
        gap: 1.5rem;
        padding-top: 0.75rem;
        padding-bottom: 0.75rem;
    }
}

.player-mini-progress {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: rgba(var(--bs-secondary-rgb), 0.4);
}

.player-mini-progress-fill {
    height: 100%;
    width: 0;
    background: var(--bs-primary);
    box-shadow: var(--nessie-glow);
    transition: width 0.9s linear;
}

/* What's playing: also the way to open the queue */
/* The song and (from md up) its heart */
.player-song {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

.player-now {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
    padding: 0.25rem;
    border: 0;
    border-radius: var(--bs-border-radius-lg);
    background: none;
    color: inherit;
    text-align: left;
}

.player-now:hover {
    background-color: var(--bs-secondary-bg-subtle);
}

.player-art {
    width: 3rem;
}

.player-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.player-title {
    font-weight: 600;
}

.player-artist {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

.player-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    min-width: 0;
}

.player-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Shuffle and repeat (player bar and Now Playing): muted while off; on, in the theme colour with
   a dot under them, so it isn't told by colour alone */
.player-mode {
    position: relative;
    font-size: 1.15rem;
    color: var(--bs-secondary-color);
}

.player-mode.player-mode-on {
    color: var(--bs-primary-text-emphasis);
}

.player-mode.player-mode-on::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 0;
    width: 0.25rem;
    height: 0.25rem;
    border-radius: 50%;
    background: currentColor;
    transform: translateX(-50%);
}

.player-toggle {
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    font-size: 1.5rem;
    line-height: 1;
}

@media (min-width: 768px) {
    .player-toggle {
        width: 3rem;
        height: 3rem;
    }
}

/* The play/pause button while the song is loading (display.js showToggle): a ring turning around
   it, shown only after a moment so a song that starts at once doesn't flicker */
.player-toggle,
.now-playing-toggle {
    position: relative;
}

.toggle-spinner {
    position: absolute;
    inset: -0.25rem;
    border: 0.15rem solid var(--bs-primary);
    border-right-color: transparent;
    border-radius: 50%;
    opacity: 0;
    pointer-events: none;
}

.is-loading .toggle-spinner {
    animation: toggle-spinner-in 0.2s ease 0.3s forwards, toggle-spinner-turn 0.75s linear infinite;
}

@keyframes toggle-spinner-in {
    to { opacity: 1; }
}

@keyframes toggle-spinner-turn {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .is-loading .toggle-spinner {
        animation: toggle-spinner-in 0.2s ease 0.3s forwards, toggle-spinner-turn 1.5s linear infinite;
    }
}

.player-seek {
    align-items: center;
    gap: 0.75rem;
    width: 100%;
}

.player-seek .form-range {
    flex: 1;
}

.player-time {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
    min-width: 2.75rem;
    text-align: center;
}

.player-side {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.25rem;
}

.player-volume {
    align-items: center;
    gap: 0.5rem;
    width: 8rem;
    color: var(--bs-secondary-color);
}

.player-output-menu {
    min-width: 16rem;
}

/* Seek and volume sliders: the part up to the thumb in the theme colour. --progress is set by
   player/display.js for seek bars; volume sliders work it out from their value in browsers that
   can't (they just show an even track) */
.player-range::-webkit-slider-runnable-track {
    background: linear-gradient(to right, var(--bs-primary) var(--progress, 0%), rgba(var(--bs-secondary-rgb), 0.45) var(--progress, 0%));
}

.player-range::-moz-range-progress {
    background-color: var(--bs-primary);
    height: 0.5rem;
    border-radius: 1rem;
}

/* Seek bars' handle as a picture: a theme that has one names it in theme.js, which sets
   html[data-seek-handle]. SVG data URLs, so fixed colours that show on the theme */
:root {
    --nessie-handle-jack-o-lantern: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 6C11 3 12 1.5 14 1' fill='none' stroke='%233E7B27' stroke-width='2' stroke-linecap='round'/%3E%3Cg stroke='%237A3A05' stroke-width='1'%3E%3Cellipse cx='8' cy='14' rx='6.5' ry='8' fill='%23E8780F'/%3E%3Cellipse cx='16' cy='14' rx='6.5' ry='8' fill='%23E8780F'/%3E%3Cellipse cx='12' cy='14' rx='5' ry='8.5' fill='%23F28C1C'/%3E%3C/g%3E%3Cg fill='%23FFD54A'%3E%3Cpath d='M6 11.5L9.5 11.5L7.75 8.5Z'/%3E%3Cpath d='M14.5 11.5L18 11.5L16.25 8.5Z'/%3E%3Cpath d='M5.5 15L18.5 15C18 18.5 15 20.5 12 20.5C9 20.5 6 18.5 5.5 15ZM8.5 15L9.5 16.5L10.5 15ZM13.5 15L14.5 16.5L15.5 15ZM10.5 20.3L11.5 18.8L12.5 20.3Z' fill-rule='evenodd'/%3E%3C/g%3E%3C/svg%3E");
}

html[data-seek-handle="jack-o-lantern"] .seek-handle { --handle-picture: var(--nessie-handle-jack-o-lantern); }

html[data-seek-handle] .seek-handle::-webkit-slider-thumb {
    width: 1.5rem;
    height: 1.5rem;
    margin-top: -0.5rem;  /* centred on the 0.5rem track */
    border-radius: 0;
    background: var(--handle-picture) center / contain no-repeat;
    box-shadow: none;
    transition: none;  /* Bootstrap fades the dot's colour, which would flash a square */
}

html[data-seek-handle] .seek-handle::-moz-range-thumb {
    width: 1.5rem;
    height: 1.5rem;
    border: 0;
    border-radius: 0;
    background: var(--handle-picture) center / contain no-repeat;
    box-shadow: none;
}

/* No glow ring to show focus: the theme colour around the picture's outline instead */
html[data-seek-handle] .seek-handle:focus-visible::-webkit-slider-thumb {
    filter: drop-shadow(0 0 2px var(--bs-primary)) drop-shadow(0 0 2px var(--bs-primary));
}

html[data-seek-handle] .seek-handle:focus-visible::-moz-range-thumb {
    filter: drop-shadow(0 0 2px var(--bs-primary)) drop-shadow(0 0 2px var(--bs-primary));
}

/* Disabled (nothing playing): faded rather than Bootstrap's grey dot */
html[data-seek-handle] .seek-handle:disabled::-webkit-slider-thumb {
    background-color: transparent;
    opacity: 0.5;
}

html[data-seek-handle] .seek-handle:disabled::-moz-range-thumb {
    background-color: transparent;
    opacity: 0.5;
}

/* Phones: the bar's song opens the full player; the chevron says so */
.player-open-hint {
    margin-left: auto;
    padding-left: 0.25rem;
    color: var(--bs-secondary-color);
}

@media (max-width: 767.98px) {
    .player-mini-progress {
        height: 3px;
    }

    .player-art {
        width: 2.75rem;
    }
}

/* --- <nessie-now-playing> --- */

/* The whole height of its sheet, so the layout inside can share out that height */
nessie-now-playing {
    height: 100%;
}

.now-playing {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    height: 100%;
    max-width: 30rem;
    margin: 0 auto;
    padding: calc(0.5rem + env(safe-area-inset-top)) 1.5rem calc(1.5rem + env(safe-area-inset-bottom));
    overflow-y: auto;
}

/* Where a downward swipe closes the sheet: no browser scrolling there to fight it */
.now-playing-swipe {
    touch-action: none;
}

.now-playing-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.now-playing-where {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 0;
    text-align: center;
}

.now-playing-label {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bs-primary-text-emphasis);
    text-shadow: var(--nessie-text-glow);
}

.now-playing-output {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

.now-playing-art-wrap {
    display: flex;
    justify-content: center;
    flex: 1 1 auto;
    min-height: 0;
}


/* As big as fits: the width, or the height left once the text and controls below it have theirs
   (about 27rem, plus the notch and home indicator), so on a short phone the cover shrinks rather
   than pushing the controls off the bottom */
.now-playing-art {
    --now-playing-rest: calc(27rem + env(safe-area-inset-top) + env(safe-area-inset-bottom));
    width: clamp(8rem, calc(100vh - var(--now-playing-rest)), min(100%, 28rem));
    height: auto;
    align-self: center;
    border-radius: var(--bs-border-radius-xl);
    box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.45), var(--nessie-glow);
}

@supports (height: 100dvh) {
    .now-playing-art {
        width: clamp(8rem, calc(100dvh - var(--now-playing-rest)), min(100%, 28rem));
    }
}

/* The title and subtitle, with the song's ⋮ menu beside them */
.now-playing-heading {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.now-playing-like {
    font-size: 1.4rem;
}

.now-playing-text {
    flex: 1 1 auto;
    min-width: 0;  /* so a long title truncates instead of pushing the menu off */
}

.now-playing-title {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 800;
}

.now-playing-subtitle {
    color: var(--bs-secondary-color);
}

.now-playing-subtitle a {
    color: inherit;
    text-decoration: none;
}

.now-playing-subtitle a:hover {
    color: var(--bs-body-color);
    text-decoration: underline;
}

.now-playing-times {
    display: flex;
    justify-content: space-between;
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

/* Shuffle and repeat at the edges, the transport buttons between */
.now-playing-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.now-playing-mode {
    font-size: 1.4rem;
}

.now-playing-skip {
    font-size: 2.25rem;
}

.now-playing-toggle {
    width: 4.5rem;
    height: 4.5rem;
    padding: 0;
    font-size: 2.5rem;
    line-height: 1;
}

.now-playing-volume {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    color: var(--bs-secondary-color);
}

.now-playing-outputs {
    display: flex;
    gap: 0.5rem;
}

.now-playing-outputs .btn {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- <nessie-queue> --- */

.queue-toolbar {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    background-color: var(--bs-tertiary-bg);
    border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.queue-list {
    margin: 0;
    padding: 0.5rem;
    list-style: none;
}

.queue-item {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    border-radius: var(--bs-border-radius-lg);
}

.queue-item:hover {
    background-color: var(--bs-secondary-bg-subtle);
}

.queue-item.current {
    background-color: var(--bs-primary-bg-subtle);
}

.queue-item.current .queue-title {
    color: var(--bs-primary-text-emphasis);
    font-weight: 600;
    text-shadow: var(--nessie-text-glow);
}

.queue-item.played {
    opacity: 0.55;
}

.queue-play {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex: 1;
    min-width: 0;
    padding: 0.4rem 0.5rem;
    border: 0;
    background: none;
    color: inherit;
    text-align: left;
}

.queue-art {
    width: 2.5rem;
}

.queue-text {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
}

.queue-artist {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

.queue-time {
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

.queue-item.current .queue-time {
    color: var(--bs-primary-text-emphasis);
}

.queue-remove,
.queue-remove-space {
    flex: 0 0 2.25rem;
    font-size: 1rem;
    color: var(--bs-secondary-color);
}

@media (hover: hover) {
    .queue-item .queue-remove {
        opacity: 0;
    }

    .queue-item:hover .queue-remove,
    .queue-remove:focus-visible {
        opacity: 1;
    }
}

/* --- <nessie-playlist-picker> --- */

.picker-art {
    width: 2.5rem;
}

/* --- <nessie-notifications>: the header's bell --- */

.notifications-button {
    position: relative;
    font-size: 1.35rem;
    text-decoration: none;  /* btn-link's, under the space beside the badge */
}

/* The unread count, on the bell's corner (outranking Bootstrap's .btn .badge) */
.notifications-button .notifications-badge {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 1.15rem;
    padding: 0.2em 0.35em;
    font-size: 0.65rem;
    background: var(--bs-danger);
    color: #fff;
}

.notifications-menu {
    width: min(24rem, calc(100vw - 2rem));
    max-height: min(32rem, 70vh);
    overflow-y: auto;
    padding: 0;
}

.notifications-heading {
    position: sticky;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.5rem 0.5rem 0.4rem 1rem;
    background: var(--bs-dropdown-bg);
    border-bottom: var(--bs-border-width) solid var(--bs-border-color-translucent);
}

.notifications-heading h2 {
    margin: 0;
    padding-block: 0.25rem;
    font-size: 1rem;
    font-weight: 600;
}

.notification {
    display: flex;
    gap: 0.65rem;
    padding: 0.6rem 1rem;
    line-height: 1.35;
}

.notification + .notification {
    border-top: var(--bs-border-width) solid var(--bs-border-color-translucent);
}

/* Not seen before it was opened */
.notification.is-new {
    background: var(--bs-primary-bg-subtle);
}

.notification-icon {
    flex: none;
    margin-top: 0.1rem;
}

.notification-text {
    overflow-wrap: anywhere;
}

.notifications-empty {
    padding: 1rem;
}

/* --- <nessie-toasts> --- */

.app-toasts {
    position: fixed;
    z-index: 1090;
    top: calc(4.5rem + env(safe-area-inset-top));
    right: 1rem;
    padding: 0;
}

.toast-success .bi { color: var(--bs-primary-text-emphasis); }
.toast-warning .bi { color: var(--bs-warning); }
.toast-danger .bi { color: var(--bs-danger); }

/* --- Reordering (lib/reorder.js): handles, and the row being dragged --- */

/* The handle takes the whole gesture: no scrolling, text selection or iOS long-press menu */
.drag-handle {
    touch-action: none;
    cursor: grab;
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    color: var(--bs-secondary-color);
}

.dragging .drag-handle {
    cursor: grabbing;
}

.queue-item.dragging,
.track-row.dragging > td {
    background-color: var(--bs-primary-bg-subtle);
}

.queue-item.dragging,
.track-row.dragging {
    position: relative;
    z-index: 1;
    outline: 2px solid var(--bs-primary);
    outline-offset: -2px;
    box-shadow: var(--nessie-glow);
}

.queue-item .drag-handle {
    flex: 0 0 2rem;
    padding: 0.25rem;
    font-size: 1.1rem;
}

/* --- A playlist being edited (nessie-track-list[editing]) --- */

.track-table .track-handle {
    width: 2.5rem;
    padding-left: 0;
    padding-right: 0;
}

.track-table.editing .track-row {
    cursor: default;
}

.track-remove {
    font-size: 1rem;
    color: var(--bs-secondary-color);
}

.track-remove:hover {
    color: var(--bs-danger);
}

.edit-hint {
    padding: 0.5rem 0.75rem;
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    font-size: 0.9rem;
}

.min-w-0 {
    min-width: 0;
}

/* --- Settings --- */

/* Scrolls sideways when the tabs don't fit (phones), never up and down. The line under them is
   an inset shadow, inside the strip, so the active tab's underline covers it without poking out
   (a tab hanging 1px over a real border made the strip scroll vertically). */
.settings-tabs {
    position: relative;  /* the tabs' offsetLeft counts from here (settings/index.js) */
    display: flex;
    gap: 0.25rem;
    margin-bottom: 1.5rem;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: thin;
    box-shadow: inset 0 calc(-1 * var(--bs-border-width)) 0 var(--bs-border-color);
}

.settings-tab {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.9rem;
    border-bottom: 2px solid transparent;
    color: var(--bs-secondary-color);
    text-decoration: none;
    white-space: nowrap;
}

.settings-tab:hover {
    color: var(--bs-body-color);
}

.settings-tab.active {
    border-bottom-color: var(--bs-primary);
    color: var(--bs-primary-text-emphasis);
    font-weight: 600;
    text-shadow: var(--nessie-text-glow);
}

.settings-section {
    max-width: 56rem;
}

.settings-intro {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
    color: var(--bs-secondary-color);
}

.settings-intro p {
    flex: 1 1 20rem;
    margin: 0;
}

.settings-add {
    margin-bottom: 1rem;
}

.card {
    --bs-card-bg: var(--bs-tertiary-bg);
    --bs-card-border-color: var(--bs-border-color);
    --bs-card-cap-bg: rgba(var(--bs-secondary-rgb), 0.1);
}

.library-cards,
.import-cards {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.library-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.library-card-actions {
    display: flex;
    gap: 0.5rem;
}

.library-card-progress:not(:empty) {
    margin-top: 0.75rem;
}

/* <nessie-scan-progress> */
.scan-progress {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.9rem;
}

.scan-done {
    display: block;
    color: var(--bs-primary-text-emphasis);
}

.scan-dir {
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
}

/* <nessie-folder-picker> */
.folder-picker-path {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.folder-picker-list {
    max-height: 18rem;
    overflow-y: auto;
    margin-bottom: 0.5rem;
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}

/* Import playlists */
.import-drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    padding: 2rem 1rem;
    border: 2px dashed var(--bs-border-color);
    border-radius: var(--bs-border-radius-xl);
    text-align: center;
    cursor: pointer;
    transition: border-color 0.15s, background-color 0.15s;
}

.import-drop:hover,
.import-drop:focus-within {
    border-color: var(--bs-primary);
    background-color: var(--bs-primary-bg-subtle);
}

.import-drop .bi {
    font-size: 2.25rem;
    color: var(--bs-primary-text-emphasis);
    text-shadow: var(--nessie-text-glow);
}

.import-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.75rem;
}

.import-card-head .import-include {
    margin-top: 0.65rem;
}

.import-card-head .import-as {
    width: auto;
}

.import-card-skipped {
    opacity: 0.6;
}

.import-tracks:not([hidden]) {
    margin-top: 0.75rem;
}

.import-table {
    --bs-table-bg: transparent;
}

.import-table tr.missing > td {
    color: var(--bs-secondary-color);
    opacity: 0.6;
}

.import-actions {
    position: sticky;
    bottom: 0;
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0.75rem 0;
    background: linear-gradient(transparent, var(--bs-body-bg) 35%);
}

/* Appearance: a card per theme, with three dots of its colours */
.theme-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
    gap: 0.75rem;
}

.theme-card {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 0.75rem;
    border: 2px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    text-align: left;
}

.theme-card:hover {
    border-color: rgba(var(--bs-primary-rgb), 0.6);
}

.theme-card.active {
    border-color: var(--bs-primary);
    box-shadow: var(--nessie-glow);
}

.theme-card-description {
    margin-top: -0.35rem;  /* close under its label */
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
}

.theme-swatch {
    display: flex;
    gap: 0.35rem;
    padding: 0.75rem;
    border-radius: var(--bs-border-radius);
}

.theme-swatch span {
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
}

/* Fixed colours: each swatch shows its own theme, whichever theme is on */
.theme-swatch-dark { background: #0d172e; }
.theme-swatch-dark span:nth-child(1) { background: #6db5a8; }
.theme-swatch-dark span:nth-child(2) { background: #2b3e6d; }
.theme-swatch-dark span:nth-child(3) { background: #152445; border: 1px solid #2b3e6d; }
.theme-swatch-light { background: #f3f5f6; box-shadow: inset 0 0 0 1px #dee2e6; }  /* an outline that takes no space */
.theme-swatch-light span:nth-child(1) { background: #6db5a8; }
.theme-swatch-light span:nth-child(2) { background: #2b3e6d; }
.theme-swatch-light span:nth-child(3) { background: #ffffff; border: 1px solid #dee2e6; }
.theme-swatch-synthwave-neon { background: #05050a; }
.theme-swatch-synthwave-neon span:nth-child(1) { background: #39ff14; box-shadow: 0 0 0.5rem #39ff14; }
.theme-swatch-synthwave-neon span:nth-child(2) { background: #bd00ff; box-shadow: 0 0 0.5rem #bd00ff; }
.theme-swatch-synthwave-neon span:nth-child(3) { background: #00f0ff; box-shadow: 0 0 0.5rem #00f0ff; }
.theme-swatch-halloween { background: #120c18; }
.theme-swatch-halloween span:nth-child(1) { background: #ff8c1a; box-shadow: 0 0 0.5rem rgba(255, 140, 26, 0.6); }
.theme-swatch-halloween span:nth-child(2) { background: #8a4fb8; }
.theme-swatch-halloween span:nth-child(3) { background: #9be04a; }
.theme-swatch-system { background: linear-gradient(135deg, #0d172e 50%, #f3f5f6 50%); }
.theme-swatch-system span:nth-child(1) { background: #6db5a8; }
.theme-swatch-system span:nth-child(2) { background: #2b3e6d; }
.theme-swatch-system span:nth-child(3) { background: #ffffff; border: 1px solid #dee2e6; }

/* --- <nessie-description> --- */

.description {
    max-width: 48rem;
    margin-bottom: 1.75rem;
}

.description-text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
    margin-bottom: 0.25rem;
    color: var(--bs-secondary-color);
    line-height: 1.6;
}

.description-text.open {
    display: block;
}

.description-credit {
    font-size: 0.75rem;
    color: var(--bs-tertiary-color, var(--bs-secondary-color));
}

/* --- <nessie-image-picker> --- */

.image-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.image-picker-choice {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    width: 100%;
    padding: 0.4rem;
    border: 2px solid transparent;
    border-radius: var(--bs-border-radius-lg);
    background: none;
    color: inherit;
    text-align: left;
}

.image-picker-choice:hover,
.image-picker-choice:focus-visible {
    border-color: var(--bs-primary);
    box-shadow: var(--nessie-glow);
}

.image-picker-choice nessie-artwork {
    width: 100%;
    display: flex;
}

.image-picker-grid.round nessie-artwork {
    border-radius: 50%;
}

/* --- Settings → Stats (views/settings/stats.js) --- */

.stats-recap {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.stats-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
}

.stats-whose {
    width: auto;
}

.stats-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.75rem;
    margin-bottom: 2rem;
}

.stats-tile {
    padding: 0.875rem 1rem;
    border-radius: var(--bs-border-radius-lg);
    background-color: var(--bs-secondary-bg);
}

.stats-tile-label {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

.stats-tile-value {
    font-size: clamp(1.25rem, 5vw, 1.75rem);
    font-weight: 700;
    line-height: 1.2;
}

.stats-tile-note {
    font-size: 0.8rem;
    color: var(--bs-secondary-color);
}

.stats-section {
    margin-bottom: 2rem;
    min-width: 0;
}

.stats-pair,
.stats-tops {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
    column-gap: 2rem;
}

/* Column charts: one hue (--nessie-chart), columns at most 24px with 4px rounded tops on a
   hairline baseline, the peak's value on its cap; a tooltip on hover and focus */
.stats-chart {
    position: relative;
}

.stats-columns {
    display: grid;
    grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
    align-items: end;
    gap: 2px;
    height: 9rem;
    padding-top: 1.25rem;  /* room for the peak's label */
    border-bottom: 1px solid var(--bs-border-color);
}

.stats-column {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: flex-end;
    height: 100%;
    cursor: default;
    outline: none;
}

.stats-bar {
    width: 100%;
    max-width: 24px;
    min-height: 0;
    border-radius: 4px 4px 0 0;
    background-color: var(--nessie-chart);
}

.stats-column:hover .stats-bar,
.stats-column:focus-visible .stats-bar {
    filter: brightness(1.2);
}

.stats-column:focus-visible {
    box-shadow: inset 0 0 0 2px var(--bs-focus-ring-color);
    border-radius: 4px;
}

.stats-peak {
    position: absolute;
    top: -1.25rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-body-color);
    white-space: nowrap;
}

.stats-axis {
    display: grid;
    grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
    margin-top: 0.25rem;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

.stats-axis span {
    overflow: visible;
    white-space: nowrap;
}

.stats-tooltip {
    position: absolute;
    top: 0;
    transform: translate(-50%, -100%);
    display: flex;
    flex-direction: column;
    padding: 0.375rem 0.625rem;
    border-radius: var(--bs-border-radius);
    background-color: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    box-shadow: var(--bs-box-shadow-sm);
    font-size: 0.8rem;
    white-space: nowrap;
    pointer-events: none;
    z-index: 2;
}

.stats-tooltip strong {
    font-size: 0.95rem;
}

.stats-tooltip span {
    color: var(--bs-secondary-color);
}

.stats-table {
    margin-top: 0.5rem;
    font-size: 0.85rem;
}

.stats-table summary {
    color: var(--bs-secondary-color);
    cursor: pointer;
}

.stats-table table {
    max-width: 24rem;
    margin-top: 0.5rem;
    font-variant-numeric: tabular-nums;
}

.stats-highlights {
    padding-left: 1.25rem;
    margin: 0;
}

.stats-highlights li + li {
    margin-top: 0.375rem;
}

/* Top lists: rank, picture, name with a meter of plays against the first's, and the count */
.stats-top {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: 0.625rem;
}

.stats-top li {
    display: grid;
    grid-template-columns: 1.5rem 2.5rem minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.75rem;
}

.stats-rank {
    text-align: right;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}

.stats-top-art,
.stats-top-icon {
    width: 2.5rem;
    height: 2.5rem;
}

.stats-top-icon {
    display: grid;
    place-items: center;
    border-radius: var(--bs-border-radius);
    background-color: var(--bs-secondary-bg);
    color: var(--bs-secondary-color);
}

.stats-top-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.stats-top-text a {
    color: inherit;
    text-decoration: none;
}

.stats-top-text a:hover {
    text-decoration: underline;
}

.stats-top-subtitle {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

.stats-meter {
    display: block;
    height: 4px;
    margin-top: 0.25rem;
    border-radius: 2px;
    background-color: var(--bs-secondary-bg);
}

.stats-meter span {
    display: block;
    height: 100%;
    border-radius: 2px;
    background-color: var(--nessie-chart);
}

.stats-top-value {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* --- <nessie-lyrics> in the lyrics panel --- */

@media (min-width: 576px) {
    .app-lyrics {
        --bs-offcanvas-width: 30rem;
    }
}

.lyrics {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-height: 100%;
}

.lyrics-song {
    min-width: 0;
}

.lyrics-title {
    font-weight: 700;
}

.lyrics-artist,
.lyrics-note,
.lyrics-footer {
    color: var(--bs-secondary-color);
}

.lyrics-note {
    margin: 2rem 0 0;
    text-align: center;
}

.lyrics-plain p {
    font-size: 1.15rem;
    line-height: 1.6;
    white-space: pre-line;  /* the song's own line breaks */
}

/* Timed lines: what's been sung fades, the line being sung is bright, what's to come in between.
   Each line is a button: clicking plays from it */
.lyrics-lines {
    list-style: none;
    margin: 0;
    padding: 30vh 0;  /* room to bring the first and last lines to the middle */
}

.lyrics-line {
    display: block;
    width: 100%;
    padding: 0.35rem 0;
    border: 0;
    background: none;
    text-align: left;
    font-size: 1.4rem;
    font-weight: 700;
    line-height: 1.35;
    color: var(--bs-secondary-color);
    transition: color 0.25s, opacity 0.25s;
}

.lyrics-line.past {
    opacity: 0.45;
}

.lyrics-line.current {
    color: var(--bs-emphasis-color);
    text-shadow: var(--nessie-text-glow);
}

/* Underlined, not brightened, so only the line being sung is lit; and only with a real pointer
   (a tap would leave a phone's line looking lit) */
@media (hover: hover) {
    .lyrics-line:hover {
        text-decoration: underline;
        text-decoration-thickness: 2px;
        text-underline-offset: 0.2em;
    }
}

.lyrics-line:focus-visible {
    outline: 2px solid var(--bs-focus-ring-color);
    border-radius: var(--bs-border-radius-sm);
}

.lyrics-footer {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    justify-content: space-between;
    margin-top: auto;
    font-size: 0.8rem;
}

@media (prefers-reduced-motion: reduce) {
    .lyrics-line {
        transition: none;
    }
}

/* --- Mix editor (views/mix-editor.js) and its name picker --- */

/* Rules beside the preview; then the bar, outside .mix-editor, so the preview (kept in view as
   the rules scroll) stops above it. On a phone everything stacks, and the bar stays at the bottom
   of the screen with the count */
.mix-editor {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1.5rem;
}

.mix-editor-main {
    flex: 999 1 34rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.mix-editor-names {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.mix-editor-name {
    flex: 1 1 14rem;
}

.mix-editor-description {
    flex: 2 1 18rem;
}

.mix-rules {
    background: var(--bs-tertiary-bg);
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-xl);
    padding: 0 1.25rem;
}

.mix-rule + .mix-rule {
    border-top: var(--bs-border-width) solid var(--bs-border-color);
}

/* Each group's row: its name and what it's set to; it opens to the controls */
.mix-rule > summary {
    display: flex;
    align-items: baseline;
    gap: 1rem;
    min-height: 3rem;
    padding: 0.85rem 0;
    list-style: none;
    cursor: pointer;
}

.mix-rule > summary::-webkit-details-marker {
    display: none;
}

.mix-rule > summary::after {
    content: "\F282";  /* bi-chevron-down */
    font-family: bootstrap-icons;
    margin-left: auto;
    color: var(--bs-secondary-color);
    transition: transform 0.2s;
}

.mix-rule[open] > summary::after {
    transform: rotate(180deg);
}

.mix-rule-label {
    flex: none;
    width: 7.5rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
}

.mix-rule-summary {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--bs-secondary-color);
}

.mix-rule-body {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 0 0 1.1rem 8.5rem;
}

.mix-rule-help {
    margin: 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.mix-rule-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
}

.mix-rule-row[hidden],
.mix-span[hidden] {
    display: none;
}

.mix-number {
    width: 6rem;
}

.mix-mode,
.mix-span {
    width: auto;
}

.mix-favours {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.mix-size {
    flex: 1 1 12rem;
}

.mix-size-value {
    min-width: 6rem;
    font-weight: 600;
}

/* The preview, kept in view beside the rules while they're scrolled (wider screens) */
.mix-preview {
    flex: 1 1 22rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    background: var(--bs-tertiary-bg);
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-xl);
    padding: 1.25rem;
    scroll-margin-top: 1rem;
}

.mix-preview-heading {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
}

.mix-preview-body {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    min-width: 0;
}

.mix-preview-count {
    font-size: 1.75rem;
    font-weight: 700;
    line-height: 1.15;
}

.mix-preview-pick {
    margin: 0;
    color: var(--bs-secondary-color);
}

.mix-preview-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.mix-preview-actions .btn-lg {
    --bs-btn-padding-y: 0.375rem;
    --bs-btn-font-size: 1rem;
}

/* Nothing fits: in the warning colour, with what dropping each rule would let in */
.mix-preview-none {
    border: var(--bs-border-width) solid var(--bs-warning-border-subtle);
    border-radius: var(--bs-border-radius-lg);
    padding: 1rem;
}

.mix-preview-none .mix-preview-count {
    font-size: 1.35rem;
    color: var(--bs-warning-text-emphasis);
}

.mix-loosen {
    margin: 0.5rem 0 0;
    padding-left: 1.2rem;
}

.mix-editor-bar {
    display: flex;
    margin-top: 1.5rem;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
}

.mix-editor-bar-count,
.mix-editor-bar-preview {
    display: none;
}

@media (min-width: 768px) {
    .mix-preview {
        position: sticky;
        top: 0;
    }
}

@media (max-width: 767.98px) {
    .mix-rule-body {
        padding-left: 0;
    }

    .mix-rule-label {
        width: 6rem;
    }

    .mix-editor-bar {
        position: sticky;
        bottom: 0;
        z-index: 2;
        margin: 0 -1rem;
        padding: 0.75rem 1rem;
        background: var(--bs-tertiary-bg);
        border-top: var(--bs-border-width) solid var(--bs-border-color);
    }

    .mix-editor-bar-count {
        display: block;
        flex: 1;
        min-width: 0;
        font-weight: 700;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* The header's Back does it on a phone, and the bar needs the room */
    .mix-editor-cancel {
        display: none;
    }

    .mix-editor-bar-preview {
        display: inline-block;
    }
}

/* <nessie-name-picker>: chosen names as chips, then an Add button with a search */
.name-picker {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.name-picker-label {
    width: 4.5rem;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.name-picker-chips {
    display: contents;
    list-style: none;
}

.name-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
    padding: 0.1rem 0.15rem 0.1rem 0.75rem;
    border-radius: 50rem;
    background: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    font-size: 0.9rem;
    font-weight: 500;
}

.name-picker-exclude .name-chip {
    background: transparent;
    border: var(--bs-border-width) solid var(--bs-warning-border-subtle);
    color: var(--bs-warning-text-emphasis);
}

.name-chip-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    border: 0;
    border-radius: 50rem;
    background: transparent;
    color: inherit;
    font-size: 0.75rem;
}

.name-chip-remove:hover {
    background: rgba(var(--bs-body-color-rgb), 0.1);
}

.name-picker-add {
    --bs-btn-color: var(--bs-secondary-color);
    --bs-btn-hover-color: var(--bs-body-color);
    border: var(--bs-border-width) dashed color-mix(in srgb, var(--bs-body-color) 50%, transparent);
    border-radius: 50rem;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.name-picker-menu {
    width: 18rem;
    padding: 0.5rem;
}

.name-picker-options {
    margin-top: 0.4rem;
    max-height: 16rem;
    overflow-y: auto;
}

.name-picker-none {
    padding: 0.4rem 0.5rem;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}


/* --- <nessie-recap>: a year's recap, a full-screen story (components/nessie-recap.js) ---
   Its own colours, the same in every theme: white on dark, saturated tones (at least 7:1), and each
   tone's accent at least 4.5:1. */
.recap {
    --recap-accent: #8fd3c7;
    position: fixed;
    inset: 0;
    z-index: 1060;  /* over the header, sidebar, player and dialogs; toasts (1090) stay above */
    display: flex;
    flex-direction: column;
    padding: calc(env(safe-area-inset-top, 0px) + 0.75rem) max(16px, env(safe-area-inset-right, 0px))
             calc(env(safe-area-inset-bottom, 0px) + 0.75rem) max(16px, env(safe-area-inset-left, 0px));
    color: #ffffff;
    background: linear-gradient(160deg, var(--recap-from), var(--recap-to));
    user-select: none;
    touch-action: pan-y;
    outline: none;
}
.recap-navy { --recap-from: #0d172e; --recap-to: #1b2d55; }
.recap-teal { --recap-from: #0b4a43; --recap-to: #0f5f56; --recap-accent: #b5ece2; }
.recap-plum { --recap-from: #3b1b5a; --recap-to: #5a2d82; --recap-accent: #e5c3ff; }
.recap-coral { --recap-from: #7a2611; --recap-to: #9a3412; --recap-accent: #ffd2b8; }
.recap-blue { --recap-from: #172f6e; --recap-to: #1e3a8a; --recap-accent: #c7d7ff; }

/* Artwork filling the screen behind a slide, under a wash of its colour: 90% through the middle,
   where the text is (white text at least 6:1 whatever the covers), 65% at the top and bottom, where
   only the controls are (at least 3.3:1; the count has its own dark pill). Everything else sits above it. */
.recap-backdrop { position: absolute; inset: 0; overflow: hidden; z-index: 0; }
.recap-backdrop::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom,
        color-mix(in srgb, var(--recap-from) 65%, transparent),
        color-mix(in srgb, var(--recap-from) 90%, transparent) 26%,
        color-mix(in srgb, var(--recap-to) 90%, transparent) 76%,
        color-mix(in srgb, var(--recap-to) 65%, transparent));
}
.recap-mosaic {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    width: 112%;
    margin: -6%;
    transform: rotate(-8deg);
    animation: recap-drift 40s linear infinite alternate;
}
.recap-mosaic img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; }
.recap > :not(.recap-backdrop) { position: relative; z-index: 1; }
@keyframes recap-drift {
    from { transform: rotate(-8deg) translateY(0); }
    to { transform: rotate(-8deg) translateY(-12%); }
}

/* New artists' pictures (the discoveries slide) */
.recap-faces { list-style: none; margin: 0.75rem 0 0.25rem; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.9rem 0.75rem; }
.recap-faces li { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; min-width: 0; animation: recap-in 0.45s ease-out both; animation-delay: calc(var(--i, 0) * 90ms); }
.recap-faces img, .recap-face-none { width: min(22vw, 88px); aspect-ratio: 1; border-radius: 50%; object-fit: cover; border: 3px solid rgb(255 255 255 / 85%); }
.recap-face-none { display: grid; place-items: center; font-size: 1.5rem; font-weight: 800; background: rgb(255 255 255 / 15%); }
.recap-faces span:last-child { max-width: 100%; font-size: 0.85rem; font-weight: 600; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.recap-progress { display: flex; gap: 4px; }
.recap-segment { flex: 1; height: 4px; border-radius: 2px; background: rgb(255 255 255 / 30%); overflow: hidden; }
.recap-segment > span { display: block; height: 100%; width: 0; background: #ffffff; }
.recap-segment.done > span { width: 100%; }

.recap-controls { display: flex; justify-content: flex-end; gap: 0.25rem; margin-top: 0.5rem; }
.recap-control {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border: 0;
    border-radius: 50%;
    color: #ffffff;
    background: rgb(255 255 255 / 12%);
    font-size: 1.15rem;
}
.recap-control:hover { background: rgb(255 255 255 / 22%); }
.recap-control:focus-visible { outline: 3px solid #ffffff; outline-offset: 2px; }
.recap-control:disabled { opacity: 0.35; }

/* Centred while it fits; taller than the screen (the summary on a small phone), it scrolls from its
   top. Auto margins rather than justify-content: center, which would cut off the top, out of reach. */
.recap-slide {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    width: 100%;
    max-width: 34rem;
    margin: 0 auto;
    padding: 0.5rem 0;
    overflow-y: auto;
    animation: recap-in 0.45s ease-out both;
}
.recap-slide > :first-child { margin-top: auto; }
.recap-slide > :last-child { margin-bottom: auto; }
.recap-kicker { margin: 0; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; font-size: 0.85rem; color: var(--recap-accent); }
.recap-title { margin: 0; font-size: clamp(2.2rem, 9vw, 3.6rem); font-weight: 800; line-height: 1.05; text-wrap: balance; overflow-wrap: anywhere; }
.recap-big { margin: 0; font-size: clamp(4rem, 22vw, 7.5rem); font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.recap-unit { margin: 0; font-size: 1.4rem; font-weight: 700; }
.recap-line { margin: 0.25rem 0 0; font-size: 1.15rem; line-height: 1.45; }
.recap-portrait { width: min(55vw, 220px); aspect-ratio: 1; object-fit: cover; border-radius: 50%; margin: 0.5rem 0; }

.recap-list { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.6rem; }
.recap-list li { display: flex; align-items: center; gap: 0.75rem; min-width: 0; animation: recap-in 0.45s ease-out both; animation-delay: calc(var(--i, 0) * 90ms); }
.recap-rank { width: 1.6rem; font-size: 1.4rem; font-weight: 800; text-align: right; color: var(--recap-accent); flex: none; }
.recap-list img, .recap-art-none { width: 56px; height: 56px; border-radius: 6px; object-fit: cover; flex: none; }
.recap-art-none { display: grid; place-items: center; background: rgb(255 255 255 / 15%); }
.recap-item { display: flex; flex-direction: column; min-width: 0; }
.recap-item strong, .recap-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recap-item span { font-size: 0.9rem; opacity: 0.85; }

.recap-card { padding: 1.25rem; border-radius: 16px; background: rgb(0 0 0 / 25%); }
/* Minutes and the top genre side by side; the top artists and songs side by side from 480px up,
   else each the card's width. Long names wrap rather than run out of the card. */
.recap-card-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1rem; margin-top: 0.75rem; }
.recap-card-grid > * { min-width: 0; }
.recap-card-grid span { display: block; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--recap-accent); }
.recap-card-grid strong { font-size: 1.6rem; line-height: 1.15; overflow-wrap: anywhere; }
.recap-card-grid ol { margin: 0.25rem 0 0; padding-left: 1.4rem; font-size: 0.95rem; line-height: 1.3; }
.recap-card-grid li { margin-top: 0.2rem; overflow-wrap: anywhere; }
.recap-card-grid li::marker { color: var(--recap-accent); font-weight: 700; }
@media (max-width: 479.98px) {
    .recap-card-grid .recap-card-list { grid-column: 1 / -1; }
}
.recap-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }

.recap-nav { display: flex; align-items: center; justify-content: space-between; max-width: 34rem; width: 100%; margin: 0 auto; }
.recap-count { font-size: 0.9rem; padding: 0.15rem 0.6rem; border-radius: 999px; background: rgb(0 0 0 / 35%); }

@keyframes recap-in {
    from { opacity: 0; transform: translateY(16px); }
    to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .recap-slide, .recap-list li, .recap-faces li, .recap-mosaic { animation: none; }
}
