/* ==========================================================================
   havMusic — application stylesheet
   One file, twenty-four themes. Themes are selected with [data-theme] on <html> and
   are nothing but a block of custom properties, so switching one never needs
   a page reload (important: the shell HTML is served from the service worker
   cache when offline and could otherwise be stale).
   ========================================================================== */

@font-face {
    font-family: "Pragati Narrow";
    src: url("../PragatiNarrow-Regular.woff2") format("woff2");
    font-weight: 400;
    font-display: swap;
}

/* --------------------------------------------------------------------------
   Tokens
   -------------------------------------------------------------------------- */

:root {
    --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --font-display: "Pragati Narrow", var(--font-ui);

    --r-xs: 4px;
    --r-sm: 8px;
    --r-md: 12px;
    --r-lg: 18px;
    --r-pill: 999px;

    --pane-max: 720px;
    --tabbar-h: 3.5rem;
    /* Indirected through a variable so it can be inspected and overridden;
       env() alone is invisible to anything but the device it renders on. */
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-top: env(safe-area-inset-top, 0px);

    --ease: cubic-bezier(0.2, 0, 0, 1);
}

/* Dark red — the historical default (`dr`) */
:root,
[data-theme="dr"] {
    color-scheme: dark;
    --bg: #0b0b0c;
    --bg-lib: #101011;
    --player-bg: linear-gradient(180deg, #2d0c0c 0%, #0b0b0c 62%);
    --surface: #17171a;
    --surface-2: #202024;
    --surface-3: #2a2a30;
    --line: #2e2e34;
    --text: #f4f4f5;
    --text-2: #a1a1aa;
    --accent: #d04040;
    --accent-2: #ee6c6c;
    --on-accent: #ffffff;
    --ok: #7fce6f;
    --on-ok: #10240c;
    --track-bg: #3a3a42;
    --theme-color: #771f1f;
    --shadow: 0 10px 30px rgb(0 0 0 / 45%);
}

[data-theme="lr"] {
    color-scheme: light;
    --bg: #ffffff;
    --bg-lib: #f6f7f9;
    --player-bg: linear-gradient(180deg, #dfe9f6 0%, #ffffff 62%);
    --surface: #ffffff;
    --surface-2: #eef1f5;
    --surface-3: #e2e6ec;
    --line: #d7dce3;
    --text: #14161a;
    --text-2: #5c6672;
    --accent: #0f7ce0;
    --accent-2: #4693e0;
    --on-accent: #ffffff;
    --ok: #2f9e57;
    --on-ok: #ffffff;
    --track-bg: #d7dce3;
    --theme-color: #0085fa;
    --shadow: 0 10px 30px rgb(20 30 50 / 12%);
}

[data-theme="db"] {
    color-scheme: dark;
    --bg: #08080c;
    --bg-lib: #0e0f16;
    --player-bg: linear-gradient(180deg, #101a45 0%, #08080c 62%);
    --surface: #151725;
    --surface-2: #1d2033;
    --surface-3: #262a41;
    --line: #2c3049;
    --text: #f1f3fa;
    --text-2: #9aa1bd;
    --accent: #4062d0;
    --accent-2: #6d8bff;
    --on-accent: #ffffff;
    --ok: #6fc7ce;
    --on-ok: #06232a;
    --track-bg: #333857;
    --theme-color: #273e8d;
    --shadow: 0 10px 30px rgb(0 0 0 / 50%);
}

[data-theme="lg"] {
    color-scheme: light;
    --bg: #ffffff;
    --bg-lib: #f4f8f4;
    --player-bg: linear-gradient(180deg, #ddefe1 0%, #ffffff 62%);
    --surface: #ffffff;
    --surface-2: #eaf1ea;
    --surface-3: #dde7de;
    --line: #d2ded3;
    --text: #12180f;
    --text-2: #5a6659;
    --accent: #2f8f4c;
    --accent-2: #3eab5d;
    --on-accent: #ffffff;
    --ok: #2f8f4c;
    --on-ok: #ffffff;
    --track-bg: #d2ded3;
    --theme-color: #54b06b;
    --shadow: 0 10px 30px rgb(20 40 20 / 12%);
}

[data-theme="lo"] {
    color-scheme: light;
    --bg: #ffffff;
    --bg-lib: #fbf6ef;
    --player-bg: linear-gradient(180deg, #ffe9cc 0%, #ffffff 62%);
    --surface: #ffffff;
    --surface-2: #f5ece0;
    --surface-3: #ebe0d1;
    --line: #e3d7c6;
    --text: #1a1510;
    --text-2: #6b6053;
    --accent: #e07d00;
    --accent-2: #ff9d00;
    --on-accent: #ffffff;
    --ok: #2f9e57;
    --on-ok: #ffffff;
    --track-bg: #e3d7c6;
    --theme-color: #ff9e07;
    --shadow: 0 10px 30px rgb(60 40 10 / 12%);
}

[data-theme="dg"] {
    color-scheme: dark;
    --bg: #05070a;
    --bg-lib: #0a0f12;
    --player-bg: linear-gradient(180deg, #05304a 0%, #05070a 62%);
    --surface: #101820;
    --surface-2: #16222c;
    --surface-3: #1e2d3a;
    --line: #24333f;
    --text: #eef6f4;
    --text-2: #8fa6a5;
    --accent: #2fc48a;
    --accent-2: #58e2a8;
    --on-accent: #04241a;
    --ok: #2fc48a;
    --on-ok: #04241a;
    --track-bg: #24333f;
    --theme-color: #0066ff;
    --shadow: 0 10px 30px rgb(0 0 0 / 50%);
}

[data-theme="lm"] {
    color-scheme: light;
    --bg: #e9e9e9;
    --bg-lib: #f2f2f2;
    --player-bg: linear-gradient(180deg, #d9d9d9 0%, #f2f2f2 62%);
    --surface: #ffffff;
    --surface-2: #ececec;
    --surface-3: #dedede;
    --line: #d2d2d2;
    --text: #15161a;
    --text-2: #62646b;
    --accent: #333338;
    --accent-2: #55565e;
    --on-accent: #ffffff;
    --ok: #2f9e57;
    --on-ok: #ffffff;
    --track-bg: #d2d2d2;
    --theme-color: #222222;
    --shadow: 0 10px 30px rgb(0 0 0 / 12%);
}

[data-theme="tn"] {
    color-scheme: dark;
    --bg: #2f3540;
    --bg-lib: #363d49;
    --player-bg: linear-gradient(180deg, #303030 0%, #4a5e74 100%);
    --surface: #3c4453;
    --surface-2: #46505f;
    --surface-3: #515c6d;
    --line: #55606f;
    --text: #f2f5f9;
    --text-2: #b3bdcb;
    --accent: #5e8cc7;
    --accent-2: #7ea9de;
    --on-accent: #08131f;
    --ok: #9ac47f;
    --on-ok: #14200c;
    --track-bg: #59636f;
    --theme-color: #4a5e74;
    --shadow: 0 10px 30px rgb(0 0 0 / 35%);
}

[data-theme="we"] {
    color-scheme: dark;
    --bg: #000000;
    --bg-lib: #08080a;
    --player-bg: linear-gradient(180deg, #000000 0%, #00417f 100%);
    --surface: #121216;
    --surface-2: #1b1b21;
    --surface-3: #26262e;
    --line: #2c2c34;
    --text: #eeeeee;
    --text-2: #9d9da6;
    --accent: #007aff;
    --accent-2: #3f9bff;
    --on-accent: #ffffff;
    --ok: #32d74b;
    --on-ok: #052a0c;
    --track-bg: #33333c;
    --theme-color: #0073ff;
    --shadow: 0 10px 30px rgb(0 0 0 / 60%);
}

/* Amethyst — dark purple */
[data-theme="am"] {
    color-scheme: dark;
    --bg: #0b0a10;
    --bg-lib: #110f18;
    --player-bg: linear-gradient(180deg, #2b1659 0%, #0b0a10 62%);
    --surface: #17141f;
    --surface-2: #1f1b2b;
    --surface-3: #29243a;
    --line: #2f2a40;
    --text: #f5f3fb;
    --text-2: #a7a0bc;
    --accent: #8152f0;
    --accent-2: #a37dff;
    --on-accent: #ffffff;
    --ok: #7fce9f;
    --on-ok: #0b2416;
    --track-bg: #3a3450;
    --theme-color: #4b2a90;
    --shadow: 0 10px 30px rgb(0 0 0 / 50%);
}

/* Lavender — light purple */
[data-theme="lv"] {
    color-scheme: light;
    --bg: #ffffff;
    --bg-lib: #f7f5fc;
    --player-bg: linear-gradient(180deg, #e9e0fb 0%, #ffffff 62%);
    --surface: #ffffff;
    --surface-2: #f0ecf8;
    --surface-3: #e5dff2;
    --line: #dcd5ea;
    --text: #17141f;
    --text-2: #625b73;
    --accent: #6d45e0;
    --accent-2: #8a6cf0;
    --on-accent: #ffffff;
    --ok: #2f9e57;
    --on-ok: #ffffff;
    --track-bg: #dcd5ea;
    --theme-color: #8a6cf0;
    --shadow: 0 10px 30px rgb(40 20 80 / 12%);
}

/* Synthwave — hot pink on deep indigo */
[data-theme="sy"] {
    color-scheme: dark;
    --bg: #0d0819;
    --bg-lib: #130c24;
    --player-bg: linear-gradient(180deg, #4a0f4d 0%, #0d0819 62%);
    --surface: #1a1230;
    --surface-2: #23193d;
    --surface-3: #2e214d;
    --line: #352858;
    --text: #fbf2ff;
    --text-2: #b5a3c9;
    --accent: #ff3d9a;
    --accent-2: #ff71b8;
    --on-accent: #24031a;
    --ok: #3ef0d0;
    --on-ok: #032a24;
    --track-bg: #3a2d5c;
    --theme-color: #5a1a7a;
    --shadow: 0 10px 30px rgb(0 0 0 / 55%);
}

/* Blossom — light pink */
[data-theme="bs"] {
    color-scheme: light;
    --bg: #ffffff;
    --bg-lib: #fdf4f7;
    --player-bg: linear-gradient(180deg, #fbdbe6 0%, #ffffff 62%);
    --surface: #ffffff;
    --surface-2: #f8ebf0;
    --surface-3: #f0dce4;
    --line: #ead3dc;
    --text: #1c1216;
    --text-2: #6e5862;
    --accent: #d1356f;
    --accent-2: #ec5d92;
    --on-accent: #ffffff;
    --ok: #2f9e57;
    --on-ok: #ffffff;
    --track-bg: #ead3dc;
    --theme-color: #f07aa5;
    --shadow: 0 10px 30px rgb(80 20 40 / 12%);
}

/* Lagoon — dark teal */
[data-theme="la"] {
    color-scheme: dark;
    --bg: #051013;
    --bg-lib: #08171b;
    --player-bg: linear-gradient(180deg, #06424d 0%, #051013 62%);
    --surface: #0e1d22;
    --surface-2: #14272d;
    --surface-3: #1b3239;
    --line: #213a42;
    --text: #eaf7f8;
    --text-2: #8aa9ad;
    --accent: #1fb5c9;
    --accent-2: #4fd3e3;
    --on-accent: #032429;
    --ok: #8fd16f;
    --on-ok: #10240c;
    --track-bg: #24404a;
    --theme-color: #075d6b;
    --shadow: 0 10px 30px rgb(0 0 0 / 50%);
}

/* Ember — amber on warm black */
[data-theme="em"] {
    color-scheme: dark;
    --bg: #0d0a07;
    --bg-lib: #13100b;
    --player-bg: linear-gradient(180deg, #4a2608 0%, #0d0a07 62%);
    --surface: #1b1610;
    --surface-2: #241e16;
    --surface-3: #2f271d;
    --line: #362d21;
    --text: #faf5ee;
    --text-2: #b0a493;
    --accent: #f0a020;
    --accent-2: #ffbe4d;
    --on-accent: #2a1700;
    --ok: #8fd16f;
    --on-ok: #10240c;
    --track-bg: #3d3426;
    --theme-color: #8a4a0c;
    --shadow: 0 10px 30px rgb(0 0 0 / 50%);
}

/* Sand — terracotta on warm cream */
[data-theme="sd"] {
    color-scheme: light;
    --bg: #faf6ef;
    --bg-lib: #f4eee3;
    --player-bg: linear-gradient(180deg, #f1dcc6 0%, #faf6ef 62%);
    --surface: #fffdf9;
    --surface-2: #f2eadd;
    --surface-3: #e8ddcc;
    --line: #ded1bd;
    --text: #231a12;
    --text-2: #6f6150;
    --accent: #b8532a;
    --accent-2: #d9744a;
    --on-accent: #ffffff;
    --ok: #4f8a3a;
    --on-ok: #ffffff;
    --track-bg: #ded1bd;
    --theme-color: #d9744a;
    --shadow: 0 10px 30px rgb(60 35 15 / 12%);
}

/* Cherry — light red */
[data-theme="ch"] {
    color-scheme: light;
    --bg: #ffffff;
    --bg-lib: #fdf5f5;
    --player-bg: linear-gradient(180deg, #f9dada 0%, #ffffff 62%);
    --surface: #ffffff;
    --surface-2: #f7eaea;
    --surface-3: #efdcdc;
    --line: #e8d2d2;
    --text: #1c1212;
    --text-2: #6e5757;
    --accent: #c62f3b;
    --accent-2: #e04f5a;
    --on-accent: #ffffff;
    --ok: #2f9e57;
    --on-ok: #ffffff;
    --track-bg: #e8d2d2;
    --theme-color: #e04f5a;
    --shadow: 0 10px 30px rgb(80 20 20 / 12%);
}

/* Graphite — dark mono */
[data-theme="gr"] {
    color-scheme: dark;
    --bg: #0c0c0d;
    --bg-lib: #111113;
    --player-bg: linear-gradient(180deg, #2a2a2e 0%, #0c0c0d 62%);
    --surface: #18181b;
    --surface-2: #212125;
    --surface-3: #2b2b30;
    --line: #323238;
    --text: #f4f4f5;
    --text-2: #a1a1aa;
    --accent: #e4e4e7;
    --accent-2: #ffffff;
    --on-accent: #111113;
    --ok: #7fce6f;
    --on-ok: #10240c;
    --track-bg: #3a3a42;
    --theme-color: #2a2a2e;
    --shadow: 0 10px 30px rgb(0 0 0 / 50%);
}

/* Royal — gold on navy */
[data-theme="ry"] {
    color-scheme: dark;
    --bg: #070b1a;
    --bg-lib: #0b1124;
    --player-bg: linear-gradient(180deg, #13245a 0%, #070b1a 62%);
    --surface: #111a33;
    --surface-2: #172241;
    --surface-3: #1f2c52;
    --line: #26335c;
    --text: #f2f4fb;
    --text-2: #9aa3c2;
    --accent: #e8b84a;
    --accent-2: #f5cd6e;
    --on-accent: #241800;
    --ok: #7fce9f;
    --on-ok: #0b2416;
    --track-bg: #2b3762;
    --theme-color: #1b2d6b;
    --shadow: 0 10px 30px rgb(0 0 0 / 55%);
}

/* Dusk — soft blue-grey, low contrast */
[data-theme="du"] {
    color-scheme: dark;
    --bg: #14171d;
    --bg-lib: #171b22;
    --player-bg: linear-gradient(180deg, #262f40 0%, #14171d 62%);
    --surface: #1b1f27;
    --surface-2: #222733;
    --surface-3: #2a3040;
    --line: #2f3646;
    --text: #d5dae3;
    --text-2: #8d95a5;
    --accent: #6f8fbf;
    --accent-2: #8aa6d1;
    --on-accent: #0e1420;
    --ok: #86b89a;
    --on-ok: #0d1f15;
    --track-bg: #343b4b;
    --theme-color: #262f40;
    --shadow: 0 10px 30px rgb(0 0 0 / 40%);
}

/* Storm — steel blue, low contrast */
[data-theme="st"] {
    color-scheme: dark;
    --bg: #0f131a;
    --bg-lib: #121720;
    --player-bg: linear-gradient(180deg, #1c2c44 0%, #0f131a 62%);
    --surface: #161c26;
    --surface-2: #1d2533;
    --surface-3: #252f41;
    --line: #2a3547;
    --text: #cfd8e6;
    --text-2: #8794a8;
    --accent: #44709f;
    --accent-2: #5f8cbd;
    --on-accent: #f2f5fa;
    --ok: #7fb8a0;
    --on-ok: #0c1f18;
    --track-bg: #2e3a4e;
    --theme-color: #1c2c44;
    --shadow: 0 10px 30px rgb(0 0 0 / 45%);
}

/* Abyss — deep navy, low contrast */
[data-theme="ab"] {
    color-scheme: dark;
    --bg: #070b12;
    --bg-lib: #0a0f18;
    --player-bg: linear-gradient(180deg, #0f2038 0%, #070b12 62%);
    --surface: #0e1520;
    --surface-2: #131c2a;
    --surface-3: #1a2536;
    --line: #1f2b3d;
    --text: #c6d0df;
    --text-2: #7f8ba0;
    --accent: #3c69a0;
    --accent-2: #5a86bd;
    --on-accent: #eef3fa;
    --ok: #6fae9a;
    --on-ok: #071c16;
    --track-bg: #233046;
    --theme-color: #0f2038;
    --shadow: 0 10px 30px rgb(0 0 0 / 55%);
}

/* Oxblood — brown-red, low contrast */
[data-theme="ox"] {
    color-scheme: dark;
    --bg: #150d0e;
    --bg-lib: #190f11;
    --player-bg: linear-gradient(180deg, #3a1418 0%, #150d0e 62%);
    --surface: #1e1415;
    --surface-2: #271a1c;
    --surface-3: #312124;
    --line: #3a272a;
    --text: #e0d4d4;
    --text-2: #9c8a8b;
    --accent: #a3434b;
    --accent-2: #bd5d65;
    --on-accent: #f7eeee;
    --ok: #8fb88a;
    --on-ok: #121f10;
    --track-bg: #42302f;
    --theme-color: #3a1418;
    --shadow: 0 10px 30px rgb(0 0 0 / 45%);
}

/* Merlot — wine, low contrast */
[data-theme="me"] {
    color-scheme: dark;
    --bg: #140b11;
    --bg-lib: #180d14;
    --player-bg: linear-gradient(180deg, #3b1229 0%, #140b11 62%);
    --surface: #1d1119;
    --surface-2: #261722;
    --surface-3: #301d2b;
    --line: #3a2434;
    --text: #e3d3dd;
    --text-2: #a08b98;
    --accent: #a8436c;
    --accent-2: #c25f86;
    --on-accent: #f8eef3;
    --ok: #8fb8a0;
    --on-ok: #0f1f18;
    --track-bg: #432d3c;
    --theme-color: #3b1229;
    --shadow: 0 10px 30px rgb(0 0 0 / 45%);
}

/* --------------------------------------------------------------------------
   Reset / base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    /* Scrolling only: no pinch or double-tap zoom. */
    touch-action: pan-x pan-y;
}

body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-ui);
    font-size: 15px;
    line-height: 1.4;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
}

h1, h2, h3 {
    margin: 0;
    font-weight: 600;
}

ol, ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

img {
    display: block;
    max-width: 100%;
}

button {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

input {
    font: inherit;
    color: inherit;
}

a {
    color: var(--accent-2);
}

[hidden] {
    display: none !important;
}

:focus-visible {
    outline: 2px solid var(--accent-2);
    outline-offset: 2px;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

.icon {
    width: 1.25em;
    height: 1.25em;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
    flex: none;
}

.icon--fill {
    fill: currentColor;
    stroke: none;
}

/* --------------------------------------------------------------------------
   Shell
   -------------------------------------------------------------------------- */

/* Height is the whole ball game for the bottom tab bar.

   100vh is the *largest* viewport — on a phone with browser chrome showing, an
   element that tall runs underneath the toolbar, taking the tab bar with it,
   and it only reappears when the toolbar happens to retract. 100dvh tracks the
   chrome but updates late (and not at all on older iOS). So: 100svh, the
   smallest viewport, always fits; then JS replaces it with the measured visual
   viewport, which is exact and also handles the on-screen keyboard. */
.app {
    height: 100vh;
    height: 100svh;
    display: flex;
    flex-direction: column;
    /* Installed on an iPhone the app is drawn under the status bar (that's
       what viewport-fit=cover and the black-translucent status bar ask for),
       so the content starts below it. The strip behind the status bar takes
       the theme colour, which keeps its white text readable on light themes.
       Everywhere else the insets are 0 and none of this shows. */
    padding-top: var(--safe-top);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    background: linear-gradient(var(--theme-color), var(--theme-color)) top / 100% var(--safe-top) no-repeat;
}

html.has-measured-vh .app {
    height: var(--app-height);
}

/* Home-screen app on iOS: WebKit reports the screen height minus the status
   bar there, which left an empty band at the bottom. The script sizes the app
   from the real window height instead; fixed positioning lets it reach past
   the short box the page itself is given. */
html.ios-standalone .app {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
}

.panes {
    flex: 1;
    min-height: 0;
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
}

.panes::-webkit-scrollbar {
    display: none;
}

.pane {
    flex: 0 0 100%;
    width: 100%;
    min-width: 0;
    height: 100%;
    scroll-snap-align: start;
    overflow-y: auto;
    overflow-x: hidden;
    /* Vertical only. A pane can't scroll sideways, so a horizontal swipe has to
       be allowed to chain out to .panes — `overscroll-behavior: contain` would
       block that and kill swiping between the library and the player. */
    overscroll-behavior-y: contain;
    overscroll-behavior-x: auto;
    display: flex;
    flex-direction: column;
    scrollbar-width: thin;
    scrollbar-color: var(--surface-3) transparent;
}

.pane::-webkit-scrollbar {
    width: 10px;
}

.pane::-webkit-scrollbar-track {
    background: transparent;
}

.pane::-webkit-scrollbar-thumb {
    background: var(--surface-3);
    border-radius: var(--r-pill);
}

.pane--library {
    background: var(--bg-lib);
}

.pane--player {
    background: var(--player-bg);
    background-attachment: local;
}

/* Visualizer (js/visualizer.js): spectrum bars that stay put behind the Now
   Playing pane while it scrolls. The wrapper sticks to the top of the pane but
   has no height, so it never pushes the player down; the canvas hangs from it
   at the pane's visible height, which the script sets. */
.player__viz-wrap {
    position: sticky;
    top: 0;
    flex: none;
    height: 0;
    z-index: 0;
}

.player__viz {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    pointer-events: none;
}

.pane--player > .player {
    position: relative;
    z-index: 1;
}

/* --------------------------------------------------------------------------
   Top bar / search
   -------------------------------------------------------------------------- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 0.75rem 0.6rem;
    background: var(--bg-lib);
    background: color-mix(in srgb, var(--bg-lib) 88%, transparent);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--line);
}

.topbar__title {
    flex: 1;
    min-width: 0;
    font-family: var(--font-display);
    font-size: 1.65rem;
    letter-spacing: 0.01em;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.badge {
    font-family: var(--font-ui);
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 0.2rem 0.45rem;
    border-radius: var(--r-pill);
    background: var(--accent);
    color: var(--on-accent);
}

.badge--offline {
    background: var(--surface-3);
    color: var(--text-2);
    border: 1px solid var(--line);
}

/* It is a button: tapping it re-checks the connection. */
.badge--offline:hover,
.badge--offline:active {
    background: var(--accent);
    color: var(--on-accent);
    border-color: var(--accent);
}

.badge--offline:disabled {
    opacity: 0.6;
}

.offline-recovery {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 0.85rem;
}

.offline-recovery__note {
    margin: 0 0 0.7rem;
    font-size: 0.85rem;
    color: var(--text-2);
}

#btn-reconnect:disabled {
    opacity: 0.7;
}

.iconbtn {
    display: grid;
    place-items: center;
    width: 2.4rem;
    height: 2.4rem;
    flex: none;
    border-radius: var(--r-sm);
    color: var(--text);
    transition: background 0.15s var(--ease);
}

.iconbtn:hover {
    background: var(--surface-2);
}

.iconbtn:active {
    background: var(--surface-3);
}

.iconbtn[aria-pressed="true"] {
    background: var(--accent);
    color: var(--on-accent);
}

.searchbar {
    position: sticky;
    top: 0;
    z-index: 21;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem;
    background: var(--bg-lib);
    border-bottom: 1px solid var(--line);
}

.field {
    flex: 1;
    min-width: 0;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 0.55rem 0.7rem;
    color: var(--text);
}

.field::placeholder {
    color: var(--text-2);
}

.field:focus {
    outline: none;
    border-color: var(--accent);
}

.pane__body {
    padding: 0.5rem 0.75rem 6rem;
}

/* --------------------------------------------------------------------------
   Library — collections, albums, tracks
   -------------------------------------------------------------------------- */

.collection {
    margin-bottom: 0.35rem;
}

.collection__head {
    position: sticky;
    top: 3.5rem;
    z-index: 10;
    display: flex;
    align-items: stretch;
    gap: 0.35rem;
    background: var(--bg-lib);
    padding: 0.15rem 0;
}

.collection__toggle {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.7rem;
    border-radius: var(--r-md);
    background: var(--surface);
    border: 1px solid var(--line);
    text-align: left;
    transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
}

.collection__toggle:hover {
    background: var(--surface-2);
}

.collection[data-open="1"] .collection__toggle {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.collection__caret {
    transition: transform 0.2s var(--ease);
}

.collection[data-open="1"] .collection__caret {
    transform: rotate(90deg);
}

.collection__name {
    flex: 1;
    min-width: 0;
    font-family: var(--font-display);
    font-size: 1.4rem;
    line-height: 1.1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.collection__count {
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    opacity: 0.7;
}

.collection__shuffle {
    flex: none;
    display: grid;
    place-items: center;
    width: 2.9rem;
    border-radius: var(--r-md);
    background: var(--surface);
    border: 1px solid var(--line);
    color: var(--text-2);
}

.collection__shuffle:hover {
    background: var(--surface-2);
    color: var(--text);
}

.collection__body {
    display: none;
    padding: 0.5rem 0 0.75rem;
}

.collection[data-open="1"] .collection__body {
    display: block;
}

.albumgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
    gap: 0.6rem;
    align-items: start;
}

.album {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    text-align: left;
    border-radius: var(--r-md);
    padding: 0;
    color: inherit;
}

.album__art {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: var(--r-md);
    background: var(--surface-2);
    border: 1px solid var(--line);
    transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}

.album:hover .album__art {
    transform: translateY(-2px);
    box-shadow: var(--shadow);
}

.album[aria-expanded="true"] .album__art {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.album__name {
    font-size: 0.8rem;
    line-height: 1.25;
    color: var(--text);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.album__meta {
    display: none;
    font-size: 0.75rem;
    color: var(--text-2);
}

.album.is-playing .album__name {
    color: var(--accent-2);
    font-weight: 600;
}

/* Album columns on a phone held upright, picked in Settings. Until then, and
   on anything wider, the grid fits as many albums as there's room for. */
.cols-setting {
    display: none;
}

.cols-setting__head {
    display: flex;
    justify-content: space-between;
    font-size: 0.85rem;
    color: var(--text-2);
    padding: 0.2rem 0.2rem 0;
}

@media (max-width: 37.5em) and (orientation: portrait) {
    [data-view="art"] .cols-setting {
        display: block;
    }

    [data-view="art"][data-cols="3"] .albumgrid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    [data-view="art"][data-cols="4"] .albumgrid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    [data-view="art"][data-cols="5"] .albumgrid {
        grid-template-columns: repeat(5, minmax(0, 1fr));
        gap: 0.45rem;
    }

    [data-view="art"][data-cols="5"] .album__name {
        font-size: 0.72rem;
    }
}

/* List view: one album per row, no artwork requested at all. */
[data-view="list"] .albumgrid {
    grid-template-columns: 1fr;
    gap: 0.25rem;
}

[data-view="list"] .album {
    flex-direction: row;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.55rem 0.7rem;
    background: var(--surface);
    border: 1px solid var(--line);
}

[data-view="list"] .album__art {
    display: none;
}

[data-view="list"] .album__name {
    font-family: var(--font-display);
    font-size: 1.15rem;
    -webkit-line-clamp: 1;
    flex: 1;
}

[data-view="list"] .album__meta {
    display: block;
}

/* The inline track drawer. JS moves it to the end of the clicked album's
   visual row so the grid opens like a shelf. */
.album-panel {
    grid-column: 1 / -1;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 0.5rem;
    box-shadow: var(--shadow);
    animation: panel-in 0.18s var(--ease);
}

@keyframes panel-in {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: none; }
}

.album-panel__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.35rem 0.6rem;
    border-bottom: 1px solid var(--line);
    margin-bottom: 0.35rem;
}

.album-panel__titles {
    flex: 1;
    min-width: 0;
}

.album-panel__title {
    font-family: var(--font-display);
    font-size: 1.3rem;
    line-height: 1.1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.album-panel__sub {
    font-size: 0.75rem;
    color: var(--text-2);
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.45rem 0.8rem;
    border-radius: var(--r-sm);
    background: var(--surface-2);
    border: 1px solid var(--line);
    color: var(--text);
    font-size: 0.85rem;
    white-space: nowrap;
    transition: background 0.15s var(--ease), color 0.15s var(--ease);
}

.btn:hover {
    background: var(--surface-3);
}

.btn--accent {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.btn--accent:hover {
    background: var(--accent-2);
    border-color: var(--accent-2);
}

.btn--ok {
    background: var(--ok);
    border-color: var(--ok);
    color: var(--on-ok);
}

.btn--block {
    width: 100%;
}

.btn--ghost {
    background: transparent;
}

.tracklist {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.track {
    display: flex;
    align-items: stretch;
    gap: 1px;
    border-radius: var(--r-xs);
    overflow: hidden;
}

.track:nth-child(odd) {
    background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}

.track__play {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.6rem;
    text-align: left;
    border-radius: var(--r-xs);
}

.track__play:hover {
    background: var(--surface-3);
}

.track__num {
    flex: none;
    width: 1.6rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    color: var(--text-2);
}

.track__title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.track__queue {
    flex: none;
    width: 2.5rem;
    display: grid;
    place-items: center;
    border-radius: var(--r-xs);
    background: color-mix(in srgb, var(--accent) 30%, transparent);
    color: var(--text);
}

.track__queue:hover {
    background: var(--accent);
    color: var(--on-accent);
}

.track.is-queued .track__queue {
    background: var(--ok);
    color: var(--on-ok);
}

/* Suppressed: never picked automatically (album play, album queueing,
   shuffles), still plays when tapped. */
.track__suppress {
    flex: none;
    width: 2.5rem;
    display: grid;
    place-items: center;
    border-radius: var(--r-xs);
    color: var(--text-2);
}

.track__suppress:hover {
    background: var(--surface-3);
    color: var(--text);
}

.track.is-suppressed .track__suppress {
    background: var(--surface-3);
    color: var(--accent-2);
}

.track.is-suppressed .track__num,
.track.is-suppressed .track__title,
.qrow.is-suppressed .qrow__title {
    opacity: 0.45;
    text-decoration: line-through;
}

.track.is-playing,
.track.is-playing .track__play,
.track.is-playing .track__play:hover {
    background: var(--accent);
    color: var(--on-accent);
}

.track.is-playing .track__num {
    color: inherit;
    opacity: 0.75;
}

/* Offline: anything not in the track cache is unreachable, so hide it. */
.is-uncached {
    display: none !important;
}

/* --------------------------------------------------------------------------
   Search results & saved queues
   -------------------------------------------------------------------------- */

.results {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding-top: 0.5rem;
}

.results__empty {
    padding: 1.5rem 0.5rem;
    text-align: center;
    color: var(--text-2);
}

.result__title,
.result__sub {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.result__sub {
    font-size: 0.75rem;
    color: var(--text-2);
}

.section {
    margin-top: 1.5rem;
}

.section__title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    color: var(--text-2);
    padding: 0 0.2rem 0.4rem;
}

.savedqueue {
    display: flex;
    gap: 1px;
    margin-bottom: 0.3rem;
}

.savedqueue__open {
    flex: 1;
    min-width: 0;
    text-align: left;
    padding: 0.55rem 0.7rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-sm) 0 0 var(--r-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.savedqueue__open:hover {
    background: var(--surface-2);
}

.savedqueue__del {
    flex: none;
    width: 2.6rem;
    display: grid;
    place-items: center;
    background: color-mix(in srgb, var(--accent) 25%, transparent);
    border: 1px solid var(--line);
    border-left: 0;
    border-radius: 0 var(--r-sm) var(--r-sm) 0;
}

.savedqueue__del:hover {
    background: var(--accent);
    color: var(--on-accent);
}

.muted {
    color: var(--text-2);
    font-size: 0.85rem;
    padding: 0.25rem 0.2rem;
}

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

.player {
    padding: 0.75rem 0.9rem 6rem;
    max-width: var(--pane-max);
    width: 100%;
    margin: 0 auto;
}

.player__art {
    width: min(58vw, 320px);
    margin: 0.5rem auto 1rem;
    aspect-ratio: 1 / 1;
    border-radius: var(--r-lg);
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: var(--shadow);
}

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

/* Album art carousel: the playing album first, then recently played ones.
   Each slide is the size the single artwork used to be, and the side padding
   lets the first one sit centred with the next peeking in. The bottom padding
   leaves room for the artwork's shadow inside the scroller. */
.artstrip-wrap {
    --art-w: min(58vw, 320px);
    position: relative;
    margin-bottom: -0.75rem;
}

.artstrip {
    display: flex;
    gap: 0.9rem;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    padding: 0.5rem calc((100% - var(--art-w)) / 2) 1.75rem;
}

.artstrip::-webkit-scrollbar {
    display: none;
}

.artstrip .player__art {
    flex: none;
    position: relative;
    width: var(--art-w);
    margin: 0;
    padding: 0;
    scroll-snap-align: center;
}

.artstrip__item--recent {
    cursor: pointer;
}

.artstrip__name {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 1.6rem 0.75rem 0.6rem;
    background: linear-gradient(transparent, rgb(0 0 0 / 72%));
    color: #ffffff;
    font-size: 0.85rem;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Arrows for a mouse, which can't swipe. */
.artstrip__nav {
    display: none;
    position: absolute;
    top: calc(0.5rem + var(--art-w) / 2);
    transform: translateY(-50%);
    width: 2.2rem;
    height: 2.2rem;
    border-radius: 50%;
    place-items: center;
    background: var(--surface);
    border: 1px solid var(--line);
    color: var(--text);
    box-shadow: var(--shadow);
}

.artstrip__nav--prev {
    left: 0.25rem;
}

.artstrip__nav--prev .icon {
    transform: rotate(180deg);
}

.artstrip__nav--next {
    right: 0.25rem;
}

@media (hover: hover) and (pointer: fine) {
    .artstrip__nav:not([hidden]) {
        display: grid;
    }
}

.player__meta {
    text-align: center;
    margin-bottom: 0.9rem;
    min-height: 3.2rem;
}

.player__title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    line-height: 1.15;
}

.player__sub {
    font-size: 0.85rem;
    color: var(--text-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.player__status {
    margin-top: 0.25rem;
    font-size: 0.75rem;
    color: var(--accent-2);
}

.player__deck {
    position: sticky;
    top: 0;
    z-index: 15;
    padding: 0.6rem 0.2rem 0.5rem;
    background: var(--bg);
    background: color-mix(in srgb, var(--bg) 78%, transparent);
    backdrop-filter: blur(14px);
    border-radius: var(--r-md);
}

/* Seek + volume sliders ---------------------------------------------------- */

.slider {
    position: relative;
    height: 1.75rem;
    display: flex;
    align-items: center;
}

.slider__rail {
    position: absolute;
    left: 0;
    right: 0;
    height: 6px;
    border-radius: var(--r-pill);
    background: var(--track-bg);
    overflow: hidden;
}

.slider__buffer {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0;
    background: color-mix(in srgb, var(--text) 25%, transparent);
}

.slider__fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0;
    background: var(--accent);
}

.slider input[type="range"] {
    position: relative;
    z-index: 2;
    width: 100%;
    height: 1.75rem;
    margin: 0;
    background: transparent;
    -webkit-appearance: none;
    appearance: none;
}

.slider input[type="range"]::-webkit-slider-runnable-track {
    height: 1.75rem;
    background: transparent;
}

.slider input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    margin-top: calc((1.75rem - 16px) / 2);
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--bg);
    box-shadow: 0 1px 4px rgb(0 0 0 / 35%);
    cursor: pointer;
}

.slider input[type="range"]::-moz-range-track {
    height: 1.75rem;
    background: transparent;
    border: 0;
}

.slider input[type="range"]::-moz-range-thumb {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--accent);
    border: 2px solid var(--bg);
    cursor: pointer;
}

.times {
    display: flex;
    justify-content: space-between;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-2);
    padding: 0 0.1rem;
}

.transport {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    padding: 0.5rem 0 0.25rem;
}

.transport__btn {
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: var(--r-pill);
    background: var(--surface-2);
    color: var(--text);
    transition: background 0.15s var(--ease), transform 0.1s var(--ease);
}

.transport__btn:hover {
    background: var(--surface-3);
}

.transport__btn:active {
    transform: scale(0.94);
}

.transport__btn:disabled {
    opacity: 0.4;
    cursor: default;
}

.transport__btn--play {
    width: 3.75rem;
    height: 3.75rem;
    background: var(--accent);
    color: var(--on-accent);
}

.transport__btn--play:hover {
    background: var(--accent-2);
}

.transport__btn[aria-pressed="true"] {
    background: var(--ok);
    color: var(--on-ok);
}

.volume {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.25rem 0.5rem 0;
}

.volume .slider {
    flex: 1;
}

/* Panels ------------------------------------------------------------------- */

.panel {
    margin-top: 1rem;
    background: var(--surface);
    background: color-mix(in srgb, var(--surface) 70%, transparent);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 0.6rem;
}

.panel__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.panel__title {
    flex: 1;
    min-width: 0;
    font-family: var(--font-display);
    font-size: 1.2rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.queuelist {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.qrow {
    display: flex;
    gap: 1px;
    border-radius: var(--r-xs);
    overflow: hidden;
}

.qrow__play {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.6rem;
    text-align: left;
    background: color-mix(in srgb, var(--surface-2) 55%, transparent);
    border-radius: var(--r-xs);
}

.qrow__play:hover {
    background: var(--surface-3);
}

.qrow__title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.qrow__num {
    flex: none;
    width: 1.5rem;
    text-align: right;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-2);
}

.qrow__del {
    flex: none;
    width: 2.4rem;
    display: grid;
    place-items: center;
    background: color-mix(in srgb, var(--accent) 25%, transparent);
    border-radius: var(--r-xs);
}

.qrow__del:hover {
    background: var(--accent);
    color: var(--on-accent);
}

.qrow__del.is-added {
    background: var(--ok);
    color: var(--on-ok);
}

.qrow.is-unavailable .qrow__play {
    opacity: 0.4;
    text-decoration: line-through;
}

.qrow.is-playing .qrow__play {
    background: var(--accent);
    color: var(--on-accent);
}

.qrow.is-playing .qrow__num {
    color: inherit;
}

/* Settings ----------------------------------------------------------------- */

.settings__group + .settings__group {
    margin-top: 1.1rem;
}

.settings__label {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-2);
    margin-bottom: 0.45rem;
}

.swatches {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0.4rem;
}

/* The two colours are painted on the button itself (set inline): some iPhones
   never laid out coloured spans inside a <button>. */
.swatch {
    height: 2.2rem;
    border-radius: var(--r-sm);
    border: 1px solid var(--line);
    overflow: hidden;
    position: relative;
}

.swatch[aria-pressed="true"] {
    outline: 2px solid var(--text);
    outline-offset: 1px;
}

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

.row > * {
    min-width: 0;
}

.stack {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

#btn-refresh-library:disabled {
    opacity: 0.7;
}

/* --------------------------------------------------------------------------
   Tab bar (small screens)
   -------------------------------------------------------------------------- */

.tabbar {
    flex: none;
    display: flex;
    position: relative;
    z-index: 30;
    /* box-sizing is border-box everywhere, so the safe-area padding has to be
       *added* to the height. Setting height to --tabbar-h alone left a notched
       iPhone with a 22px bar and its icons clipped out of it. */
    height: calc(var(--tabbar-h) + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
    background: var(--bg);
    background: color-mix(in srgb, var(--bg) 85%, transparent);
    backdrop-filter: blur(14px);
    border-top: 1px solid var(--line);
}

.tabbar__btn {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.1rem;
    font-size: 0.7rem;
    color: var(--text-2);
}

.tabbar__btn[aria-selected="true"] {
    color: var(--accent-2);
}

.tabbar__now {
    max-width: 90%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Modal
   -------------------------------------------------------------------------- */

.modal {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: grid;
    place-items: center;
    padding: 1.5rem;
    background: rgb(0 0 0 / 55%);
    animation: fade-in 0.15s var(--ease);
}

@keyframes fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

.modal__box {
    width: min(24rem, 100%);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 1.1rem;
    box-shadow: var(--shadow);
}

.modal__text {
    margin-bottom: 1rem;
}

.modal__actions {
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
}

.toast {
    position: fixed;
    left: 50%;
    bottom: calc(var(--tabbar-h) + var(--safe-bottom) + 1rem);
    transform: translateX(-50%);
    z-index: 90;
    background: var(--surface-3);
    color: var(--text);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 0.5rem 1rem;
    font-size: 0.85rem;
    box-shadow: var(--shadow);
    animation: fade-in 0.15s var(--ease);
}

/* --------------------------------------------------------------------------
   Login
   -------------------------------------------------------------------------- */

.login {
    height: 100vh;
    height: 100svh;
    display: grid;
    place-items: center;
    padding: 1.5rem;
    background: var(--player-bg);
}

.login__box {
    width: min(22rem, 100%);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 1.5rem;
    box-shadow: var(--shadow);
}

.login__brand {
    font-family: var(--font-display);
    font-size: 2rem;
    text-align: center;
    margin-bottom: 1.25rem;
}

.login__field {
    margin-bottom: 0.9rem;
}

.login__field label {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-2);
    margin-bottom: 0.3rem;
}

.login__field .field {
    width: 100%;
}

/* --------------------------------------------------------------------------
   Larger screens: real two-pane layout, no tab bar
   -------------------------------------------------------------------------- */

@media (min-width: 62em) {
    .panes {
        display: grid;
        grid-template-columns: minmax(22rem, 5fr) 6fr;
        overflow: hidden;
    }

    .pane {
        width: auto;
    }

    .pane--player {
        border-left: 1px solid var(--line);
    }

    .tabbar {
        display: none;
    }

    .albumgrid {
        grid-template-columns: repeat(auto-fill, minmax(124px, 1fr));
    }

    /* A quarter smaller than on phones' proportions, leaving the queue more room. */
    .player__art {
        width: min(30vw, 225px);
    }

    .artstrip-wrap {
        --art-w: min(30vw, 225px);
    }

    /* Desktop only: the player pane stops scrolling so the artwork and
       controls stay in view, and the Up next list (or the settings) scrolls
       inside its panel instead. A window too short for even that falls back
       to scrolling the whole pane. */
    .pane--player > .player {
        display: flex;
        flex-direction: column;
        height: 100%;
        padding-bottom: 1rem;
    }

    .pane--player > .player > :not(.panel) {
        flex: none;
    }

    .pane--player .panel {
        flex: 1 1 auto;
        min-height: 9rem;
    }

    #panel-upnext {
        display: flex;
        flex-direction: column;
    }

    #panel-upnext .queuelist {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    /* The list is a flex column too; without this its rows would shrink to
       fit its height instead of scrolling. */
    #panel-upnext .queuelist > * {
        flex: none;
    }

    #panel-settings {
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    .toast {
        bottom: 1.5rem;
    }
}

@media (min-width: 100em) {
    .albumgrid {
        grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}
