- Dual mode (separate video + audio, used by adaptive streams and the iPhone EQ copies): going to the background now makes the audio the master, so progress, Now Playing and auto-advance keep working while iOS has the video suspended (the paused video used to be the only source of "ended", so playback stopped after the current song). The picture is re-synced on return. - A track that starts while the app is in the background (auto-advance, the lock-screen Next button) starts as audio — iOS will not start a <video> there — and gets its picture back at the same position when the app returns. - The handoff also runs on pagehide and when iOS pauses the master video while the page is hidden, for when visibilitychange arrives too late. - Classic: playlist cards place their three actions as a 2x2 block (note + add on top, remove below) instead of the note button wrapping to the bottom-left. - Save to this device: hide the full progress bar once the file is ready; it read as a squashed, broken button above "Save to Photos / Files".
602 lines
26 KiB
CSS
602 lines
26 KiB
CSS
/* ============================================================================
|
||
* Layout refresh: playlist header, player deck, now-playing actions, lyrics panel
|
||
*
|
||
* Loaded after styles.css. Uses #id-prefixed selectors so it wins over the
|
||
* older per-breakpoint rules without needing !important. The theme tokens
|
||
* (--bg-*, --accent*, --line, --text*) are reused so light / contrast themes
|
||
* keep working.
|
||
* ========================================================================== */
|
||
|
||
/* ---- 1. Playlist / list header: title on top, ONE primary action, tidy rest --- */
|
||
.list-header {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
gap: 14px;
|
||
}
|
||
.list-header h2 {
|
||
font-size: clamp(26px, 6.4vw, 34px);
|
||
line-height: 1.05;
|
||
letter-spacing: -0.03em;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
#listActions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
gap: 8px;
|
||
}
|
||
#listActions button {
|
||
flex: 0 0 auto;
|
||
height: 36px;
|
||
padding: 0 14px;
|
||
border-radius: 999px;
|
||
font-size: 13px;
|
||
white-space: nowrap;
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
}
|
||
#listActions button.la-primary {
|
||
flex: 1 1 100%;
|
||
height: 54px;
|
||
border: 0;
|
||
border-radius: 18px;
|
||
font-size: 16px;
|
||
font-weight: 800;
|
||
letter-spacing: 0.01em;
|
||
justify-content: center;
|
||
color: #fff;
|
||
background: linear-gradient(145deg, var(--accent-bright), var(--accent-deep));
|
||
box-shadow: 0 16px 30px -14px var(--accent-glow);
|
||
}
|
||
#listActions button.la-primary:hover { color: #fff; filter: brightness(1.08); }
|
||
#listActions button.la-main {
|
||
flex: 1 1 calc(33.3% - 8px);
|
||
min-width: 0;
|
||
height: 46px;
|
||
border-radius: 14px;
|
||
justify-content: center;
|
||
color: var(--text);
|
||
background: var(--bg-3);
|
||
overflow: hidden; text-overflow: ellipsis;
|
||
}
|
||
/* Secondary actions sit on a quiet second line, visually below the main three. */
|
||
#listActions button.la-main + button:not(.la-main) { margin-left: 0; }
|
||
#listActions button:not(.la-primary):not(.la-main):not(.la-icon) {
|
||
background: transparent;
|
||
color: var(--text-dim);
|
||
font-weight: 600;
|
||
}
|
||
#listActions button:not(.la-primary):not(.la-main):not(.la-icon):hover { color: var(--text); background: var(--bg-2); }
|
||
#listActions button.pinned { color: var(--accent-bright); border-color: var(--accent); background: transparent; }
|
||
#listActions button.la-main { padding: 0 6px; font-size: 13px; }
|
||
@media (min-width: 900px) {
|
||
#listActions button.la-primary { flex: 0 0 auto; height: 44px; padding: 0 26px; border-radius: 14px; }
|
||
#listActions button.la-main { flex: 0 0 auto; height: 44px; padding: 0 18px; }
|
||
}
|
||
|
||
/* ---- 2. Player deck ------------------------------------------------------- */
|
||
#controls {
|
||
padding: 18px 16px 16px;
|
||
border-radius: 24px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14px;
|
||
}
|
||
#controls .seek-row { gap: 10px; }
|
||
#controls .time { min-width: 40px; font-size: 12px; color: var(--text-dim); }
|
||
|
||
#controls .deck-main {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1.5fr 1fr 1fr;
|
||
align-items: center;
|
||
justify-items: center;
|
||
gap: 4px;
|
||
margin: 2px 0 0;
|
||
}
|
||
#controls .deck-main .ctrl {
|
||
width: 48px; height: 48px; min-width: 0;
|
||
border-radius: 50%;
|
||
border-color: transparent;
|
||
background: transparent;
|
||
font-size: 19px;
|
||
}
|
||
#controls .deck-main .ctrl:hover { background: var(--bg-3); }
|
||
#controls .deck-main .ctrl.active { color: var(--accent-bright); background: color-mix(in srgb, var(--accent) 16%, transparent); }
|
||
#controls .deck-main .ctrl.play {
|
||
width: 74px; height: 74px;
|
||
font-size: 26px;
|
||
background: linear-gradient(145deg, var(--accent-bright), var(--accent-deep));
|
||
box-shadow: 0 18px 34px -12px var(--accent-glow), inset 0 1px 0 rgba(255, 255, 255, 0.25);
|
||
}
|
||
|
||
#controls .deck-vol {
|
||
display: flex; align-items: center; gap: 10px;
|
||
padding: 0 4px;
|
||
}
|
||
#controls .deck-vol .ctrl { width: 38px; height: 38px; min-width: 0; border-radius: 50%; background: transparent; border-color: transparent; font-size: 17px; }
|
||
#controls .deck-vol input[type="range"] { flex: 1; width: auto; min-width: 0; }
|
||
|
||
#controls .deck-groups {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 10px;
|
||
}
|
||
#controls .dk-group {
|
||
min-width: 0;
|
||
padding: 10px 10px 10px;
|
||
border-radius: 18px;
|
||
background: color-mix(in srgb, var(--bg) 55%, transparent);
|
||
border: 1px solid var(--line-soft, var(--line));
|
||
}
|
||
#controls .dk-title {
|
||
margin: 0 2px 8px;
|
||
font: 700 10px/1 var(--mono);
|
||
letter-spacing: 0.16em;
|
||
text-transform: uppercase;
|
||
color: var(--text-dim);
|
||
}
|
||
#controls .dk-tiles {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 6px;
|
||
}
|
||
#controls .dk-tiles .ctrl {
|
||
width: 100%; min-width: 0; height: 44px;
|
||
border-radius: 13px;
|
||
font-size: 16px;
|
||
}
|
||
#controls .dk-tiles .ctrl.hidden { display: none; }
|
||
#controls .dk-sel {
|
||
grid-column: span 3;
|
||
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
||
height: 40px; padding: 0 4px 0 10px;
|
||
border-radius: 13px;
|
||
background: var(--bg-3);
|
||
border: 1px solid var(--line);
|
||
}
|
||
#controls .dk-sel select {
|
||
flex: 1; min-width: 0;
|
||
height: 34px;
|
||
border: 0; background: transparent;
|
||
text-align: right; text-align-last: right;
|
||
font-size: 14px; font-weight: 700;
|
||
padding: 0 4px;
|
||
}
|
||
@media (max-width: 480px) {
|
||
#controls .deck-groups { grid-template-columns: 1fr; }
|
||
#controls .dk-tiles { grid-template-columns: repeat(auto-fit, minmax(52px, 1fr)); }
|
||
#controls .dk-sel { grid-column: 1 / -1; }
|
||
#controls .deck-main .ctrl { width: 44px; height: 44px; }
|
||
#controls .deck-main .ctrl.play { width: 70px; height: 70px; }
|
||
}
|
||
|
||
/* ---- 3. Now playing: name first, actions as clear tiles, extras as chips ---- */
|
||
#nowPlayingMeta {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
gap: 14px;
|
||
margin-top: 22px;
|
||
}
|
||
#nowPlayingMeta .np-title {
|
||
font-size: clamp(22px, 5.6vw, 28px);
|
||
line-height: 1.15;
|
||
letter-spacing: -0.025em;
|
||
}
|
||
#nowPlayingMeta .np-channel { margin-top: 4px; }
|
||
#nowPlayingMeta .np-actions {
|
||
display: flex; flex-wrap: wrap; gap: 8px;
|
||
max-width: none;
|
||
}
|
||
#nowPlayingMeta .np-actions .np-btn {
|
||
flex: 0 0 auto;
|
||
height: 38px; padding: 0 14px;
|
||
border-radius: 999px;
|
||
background: transparent;
|
||
color: var(--text-2);
|
||
font-size: 13px;
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
}
|
||
/* The three everyday actions are big equal tiles on their own line. */
|
||
#nowPlayingMeta .np-actions #queueBtn,
|
||
#nowPlayingMeta .np-actions #saveBtn,
|
||
#nowPlayingMeta .np-actions #addPlaylistBtn {
|
||
order: -1;
|
||
flex: 1 1 calc(33.3% - 8px);
|
||
height: 52px;
|
||
justify-content: center;
|
||
border-radius: 16px;
|
||
color: var(--text);
|
||
background: var(--bg-3);
|
||
font-weight: 700;
|
||
}
|
||
#nowPlayingMeta .np-actions #saveBtn.done {
|
||
color: #7ee0a8;
|
||
background: rgba(126, 224, 168, 0.1);
|
||
}
|
||
#nowPlayingMeta .np-actions #brokenBtn { color: var(--text-dim); }
|
||
|
||
/* ---- 4. Lyrics panel ------------------------------------------------------- */
|
||
.notes-panel { border-radius: 24px; }
|
||
.notes-tabs {
|
||
gap: 6px;
|
||
padding: 10px 12px;
|
||
border-bottom: 0;
|
||
}
|
||
.notes-tab {
|
||
border: 0;
|
||
border-radius: 999px;
|
||
padding: 9px 14px;
|
||
letter-spacing: 0.1em;
|
||
background: transparent;
|
||
}
|
||
.notes-tab.active {
|
||
color: #fff;
|
||
background: color-mix(in srgb, var(--accent) 30%, transparent);
|
||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
|
||
}
|
||
.notes-pane { padding: 4px 14px 16px; }
|
||
|
||
#lyricsPane .lyrics-toolbar {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 8px;
|
||
margin-bottom: 14px;
|
||
}
|
||
#lyricsPane .lyrics-toolbar .np-btn {
|
||
height: 42px; padding: 0 8px;
|
||
border-radius: 13px;
|
||
justify-content: center;
|
||
font-size: 13px;
|
||
background: var(--bg-3);
|
||
color: var(--text);
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
}
|
||
#lyricsPane .lyrics-toolbar .notes-spacer { display: none; }
|
||
#lyricsPane .lyrics-toolbar .lyr-offset {
|
||
grid-column: 1 / 3;
|
||
height: 42px;
|
||
justify-content: space-between;
|
||
border-radius: 13px; padding: 3px;
|
||
}
|
||
#lyricsPane .lyr-off-btn { flex: none; height: 34px; padding: 0 12px; font-size: 12px; background: var(--bg-3); }
|
||
#lyricsPane .lyr-off-val { flex: 1; font-size: 13px; }
|
||
#lyricsPane .lyr-auto {
|
||
grid-column: 3;
|
||
height: 42px; justify-content: center;
|
||
border-radius: 13px; border: 1px solid var(--line);
|
||
font-size: 12px; font-weight: 600;
|
||
}
|
||
.lyr-auto input { accent-color: var(--accent); width: 16px; height: 16px; }
|
||
|
||
.lyrics-list { padding-top: 6px; }
|
||
.lyr-line {
|
||
padding: 10px 12px;
|
||
border-radius: 14px;
|
||
gap: 14px;
|
||
align-items: center;
|
||
}
|
||
.lyr-time {
|
||
width: auto; min-width: 34px;
|
||
padding: 3px 7px;
|
||
border-radius: 8px;
|
||
background: var(--bg-1);
|
||
text-align: center;
|
||
}
|
||
.lyr-text { font-size: 16px; line-height: 1.4; }
|
||
.lyr-line.active {
|
||
background: color-mix(in srgb, var(--accent) 14%, var(--bg-3));
|
||
box-shadow: inset 3px 0 0 var(--accent);
|
||
}
|
||
.lyr-line.active .lyr-text { font-size: 18px; }
|
||
.lyr-section { margin: 20px 0 6px 12px; }
|
||
|
||
@media (max-width: 380px) {
|
||
#lyricsPane .lyrics-toolbar .np-btn { font-size: 12px; }
|
||
.notes-tab { padding: 8px 10px; letter-spacing: 0.06em; }
|
||
}
|
||
|
||
/* Cards in the player column never shrink below their content. */
|
||
#controls, #nowPlayingMeta, #notesPanel { flex-shrink: 0; }
|
||
#lyricsPane .lyr-auto { font-size: 11.5px; gap: 5px; padding: 0 4px; white-space: nowrap; }
|
||
|
||
/* ---- Round 2: uniform secondary buttons, deck tabs, borderless autoscroll, reports in the lyrics panel ---- */
|
||
#listActions button:not(.la-primary):not(.la-main):not(.la-icon) {
|
||
flex: 0 0 calc(50% - 4px);
|
||
height: 40px;
|
||
padding: 0 10px;
|
||
justify-content: center;
|
||
border: 1px solid var(--line);
|
||
border-radius: 12px;
|
||
font-size: 13px;
|
||
overflow: hidden; text-overflow: ellipsis;
|
||
}
|
||
@media (min-width: 900px) {
|
||
#listActions button:not(.la-primary):not(.la-main):not(.la-icon) { flex: 0 0 auto; min-width: 124px; }
|
||
}
|
||
#nowPlayingMeta .np-actions .np-btn:not(#addBtn):not(#serviceBtn):not(#queueBtn):not(#saveBtn):not(#exportBtn):not(#addPlaylistBtn) {
|
||
flex: 0 0 calc(50% - 4px);
|
||
height: 42px;
|
||
padding: 0 10px;
|
||
justify-content: center;
|
||
border-radius: 12px;
|
||
overflow: hidden; text-overflow: ellipsis;
|
||
}
|
||
@media (min-width: 900px) {
|
||
#nowPlayingMeta .np-actions .np-btn:not(#addBtn):not(#serviceBtn):not(#queueBtn):not(#saveBtn):not(#exportBtn):not(#addPlaylistBtn) { flex: 0 0 auto; min-width: 140px; }
|
||
}
|
||
|
||
/* Deck tabs */
|
||
#controls .dk-tabs {
|
||
display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
|
||
padding: 4px; border-radius: 14px;
|
||
background: color-mix(in srgb, var(--bg) 60%, transparent);
|
||
border: 1px solid var(--line-soft, var(--line));
|
||
}
|
||
#controls .dk-tab {
|
||
height: 38px; border: 0; border-radius: 10px; cursor: pointer;
|
||
background: transparent; color: var(--text-dim);
|
||
font: 700 11px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase;
|
||
transition: background 0.16s, color 0.16s;
|
||
}
|
||
#controls .dk-tab.active {
|
||
color: #fff;
|
||
background: color-mix(in srgb, var(--accent) 30%, transparent);
|
||
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
|
||
}
|
||
#controls .deck-groups { grid-template-columns: 1fr; }
|
||
#controls .dk-group { padding: 8px; }
|
||
#controls .dk-tiles { grid-template-columns: repeat(auto-fit, minmax(56px, 1fr)); }
|
||
|
||
/* Autoscroll: checkbox + label without a box around them */
|
||
#lyricsPane .lyr-auto { border: 0; background: transparent; }
|
||
|
||
/* Report toggle in the lyrics toolbar */
|
||
#lyricsPane .lyr-flag {
|
||
grid-column: 1 / -1;
|
||
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
||
height: 40px; border-radius: 12px; cursor: pointer;
|
||
border: 1px dashed color-mix(in srgb, #ffb454 55%, transparent);
|
||
background: transparent; color: #ffb454;
|
||
font: 600 13px var(--ui);
|
||
}
|
||
#lyricsPane .lyr-flag svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
|
||
#lyricsPane .lyr-flag[aria-pressed="true"] { background: rgba(255, 180, 84, 0.16); border-style: solid; }
|
||
#lyricsList.flagging .lyr-line { outline: 1.5px dashed rgba(255, 180, 84, 0.45); outline-offset: -2px; cursor: crosshair; }
|
||
.lyr-line.flagged { position: relative; }
|
||
.lyr-line.flagged::after {
|
||
content: "⚑" attr(data-n);
|
||
margin-left: auto; flex: none;
|
||
font: 700 12px var(--ui);
|
||
color: #ffb454; padding: 3px 8px; border-radius: 999px;
|
||
border: 1px solid rgba(255, 180, 84, 0.5);
|
||
}
|
||
.lyr-line.flagged.mine::after { background: #ffb454; color: #1a1206; border-color: #ffb454; }
|
||
|
||
/* ---- Save to device + On other devices ---- */
|
||
.card-act {
|
||
background: var(--bg-3); border: 1px solid var(--line); color: var(--text-2);
|
||
width: 36px; height: 36px; border-radius: 11px; flex-shrink: 0; align-self: center;
|
||
font-size: 16px; line-height: 1; cursor: pointer; transition: all 0.16s var(--ease);
|
||
}
|
||
.card-act:hover { color: #fff; background: var(--accent); border-color: var(--accent); }
|
||
.p2p-card .p2p-on { color: #7ee0a8; font-weight: 700; }
|
||
.p2p-card .p2p-off { color: var(--text-dim); }
|
||
.export-box { display: grid; gap: 14px; min-width: min(420px, 78vw); }
|
||
.export-status { font-size: 14px; line-height: 1.45; color: var(--text-2); overflow-wrap: anywhere; }
|
||
.export-bar { height: 8px; border-radius: 99px; background: var(--bg-3); overflow: hidden; }
|
||
.export-bar i { display: block; height: 100%; width: 0; border-radius: inherit; background: linear-gradient(90deg, var(--accent-deep), var(--accent-bright)); transition: width 0.25s linear; }
|
||
.export-bar.busy i { width: 40%; animation: export-slide 1.2s ease-in-out infinite; }
|
||
@keyframes export-slide { 0% { margin-left: -40%; } 100% { margin-left: 100%; } }
|
||
.export-actions { display: grid; gap: 8px; }
|
||
.export-actions .btn { height: 48px; width: 100%; }
|
||
|
||
/* Four everyday actions: Queue · Save · Gallery · Playlist, equal tiles */
|
||
#nowPlayingMeta .np-actions #queueBtn,
|
||
#nowPlayingMeta .np-actions #saveBtn,
|
||
#nowPlayingMeta .np-actions #exportBtn,
|
||
#nowPlayingMeta .np-actions #addPlaylistBtn {
|
||
order: -1;
|
||
flex: 1 1 calc(25% - 8px);
|
||
min-width: 0;
|
||
height: 52px;
|
||
padding: 0 4px;
|
||
justify-content: center;
|
||
border-radius: 16px;
|
||
color: var(--text);
|
||
background: var(--bg-3);
|
||
font-weight: 700;
|
||
font-size: 12.5px;
|
||
white-space: nowrap;
|
||
}
|
||
@media (max-width: 380px) {
|
||
#nowPlayingMeta .np-actions #queueBtn,
|
||
#nowPlayingMeta .np-actions #saveBtn,
|
||
#nowPlayingMeta .np-actions #exportBtn,
|
||
#nowPlayingMeta .np-actions #addPlaylistBtn { flex-basis: calc(50% - 8px); }
|
||
}
|
||
|
||
/* Icon-only refresh beside the primary action */
|
||
#listActions button.la-primary.la-inline { flex: 1 1 0; min-width: 0; }
|
||
#listActions button.la-icon {
|
||
flex: 0 0 10%; width: 10%; min-width: 0; height: 54px; padding: 0;
|
||
border-radius: 18px; font-size: 22px; justify-content: center;
|
||
border: 1px solid var(--line); background: var(--bg-3); color: var(--text);
|
||
}
|
||
@media (min-width: 900px) { #listActions button.la-icon { height: 44px; flex-basis: 44px; width: 44px; border-radius: 14px; } }
|
||
|
||
/* ---- More actions ---- */
|
||
#nowPlayingMeta .np-actions .np-more-host { display: none; }
|
||
#nowPlayingMeta .np-actions .np-more {
|
||
order: 5; flex: 1 1 100%; min-height: 54px; padding: 8px 16px;
|
||
display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px;
|
||
border-radius: 16px; border: 1px solid var(--line); background: transparent; color: var(--text); cursor: pointer; text-align: left;
|
||
}
|
||
.np-more span { font: 700 14px var(--ui); }
|
||
.np-more small { font: 400 12px var(--ui); color: var(--text-dim); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.np-more:hover { border-color: var(--accent); }
|
||
.more-list { display: grid; gap: 8px; min-width: min(420px, 80vw); }
|
||
.more-row {
|
||
display: flex; align-items: center; gap: 14px; width: 100%; padding: 12px 14px; text-align: left;
|
||
border-radius: 14px; border: 1px solid var(--line); background: var(--bg-3); color: var(--text); cursor: pointer;
|
||
}
|
||
.more-row:hover { border-color: var(--accent); }
|
||
.more-row[disabled] { opacity: 0.5; pointer-events: none; }
|
||
.more-ico { flex: none; width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; background: var(--bg-1); font-size: 19px; }
|
||
.more-txt { flex: 1; min-width: 0; display: grid; gap: 2px; }
|
||
.more-txt b { font: 700 14px var(--ui); }
|
||
.more-txt small { font: 400 12px/1.3 var(--ui); color: var(--text-dim); }
|
||
.more-go { color: var(--text-dim); font-size: 22px; }
|
||
.more-row.danger b { color: #ff8a80; }
|
||
.more-row.danger .more-ico { background: rgba(255, 75, 50, 0.16); }
|
||
|
||
/* ---- Deck: quick row + More controls ---- */
|
||
#controls #dkMoreHost { display: none; }
|
||
#controls .dk-quick { display: flex; gap: 8px; align-items: stretch; }
|
||
#controls .dk-quick .ctrl { flex: 0 0 56px; width: 56px; height: 56px; border-radius: 16px; font-size: 20px; }
|
||
#controls .dk-more {
|
||
flex: 1; min-width: 0; padding: 6px 14px; text-align: left; cursor: pointer;
|
||
display: flex; flex-direction: column; justify-content: center; gap: 2px;
|
||
border-radius: 16px; border: 1px solid var(--line); background: transparent; color: var(--text);
|
||
}
|
||
#controls .dk-more span { font: 700 14px var(--ui); }
|
||
#controls .dk-more small { font: 400 11.5px var(--ui); color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
#controls .dk-more:hover { border-color: var(--accent); }
|
||
.more-row.on .more-go { color: var(--accent-bright); }
|
||
.more-row.on { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
|
||
.more-sel { margin-left: auto; min-width: 96px; height: 38px; padding: 0 8px; border-radius: 10px; border: 1px solid var(--line); background: var(--bg-1); color: var(--text); font: 700 14px var(--mono); }
|
||
|
||
/* SVG transport icons: drawn on one grid so they centre exactly */
|
||
#controls .ctrl svg { width: 22px; height: 22px; display: block; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
||
#controls .ctrl svg.fill { fill: currentColor; stroke: none; }
|
||
#controls .deck-main .ctrl svg { width: 24px; height: 24px; }
|
||
#controls .deck-main .ctrl.play svg { width: 34px; height: 34px; }
|
||
#controls .deck-main .ctrl { display: grid; place-items: center; }
|
||
#controls .ctrl.active svg { filter: drop-shadow(0 0 6px var(--accent-glow)); }
|
||
|
||
/* One playback-mode button + mute in the transport row */
|
||
#controls .deck-main { grid-template-columns: 1fr 1fr 1.5fr 1fr 1fr; }
|
||
#controls #dkModeHost { display: none; }
|
||
#controls #modeBtn { position: relative; }
|
||
#controls #modeBtn:not(.active) { color: var(--text-dim); }
|
||
#controls #modeBtn[data-badge]:not([data-badge=""])::after {
|
||
content: attr(data-badge); position: absolute; right: 4px; top: 4px;
|
||
font: 800 12px/1 var(--ui); color: var(--accent-bright);
|
||
}
|
||
#controls .deck-main #muteBtn { font-size: 20px; }
|
||
#controls .dk-quick .ctrl { display: none; }
|
||
#controls .dk-quick #fsBtn { display: grid; }
|
||
#controls .deck-main #modeBtn { order: 1; }
|
||
#controls .deck-main #muteBtn { order: 5; }
|
||
|
||
/* Fullscreen: labelled in the quick row, icon-only once A-B markers appear */
|
||
#controls .dk-quick .ctrl { display: none; }
|
||
#controls .dk-quick #fsBtn { display: flex; flex: 0 0 auto; width: auto; padding: 0 16px; gap: 8px; align-items: center; justify-content: center; }
|
||
#controls .dk-quick #fsBtn svg { width: 22px; height: 22px; }
|
||
#controls .dk-quick .fs-label { font: 700 13px var(--ui); }
|
||
#controls .dk-quick.ab-on #fsBtn { width: 56px; padding: 0; }
|
||
#controls .dk-quick.ab-on .fs-label { display: none; }
|
||
#controls .dk-quick.ab-on #abABtn,
|
||
#controls .dk-quick.ab-on #abBBtn { display: grid; flex: 0 0 56px; width: 56px; font: 800 18px var(--ui); }
|
||
#controls .dk-quick.ab-on #abClearBtn:not(.hidden) { display: grid; flex: 0 0 56px; width: 56px; }
|
||
#controls .dk-quick.ab-on .dk-more small { display: none; }
|
||
#controls .fs-mini {
|
||
flex: none; width: 30px; height: 30px; padding: 0; display: grid; place-items: center;
|
||
border-radius: 9px; border: 0; background: transparent; color: var(--text-dim); cursor: pointer;
|
||
}
|
||
#controls .fs-mini:hover { color: var(--accent-bright); background: var(--bg-3); }
|
||
#controls .fs-mini svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
||
@media (max-width: 380px) { #controls .dk-quick.ab-on .dk-more span { font-size: 12px; } }
|
||
#controls .dk-quick .fs-label { text-transform: none; letter-spacing: 0; }
|
||
#controls .dk-more i { font-style: normal; }
|
||
#controls .dk-quick.ab-on .mc-rest { display: none; }
|
||
#controls .dk-quick.ab-on .dk-more { padding: 6px 10px; align-items: center; text-align: center; }
|
||
#controls .dk-quick.ab-on .dk-more span { white-space: nowrap; }
|
||
#controls .dk-quick.ab-on #abABtn, #controls .dk-quick.ab-on #abBBtn,
|
||
#controls .dk-quick.ab-on #abClearBtn:not(.hidden), #controls .dk-quick.ab-on #fsBtn { flex-basis: 52px; width: 52px; height: 52px; }
|
||
#controls .dk-more em { font-style: normal; }
|
||
#controls .dk-quick.ab-on .mc-label { display: none; }
|
||
#controls .dk-quick.ab-on .dk-more span { font-size: 22px; line-height: 1; }
|
||
#controls .dk-quick.ab-on .dk-more { flex: 1 1 52px; min-width: 52px; }
|
||
|
||
/* Transport = prev · play · next; volume row = slider · speaker · playback mode */
|
||
#controls .deck-main { grid-template-columns: repeat(3, auto); justify-content: center; gap: 28px; }
|
||
#controls .deck-vol { gap: 6px; }
|
||
#controls .deck-vol input[type="range"] { order: 0; }
|
||
#controls .deck-vol .ctrl { order: 1; width: 42px; height: 42px; flex: none; border-radius: 12px; border-color: transparent; background: transparent; }
|
||
#controls .deck-vol .ctrl:hover { background: var(--bg-3); }
|
||
#controls .deck-vol .ctrl svg { width: 22px; height: 22px; }
|
||
#controls .deck-vol #muteBtn svg { fill: currentColor; stroke: currentColor; stroke-width: 1.8; }
|
||
#controls .deck-vol #muteBtn svg path:not(.spk) { fill: none; }
|
||
#controls .deck-vol #muteBtn.muted { color: var(--accent-bright); }
|
||
|
||
#nowPlayingMeta .np-actions #addBtn,
|
||
#nowPlayingMeta .np-actions #serviceBtn {
|
||
order: -1; flex: 1 1 calc(25% - 8px); min-width: 0; height: 52px; padding: 0 4px; justify-content: center;
|
||
border-radius: 16px; color: var(--text); background: var(--bg-3); font-weight: 700; font-size: 12.5px; white-space: nowrap;
|
||
}
|
||
@media (max-width: 380px) { #nowPlayingMeta .np-actions #addBtn, #nowPlayingMeta .np-actions #serviceBtn { flex-basis: calc(50% - 8px); } }
|
||
.player-stage { flex-shrink: 0; }
|
||
|
||
/* Saved searches */
|
||
.ss-list { max-height: 280px; overflow-y: auto; margin-top: 8px; border: 1px solid var(--line); border-radius: 14px; }
|
||
.ss-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--line-soft, var(--line)); cursor: pointer; }
|
||
.ss-row:last-child { border-bottom: 0; }
|
||
.ss-row input { width: 18px; height: 18px; accent-color: var(--accent); flex: none; }
|
||
.ss-q { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||
.ss-row small { color: var(--text-dim); flex: none; font-size: 11px; }
|
||
.search-recent-clear small { opacity: 0.6; }
|
||
.topbar { position: relative; z-index: 80; } /* keeps the recent-searches dropdown above the page content */
|
||
|
||
/* Search results: age line + "Update search" */
|
||
.search-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 0 0 10px; padding: 8px 12px; border: 1px solid var(--line); border-radius: 12px; font-size: 12px; color: var(--text-dim); }
|
||
.search-meta.hidden { display: none; }
|
||
.search-meta .sm-btn { flex: none; border: 1px solid var(--line); background: transparent; color: var(--text); border-radius: 999px; padding: 6px 12px; font: inherit; font-weight: 600; cursor: pointer; }
|
||
.search-meta .sm-btn:disabled { opacity: .55; cursor: default; }
|
||
|
||
/* ---- Playlist header: wrapping title (≤90%) + icon actions; icon row beside the filter ---- */
|
||
.list-title-row { display: flex; align-items: flex-start; gap: 6px; min-width: 0; }
|
||
.list-title-row h2 { flex: 0 1 auto; max-width: 90%; min-width: 0; overflow-wrap: anywhere; }
|
||
.list-title-row h2.title-clickable { cursor: pointer; }
|
||
.list-title-row h2.title-clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
|
||
.list-title-actions { flex: 0 0 auto; display: flex; flex-direction: column; gap: 4px; margin-left: auto; }
|
||
.list-title-actions:empty { display: none; }
|
||
.list-filter-bar { display: flex; align-items: center; gap: 6px; }
|
||
.list-filter-bar input { flex: 1 1 auto; min-width: 0; width: auto; }
|
||
.list-filter-actions { flex: 0 0 auto; display: flex; gap: 6px; }
|
||
.list-filter-actions:empty { display: none; }
|
||
.list-icon-btn {
|
||
flex: none; width: 40px; height: 40px; padding: 0;
|
||
display: grid; place-items: center;
|
||
border-radius: 12px; border: 1px solid var(--line);
|
||
background: var(--bg-2); color: var(--text-2); cursor: pointer;
|
||
transition: color 0.16s, border-color 0.16s, background 0.16s;
|
||
}
|
||
.list-title-actions .list-icon-btn { width: 34px; height: 34px; border-radius: 10px; }
|
||
.list-icon-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
||
.list-icon-btn:hover { color: var(--text); border-color: var(--accent); }
|
||
.list-icon-btn.pinned { color: var(--accent-bright); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
|
||
.list-icon-btn.done { color: #3ecf8e; border-color: color-mix(in srgb, #3ecf8e 55%, transparent); opacity: 1; }
|
||
.list-icon-btn.busy { width: auto; min-width: 40px; padding: 0 8px; }
|
||
.list-icon-btn .lib-progress { font: 700 11px var(--mono); color: var(--accent-bright); }
|
||
.list-icon-btn.danger:hover { color: #ff5a4f; border-color: #ff5a4f; }
|
||
.list-icon-btn:disabled, .list-icon-btn.disabled { cursor: default; pointer-events: none; }
|
||
.list-icon-btn.disabled:not(.done):not(.busy) { opacity: 0.45; }
|
||
|
||
/* ---- Transport: one row — prev · −10 · play · +10 · next ---- */
|
||
#controls .deck-main { grid-template-columns: repeat(5, auto); gap: 14px; }
|
||
#controls .deck-main #prevBtn { order: 1; }
|
||
#controls .deck-main #back10Btn { order: 2; }
|
||
#controls .deck-main #playBtn { order: 3; }
|
||
#controls .deck-main #fwd10Btn { order: 4; }
|
||
#controls .deck-main #nextBtn { order: 5; }
|
||
@media (max-width: 400px) { #controls .deck-main { gap: 6px; } }
|
||
|
||
/* Rename modal: wrapping box so a long playlist name shows in full */
|
||
.modal textarea.rename-input {
|
||
display: block; width: 100%; resize: none; overflow: hidden;
|
||
background: var(--bg-3); border: 1px solid var(--line); border-radius: 13px;
|
||
padding: 13px 15px; color: var(--text); font: 600 16px/1.35 var(--ui);
|
||
outline: none; overflow-wrap: anywhere; transition: border-color 0.16s, box-shadow 0.16s;
|
||
}
|
||
.modal textarea.rename-input:focus { border-color: var(--accent); box-shadow: 0 0 0 4px rgba(255,75,50,0.12); }
|
||
.export-bar[hidden] { display: none; }
|