/*
 * The page frame: header, sidebar, current view and player bar.
 *
 * The body is a three-row grid as tall as the screen (header / body / player); only the view
 * (and the sidebar, on desktop) scroll. Below lg the sidebar is a slide-out drawer (Bootstrap's
 * offcanvas-lg), from lg a fixed column. Safe-area insets keep things clear of notches and the
 * home indicator when the app runs full screen from a phone's home screen.
 */

html,
body {
    height: 100%;
}

body.app {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-columns: minmax(0, 1fr);  /* never wider than the screen, whatever is inside */
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    background-color: var(--bs-body-bg);
}

.app-skip-link {
    position: absolute;
    z-index: 1100;
    top: 0.5rem;
    left: 0.5rem;
    padding: 0.5rem 1rem;
    background: var(--bs-primary);
    color: var(--nessie-on-primary);
    border-radius: var(--bs-border-radius);
}

/* --- Header --- */

.app-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: calc(0.5rem + env(safe-area-inset-top)) calc(1rem + env(safe-area-inset-right)) 0.5rem
        calc(1rem + env(safe-area-inset-left));
    z-index: 1020;
}

/* The menu button, the brand, and Back and Forward */
.app-header-start {
    display: flex;
    flex: none;
    align-items: center;
    gap: 0.75rem;
}

.app-brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 700;
    font-size: 1.15rem;
    letter-spacing: 0.02em;
    color: var(--bs-body-color);
    text-decoration: none;
    text-shadow: var(--nessie-text-glow);
}

.app-brand img {
    border-radius: 0.5rem;
}

.app-icon-button {
    font-size: 1.5rem;
    line-height: 1;
    padding: 0.25rem 0.4rem;
    color: var(--bs-body-color);
}

.app-icon-button:hover {
    color: var(--bs-primary-text-emphasis);
}

/* Back and Forward (main.js): dimmed when there's nowhere to go */
.app-history {
    display: flex;
    gap: 0.125rem;
}

.app-history .app-icon-button {
    --bs-btn-disabled-color: var(--bs-body-color);
    --bs-btn-disabled-opacity: 0.3;
    padding-inline: 0.3rem;
}

/* Phones: no Forward, and Back only on pages below the sidebar's (an album, an artist, search
   results), in place of the brand */
@media (max-width: 767.98px) {
    .app-history,
    #history-forward {
        display: none;
    }

    .app-header.has-back .app-history {
        display: flex;
    }

    .app-header.has-back .app-brand {
        display: none;
    }
}

/* Search grows into the header's free space, up to a comfortable width */
.app-search {
    position: relative;
    flex: 1 1 auto;
    max-width: 32rem;
    min-width: 0;
}

.app-search > .bi {
    position: absolute;
    left: 0.9rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--bs-secondary-color);
    pointer-events: none;
}

.app-search .form-control {
    padding-left: 2.5rem;
    border-radius: 50rem;
    background-color: var(--bs-body-bg);
}

/* From md up the header is three columns, the outer two as wide as each other, so the search box
   sits in the middle of the screen whatever is beside it. Placed by column, as the search box
   can be hidden */
@media (min-width: 768px) {
    .app-header {
        display: grid;
        grid-template-columns: 1fr minmax(0, 32rem) 1fr;
    }

    .app-header-start {
        grid-column: 1;
    }

    .app-search {
        grid-column: 2;
        max-width: none;
    }

    .app-header-actions {
        grid-column: 3;
        justify-self: end;
    }
}

/* On phones the brand gives way to the search box when there is one */
@media (max-width: 575.98px) {
    .app-header:has(.app-search:not([hidden])) .app-brand span {
        display: none;
    }
}

/* "Offline" (js/connection.js): in the theme's warning colours */
.app-offline {
    background: var(--bs-warning-bg-subtle);
    color: var(--bs-warning-text-emphasis);
    border: var(--bs-border-width) solid var(--bs-warning-border-subtle);
    font-weight: 600;
    padding: 0.35em 0.7em;
}

.app-demo {
    background: var(--bs-info-bg-subtle);
    color: var(--bs-info-text-emphasis);
    border: var(--bs-border-width) solid var(--bs-info-border-subtle);
    font-weight: 600;
    padding: 0.35em 0.7em;
}

.app-header-actions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

/* The AI button (js/ai-prompt.js): the search box's right end, full height, a × while the box is
   the AI prompt. The box leaves room for it, so the browser's own clear button sits before it */
