/* Mixterverse Radio — LoFi-Girl-style always-on radio. Minimal + beautiful.
   Paired with radio.php + js/radio.js. Spec: mixterversePublic/landingPageRadio.md */

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
    font-family: 'Ubuntu', sans-serif;
    background: #0f0d0c;
    color: #f2ede9;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
}

/* ---- Full-bleed crossfading slideshow ---- */
.radio-stage { position: fixed; inset: 0; z-index: 0; background: #0f0d0c; }
.slide {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    opacity: 0;
    transition: opacity 2.4s ease-in-out;
    transform: scale(1.03);          /* slight zoom so the crossfade feels alive */
    will-change: opacity;
}
.slide.show { opacity: 1; }
/* Until images load, a calm gradient rather than black. */
.radio-stage::before {
    content: "";
    position: absolute; inset: 0;
    background: radial-gradient(130% 100% at 50% 15%, #2a2233 0%, #14100f 65%, #0f0d0c 100%);
}
.radio-scrim {
    position: absolute; inset: 0;
    /* Legibility wash top + bottom, image stays bright in the middle. */
    background:
        linear-gradient(to bottom, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0) 26%),
        linear-gradient(to top,    rgba(0,0,0,0.55) 0%, rgba(0,0,0,0) 34%);
}

/* ---- Wordmark ---- */
.radio-brand {
    position: fixed;
    top: 22px; left: 26px;
    z-index: 3;
    font-weight: 700;
    font-size: 0.95rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(255,255,255,0.82);
    text-shadow: 0 1px 10px rgba(0,0,0,0.6);
    pointer-events: none;
}

/* ---- Centered UI (station picker + player) ---- */
.radio-ui {
    position: fixed;
    inset: 0;
    z-index: 4;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 30px;
    padding: 24px;
    text-align: center;
}

/* ---- Signed-in greeting ----
   The first thing on the pre-play screen, because landing here is what sign-in is for. Same crisp
   black outline the rest of the UI uses, so it survives a bright photo. It fades out the moment a
   station starts — a greeting that stayed up would just be furniture over the artwork. */
.radio-welcome {
    font-size: 1.7rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: #fff;
    text-shadow:
        -1px -1px 0 rgba(0,0,0,0.85),  1px -1px 0 rgba(0,0,0,0.85),
        -1px  1px 0 rgba(0,0,0,0.85),  1px  1px 0 rgba(0,0,0,0.85),
        0 2px 16px rgba(0,0,0,0.65);
    margin-bottom: -6px;                 /* the .radio-ui gap is sized for the picker alone */
    opacity: 1;
    transform: none;
    transition: opacity 0.5s ease, transform 0.5s ease, margin 0.5s ease;
}
.radio-welcome[hidden] { display: none; }
.radio-welcome a { color: inherit; text-decoration: none; }
.radio-welcome a:hover, .radio-welcome a:focus-visible {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 5px;
    text-decoration-color: #E77D42;
}
/* Music started — step aside. */
body.has-station .radio-welcome {
    opacity: 0;
    transform: translateY(-8px);
    margin-bottom: -34px;
    pointer-events: none;
}

.station-picker {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    max-width: 640px;
}
.station {
    font-family: inherit;
    font-size: 1.02rem;
    font-weight: 700;
    color: #f2ede9;
    /* Smallest crisp black outline so labels stay legible on near-white images. */
    text-shadow:
        -1px -1px 0 rgba(0,0,0,0.85),  1px -1px 0 rgba(0,0,0,0.85),
        -1px  1px 0 rgba(0,0,0,0.85),  1px  1px 0 rgba(0,0,0,0.85);
    background: rgba(255,255,255,0.10);
    border: 1px solid rgba(255,255,255,0.22);
    backdrop-filter: blur(7px);
    -webkit-backdrop-filter: blur(7px);
    padding: 12px 24px;
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}
.station:hover { background: rgba(255,255,255,0.18); transform: translateY(-1px); }
.station.active {
    background: #E77D42;
    border-color: #E77D42;
    color: #fff;
    box-shadow: 0 6px 22px rgba(231,125,66,0.4);
}

/* Player row is hidden until a station is picked. */
.player-row {
    display: flex;
    align-items: center;
    gap: 16px;
    max-width: 90vw;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.3s ease, transform 0.3s ease;
    pointer-events: none;
}
body.has-station .player-row { opacity: 1; transform: none; pointer-events: auto; }

.play-toggle {
    flex: 0 0 auto;
    width: 56px; height: 56px;
    border-radius: 50%;
    border: none;
    background: rgba(255,255,255,0.14);
    color: #fff;
    font-size: 1.1rem;
    line-height: 56px;
    cursor: pointer;
    backdrop-filter: blur(7px);
    -webkit-backdrop-filter: blur(7px);
    transition: background 0.15s ease, transform 0.1s ease;
}
.play-toggle:hover { background: rgba(255,255,255,0.24); }
.play-toggle:active { transform: scale(0.94); }

.now-playing {
    font-size: 0.98rem;
    color: rgba(255,255,255,0.9);
    /* 1px black outline (legibility on near-white images) + a soft glow for depth. */
    text-shadow:
        -1px -1px 0 rgba(0,0,0,0.85),  1px -1px 0 rgba(0,0,0,0.85),
        -1px  1px 0 rgba(0,0,0,0.85),  1px  1px 0 rgba(0,0,0,0.85),
        0 1px 8px rgba(0,0,0,0.6);
    min-height: 1.2em;
    max-width: 60vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.now-playing .np-title { font-weight: 700; }
.now-playing .np-by    { opacity: 0.6; }
.now-playing .np-artist { opacity: 0.85; }

/* The title links to the track's page on whichever library it came from. The text stays white —
   it has to survive a near-white photo — so the library colour rides on the underline instead:
   ccMixter green, MixterPlus blue, the mixterverse-wide "which library is this?" convention.
   A real underline, not a border-bottom: .now-playing is overflow:hidden (it ellipsises long
   titles), and a border sits outside the line box where that clipping would eat it. */
a.np-title {
    color: inherit;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    text-decoration-color: rgba(255,255,255,0.45);
    transition: text-decoration-color 0.15s ease, color 0.15s ease;
}
a.np-title.src-ccm { text-decoration-color: #191; }        /* ccMixter */
a.np-title.src-mp  { text-decoration-color: #518BA1; }     /* MixterPlus */
a.np-title:hover, a.np-title:focus-visible {
    color: #fff;
    text-decoration-color: rgba(255,255,255,0.95);
    text-decoration-thickness: 2px;
}

/* ---- Favorites heart (player row) ----
   Text-free toggle. Outline when unsaved, filled + library-coloured when saved: ccMixter green,
   MixterPlus blue — the mixterverse-wide "which library is this from?" convention. */
.fav-toggle {
    flex: 0 0 auto;
    font-family: inherit;
    font-size: 1.5rem;
    line-height: 1;
    background: none;
    border: none;
    padding: 4px 2px;
    cursor: pointer;
    color: rgba(255,255,255,0.75);
    /* Same 1px black outline the rest of the row uses, so it survives a near-white image. */
    text-shadow:
        -1px -1px 0 rgba(0,0,0,0.85),  1px -1px 0 rgba(0,0,0,0.85),
        -1px  1px 0 rgba(0,0,0,0.85),  1px  1px 0 rgba(0,0,0,0.85);
    transition: color 0.15s ease, transform 0.1s ease, opacity 0.15s ease;
}
.fav-toggle:hover { color: #fff; transform: scale(1.08); }
.fav-toggle:active { transform: scale(0.92); }
.fav-toggle.on.src-ccm { color: #191; }        /* ccMixter */
.fav-toggle.on.src-mp  { color: #518BA1; }     /* MixterPlus */
/* Signed out, or nothing playing yet — present but receding. */
.fav-toggle.muted { opacity: 0.5; }

/* The word next to the heart — "Sign in to save" signed out, "Save" signed in. A soft glow was
   not enough over a bright photo, so both carry the same crisp 1px black outline as the station
   pills and the title, on brighter text. */
.fav-signin, .fav-save {
    flex: 0 0 auto;
    font-family: inherit;
    font-size: 0.84rem;
    font-weight: 700;
    color: rgba(255,255,255,0.92);
    text-decoration: none;
    background: none;
    border: none;
    border-bottom: 1px solid rgba(255,255,255,0.35);
    padding: 0 0 1px;
    text-shadow:
        -1px -1px 0 rgba(0,0,0,0.85),  1px -1px 0 rgba(0,0,0,0.85),
        -1px  1px 0 rgba(0,0,0,0.85),  1px  1px 0 rgba(0,0,0,0.85),
        0 1px 8px rgba(0,0,0,0.6);
    white-space: nowrap;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.fav-signin:hover, .fav-save:hover:not(:disabled) { color: #fff; border-color: #E77D42; }
/* Already saved: the label agrees with the filled heart instead of contradicting it. */
.fav-save.on { border-bottom-color: rgba(255,255,255,0.18); color: rgba(255,255,255,0.75); }
/* Nothing playing yet — nothing to save. */
.fav-save:disabled { opacity: 0.45; cursor: default; }
.fav-save[hidden] { display: none; }
/* Both states are always in the DOM so js/radio.js can swap them without building markup. */
.fav-signin[hidden] { display: none; }

/* A single soft pulse when someone taps the heart while signed out — a nudge, not a nag. */
.fav-signin.nudge { animation: favNudge 1.1s ease; }
@keyframes favNudge {
    0%, 100% { color: rgba(255,255,255,0.7); }
    35%      { color: #E77D42; border-color: #E77D42; }
}

/* ---- Image credit ----
   Attribution for the slideshow art, which MixterPlus users uploaded. Bottom-left, diagonally
   opposite the DOC stamp and sitting inside the scrim's bottom wash, at a weight that reads as a
   caption rather than UI. It fades out and back with each crossfade (js/radio.js setCredit), and
   `:empty` keeps it invisible until the first image is actually up. */
.image-credit {
    position: fixed;
    left: 26px; bottom: 26px;
    z-index: 5;
    max-width: min(38vw, 420px);
    font-size: 0.72rem;
    line-height: 1.35;
    color: rgba(255,255,255,0.55);
    text-shadow: 0 1px 8px rgba(0,0,0,0.75), 0 0 2px rgba(0,0,0,0.6);
    opacity: 1;
    transition: opacity 0.6s ease;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.image-credit:empty      { opacity: 0; }   /* before the first slide */
.image-credit.swapping   { opacity: 0; }   /* mid-crossfade */
.image-credit a {
    color: rgba(255,255,255,0.72);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    text-decoration-color: rgba(255,255,255,0.2);
    transition: color 0.15s ease, text-decoration-color 0.15s ease;
}
/* Every one of these images is a MixterPlus upload — so the one accent here is M+ blue. */
.image-credit a:hover, .image-credit a:focus-visible {
    color: #fff;
    text-decoration-color: #518BA1;
}
.image-credit .ic-title  { font-style: italic; }
.image-credit .ic-by     { opacity: 0.7; }
.image-credit .ic-artist { font-weight: 700; }

/* mvAdmin sessions get the flag panel in this exact corner, so move the credit up under the
   wordmark for them. Nobody else ever sees this variant. */
body.is-mvadmin .image-credit {
    bottom: auto;
    top: 46px;
    max-width: min(46vw, 420px);
}

/* ---- Close / back ---- */
.radio-home {
    position: fixed;
    top: 20px; right: 22px;
    z-index: 5;
    width: 40px; height: 40px;
    display: flex; align-items: center; justify-content: center;
    color: rgba(255,255,255,0.75);
    text-decoration: none;
    font-size: 1.1rem;
    border-radius: 50%;
    transition: background 0.15s ease, color 0.15s ease;
}
.radio-home:hover { background: rgba(255,255,255,0.14); color: #fff; }

/* ---- DOC-style "certified human" stamp ---- */
.doc-stamp {
    position: fixed;
    right: 26px; bottom: 26px;
    z-index: 5;
    width: 276px; height: 276px;                 /* quadrupled area (2x w, 2x h) */
    display: flex; align-items: center; justify-content: center;
    text-align: center;
    padding: 26px;
    transform: rotate(-8deg);
    border: 5px double #eaa07f;
    border-radius: 50%;
    color: #f6c9b2;
    font-weight: 700;
    font-size: 1.5rem;
    line-height: 1.2;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    opacity: 0.9;
    pointer-events: none;
    text-shadow: 0 1px 8px rgba(0,0,0,0.6);
    box-shadow: inset 0 0 0 1px rgba(246,201,178,0.35);
    transition: opacity 0.6s ease;               /* fade during the phrase swap */
}
/* Momentary fade-out while radio.js swaps in the next phrase (on each image change). */
.doc-stamp.swapping { opacity: 0; }

/* ---- Admin flag overlay ----
   Only in the DOM for an mvAdmin session (radio.php). Bottom-left, opposite the DOC stamp: present
   enough to use at a glance, quiet enough that a screenshot of the radio still looks like the radio.
   It fades to half opacity until you approach it, so it never competes with the artwork. */
.admin-flag {
    position: fixed;
    left: 20px; bottom: 22px;
    z-index: 6;
    width: 268px;
    max-width: calc(100vw - 40px);
    padding: 12px 14px 13px;
    border-radius: 12px;
    background: rgba(16, 14, 20, 0.62);
    border: 1px solid rgba(255,255,255,0.16);
    backdrop-filter: blur(9px);
    -webkit-backdrop-filter: blur(9px);
    box-shadow: 0 10px 34px rgba(0,0,0,0.45);
    font-size: 0.82rem;
    opacity: 0.5;
    transition: opacity 0.2s ease;
}
.admin-flag:hover, .admin-flag:focus-within { opacity: 1; }

.af-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-bottom: 9px;
}
.af-tag {
    font-size: 0.64rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
    color: #E77D42;                                  /* the mvAdmin accent */
}
.af-list-toggle {
    font-family: inherit; font-size: 0.72rem;
    background: none; border: none; padding: 0;
    color: rgba(255,255,255,0.6);
    border-bottom: 1px dashed rgba(255,255,255,0.28);
    cursor: pointer;
}
.af-list-toggle:hover { color: #fff; }

.af-actions { display: flex; flex-direction: column; gap: 6px; }
.af-btn {
    font-family: inherit; font-size: 0.8rem; text-align: left;
    padding: 8px 11px;
    border-radius: 8px;
    border: 1px solid rgba(255,255,255,0.2);
    background: rgba(255,255,255,0.08);
    color: #f2ede9;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.af-btn:hover:not(:disabled) { background: rgba(231,125,66,0.28); border-color: #E77D42; }
/* "Not for radio" is the bigger hammer — tint it so the two are never confused mid-click. */
.af-btn-hard:hover:not(:disabled) { background: rgba(192,57,43,0.34); border-color: #c0392b; }
.af-btn:disabled { opacity: 0.4; cursor: default; }

.af-note {
    min-height: 1.1em; margin-top: 7px;
    font-size: 0.72rem; color: rgba(255,255,255,0.62);
}

.af-list {
    list-style: none; margin: 6px 0 0; padding: 6px 0 0;
    border-top: 1px solid rgba(255,255,255,0.14);
    max-height: 30vh; overflow-y: auto;
}
.af-list li {
    display: flex; align-items: baseline; gap: 7px;
    padding: 4px 0;
    font-size: 0.74rem;
    color: rgba(255,255,255,0.72);
}
.af-undo {
    flex: 0 0 auto;
    font-family: inherit; font-size: 0.7rem; line-height: 1;
    background: none; border: none; padding: 2px 3px;
    color: rgba(255,255,255,0.45);
    cursor: pointer;
}
.af-undo:hover { color: #E77D42; }
.af-undo:disabled { opacity: 0.4; cursor: default; }
.af-where {
    flex: 0 0 auto;
    font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.04em;
    color: rgba(255,255,255,0.45);
}
.af-what { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- Mobile ---- */
@media (max-width: 640px) {
    /* The DOC stamp owns the bottom-right; drop the panel to full width above it. */
    .admin-flag { left: 12px; right: 12px; width: auto; bottom: 12px; opacity: 1; }
    .af-list { max-height: 22vh; }
    .radio-brand { font-size: 0.82rem; top: 16px; left: 18px; }
    .station { font-size: 0.94rem; padding: 11px 20px; }
    .doc-stamp { width: 208px; height: 208px; font-size: 1.1rem; padding: 20px; right: 16px; bottom: 16px; }
    /* Heart + nudge share the row now, so the title gets less of it. */
    .now-playing { max-width: 46vw; }
    .fav-signin, .fav-save { font-size: 0.76rem; }
    .radio-welcome { font-size: 1.3rem; }
    /* The DOC stamp claims 208px of the bottom-right; keep the credit clear of it and let it wrap
       to two lines rather than truncating an artist's name to nothing. */
    .image-credit {
        left: 16px; bottom: 16px;
        max-width: calc(100vw - 246px);
        font-size: 0.68rem;
        white-space: normal;
    }
    body.is-mvadmin .image-credit { top: 40px; max-width: calc(100vw - 246px); }
}
