@@ -446,11 +476,9 @@ function mixerScreen() {
${fmt(state.progress * dur)}${fmt(dur)}
-
-
-
-
-
+
+
+
${preparing ? '
Preparing audio…
' : ""}
@@ -824,6 +852,12 @@ app.addEventListener("click", (e) => {
case "mixview":
state.mixerView = t.dataset.view;
break;
+ case "prev":
+ prevTrack();
+ return;
+ case "next":
+ nextTrack();
+ return;
case "play":
case "play-mini":
e.stopPropagation();
@@ -890,7 +924,6 @@ async function loadLibrary() {
const jobs = await fetchJobs();
state.tracks = jobs.map(jobToCard).sort((a, b) => b.createdAt - a.createdAt);
state.libState = state.tracks.length ? "ready" : "empty";
- if (!state.current && state.tracks.length) state.current = state.tracks[0];
} catch (e) {
console.warn("[mobile] failed to load library:", e);
state.libState = "error";
diff --git a/static/mobile/styles.css b/static/mobile/styles.css
index e9457dc1..4e416954 100644
--- a/static/mobile/styles.css
+++ b/static/mobile/styles.css
@@ -248,25 +248,22 @@ button {
gap: 22px;
margin-top: 8px;
}
-.t-ghost {
- background: none;
- border: none;
- color: var(--muted);
- cursor: pointer;
- display: flex;
- align-items: center;
- gap: 4px;
- font-family: var(--mono);
- font-size: 12px;
- font-weight: 600;
-}
.t-step {
+ width: 48px;
+ height: 48px;
background: none;
border: none;
- color: #d8d8dc;
+ border-radius: 50%;
+ color: #c8c8cc;
cursor: pointer;
display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: color 0.12s, transform 0.1s, opacity 0.12s;
}
+.t-step:hover { color: #fff; }
+.t-step:active { transform: scale(0.88); opacity: 0.7; }
+.t-step:disabled { opacity: 0.22; cursor: default; }
.t-play {
width: 66px;
height: 66px;
@@ -278,6 +275,11 @@ button {
align-items: center;
justify-content: center;
cursor: pointer;
+ transition: background 0.15s, box-shadow 0.15s;
+}
+.t-play[data-playing="true"] {
+ background: linear-gradient(135deg, #3fcf6e 0%, #1fa84e 100%);
+ box-shadow: 0 12px 30px -6px rgba(63, 207, 110, 0.65);
}
.mx-prep {