.app-search-ai {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    line-height: 1;
    padding: 0;
    border-radius: 0 50rem 50rem 0;
    color: var(--bs-secondary-color);
}

/* A 44px-tall target, a little past the box's edges */
.app-search-ai::after {
    content: "";
    position: absolute;
    inset: -0.2rem 0;
}

@media (hover: hover) {
    .app-search-ai:hover {
        color: var(--bs-primary-text-emphasis);
    }
}

.app-search:has(.app-search-ai:not([hidden])) .form-control {
    padding-right: 2.75rem;
}

/* The ✨ at the box's start marks the prompt */
.app-header.ai-prompting .app-search > .bi {
    color: var(--bs-primary-text-emphasis);
}

/* Touch: a bigger icon, and the browser's clear button further from it */
@media (pointer: coarse) {
    .app-search-ai {
        width: 3rem;
        font-size: 1.3rem;
    }

    .app-search:has(.app-search-ai:not([hidden])) .form-control {
        padding-right: 3.25rem;
    }
}

/* Phones: the prompt gets a row of its own under the header's buttons, to see what's typed */
@media (max-width: 575.98px) {
    .app-header.ai-prompting {
        flex-wrap: wrap;
        row-gap: 0.5rem;
    }

    .app-header.ai-prompting .app-search {
        order: 1;
        flex-basis: 100%;
        max-width: none;
    }
}

/* --- Body: sidebar and view --- */

.app-body {
    display: flex;
    min-height: 0;
}

.app-sidebar {
    --bs-offcanvas-width: min(20rem, 85vw);
    --bs-offcanvas-bg: var(--bs-tertiary-bg);
}

.app-sidebar .offcanvas-body {
    flex-direction: column;
    padding: 0.75rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom));
}

@media (max-width: 991.98px) {
    /* A drawer as tall as the screen, status bar included (the app, a Home Screen app): its header
       starts below the status bar, as the queue's does, and both clear a notch on the left */
    .app-sidebar .offcanvas-header {
        padding-top: calc(var(--bs-offcanvas-padding-y) + env(safe-area-inset-top));
        padding-left: calc(var(--bs-offcanvas-padding-x) + env(safe-area-inset-left));
    }

    .app-sidebar .offcanvas-body {
        padding-left: calc(0.75rem + env(safe-area-inset-left));
    }
}

@media (min-width: 992px) {
    /* A column of its own; Bootstrap makes an offcanvas-lg transparent here, so the frame paints it */
    .app-sidebar-frame {
        flex: 0 0 16.5rem;
        overflow-y: auto;
        border-right: var(--bs-border-width) solid var(--bs-border-color);
    }

    .app-sidebar .offcanvas-body {
        padding: 1rem 0.75rem;
    }
}

.app-main {
    flex: 1 1 auto;
    min-width: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 1.25rem calc(1rem + env(safe-area-inset-right)) 2rem calc(1rem + env(safe-area-inset-left));
}

.app-main:focus {
    outline: none;
}

@media (min-width: 992px) {
    .app-main {
        padding: 1.75rem 2rem 2.5rem;
    }
}

/* --- Player bar --- */

.app-player {
    display: block;
    padding-bottom: env(safe-area-inset-bottom);
    z-index: 1020;
}

/* --- Queue panel: a side panel on desktop, the whole screen on phones --- */

.app-queue {
    --bs-offcanvas-width: 26rem;
}

@media (max-width: 575.98px) {
    .app-queue {
        --bs-offcanvas-width: 100vw;
    }

    .app-queue .offcanvas-header {
        padding-top: calc(1rem + env(safe-area-inset-top));
    }
}

/* --- Now Playing: a sheet over the whole screen --- */

/* Bootstrap sizes a bottom offcanvas from --bs-offcanvas-height (its rule beats a plain height
   here). 100vh on iOS Safari includes the strip behind the browser's toolbar, which hid the
   bottom of the sheet; 100dvh is the visible height. A custom property takes any value, so the
   fallback can't just be listed first: @supports picks one. */
.app-now-playing {
    --bs-offcanvas-height: 100vh;
    border-top: 0;
    transition: transform 0.3s ease-in-out;
    background: linear-gradient(180deg, rgba(var(--bs-primary-rgb), 0.18), transparent 45%), var(--bs-tertiary-bg);
}

@supports (height: 100dvh) {
    .app-now-playing {
        --bs-offcanvas-height: 100dvh;
    }
}
