Waiting for the shuffle bag to land on the animation you are working on makes testing one of them tedious. The queue page now carries an Animation row next to Background: Auto keeps the per-track cycle, any other button pins the player to that animation until the mode changes again. The animation names live in config.js alongside their labels, so the server can validate them and the queue page can label its buttons; motion.js keys its registry by the same names. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg15tLAuT6NrCE1ZxKVgDB
274 lines
4.3 KiB
CSS
274 lines
4.3 KiB
CSS
:root {
|
|
--accent: #ff4fc3;
|
|
--ink: #14060f;
|
|
--panel: #1f0c1a;
|
|
--panel-2: #2a1124;
|
|
--text: #f7e9f3;
|
|
--muted: #a8859c;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0 auto;
|
|
padding: 24px 20px 60px;
|
|
max-width: 720px;
|
|
background: var(--ink);
|
|
color: var(--text);
|
|
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
|
|
header {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
h1 {
|
|
margin: 0;
|
|
font-size: 1.8rem;
|
|
letter-spacing: -0.02em;
|
|
color: var(--accent);
|
|
}
|
|
|
|
#status {
|
|
font-size: 0.7rem;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
color: var(--muted);
|
|
}
|
|
|
|
#status.offline {
|
|
color: #ff8a5c;
|
|
}
|
|
|
|
#status.online::before {
|
|
content: "";
|
|
display: inline-block;
|
|
width: 7px;
|
|
height: 7px;
|
|
margin-right: 6px;
|
|
border-radius: 50%;
|
|
background: #55e08a;
|
|
}
|
|
|
|
/* --- add form ----------------------------------------------------------- */
|
|
|
|
#add-form {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
#url {
|
|
flex: 1;
|
|
min-width: 0;
|
|
font: inherit;
|
|
padding: 12px 14px;
|
|
border-radius: 10px;
|
|
border: 1px solid #43213a;
|
|
background: var(--panel);
|
|
color: var(--text);
|
|
}
|
|
|
|
#url:focus {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 1px;
|
|
}
|
|
|
|
#add-form button {
|
|
font: inherit;
|
|
font-weight: 700;
|
|
padding: 12px 24px;
|
|
border: 0;
|
|
border-radius: 10px;
|
|
background: var(--accent);
|
|
color: var(--ink);
|
|
cursor: pointer;
|
|
}
|
|
|
|
#error {
|
|
margin: 10px 2px 0;
|
|
color: #ff8a5c;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* --- totals ------------------------------------------------------------- */
|
|
|
|
#totals {
|
|
display: flex;
|
|
gap: 10px;
|
|
margin: 22px 0 12px;
|
|
}
|
|
|
|
.total {
|
|
flex: 1;
|
|
padding: 12px 14px;
|
|
border-radius: 10px;
|
|
background: var(--panel);
|
|
border: 1px solid #37172f;
|
|
}
|
|
|
|
.label {
|
|
display: block;
|
|
font-size: 0.68rem;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--muted);
|
|
}
|
|
|
|
.value {
|
|
display: block;
|
|
margin-top: 4px;
|
|
font-size: 1.5rem;
|
|
font-variant-numeric: tabular-nums;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* --- list --------------------------------------------------------------- */
|
|
|
|
#list {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 10px 12px;
|
|
border-radius: 10px;
|
|
background: var(--panel);
|
|
border: 1px solid transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.item.current {
|
|
background: var(--panel-2);
|
|
border-color: var(--accent);
|
|
box-shadow: 0 0 0 1px rgba(255, 79, 195, 0.35);
|
|
}
|
|
|
|
.item.dragging {
|
|
opacity: 0.35;
|
|
}
|
|
|
|
.item.drop-before {
|
|
border-top-color: var(--accent);
|
|
box-shadow: 0 -2px 0 var(--accent);
|
|
}
|
|
|
|
.item.drop-after {
|
|
border-bottom-color: var(--accent);
|
|
box-shadow: 0 2px 0 var(--accent);
|
|
}
|
|
|
|
.handle {
|
|
flex: none;
|
|
cursor: grab;
|
|
color: var(--muted);
|
|
padding: 0 2px;
|
|
font-size: 1.1rem;
|
|
line-height: 1;
|
|
user-select: none;
|
|
}
|
|
|
|
.index {
|
|
flex: none;
|
|
width: 1.6em;
|
|
text-align: right;
|
|
color: var(--muted);
|
|
font-variant-numeric: tabular-nums;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.item.current .index {
|
|
color: var(--accent);
|
|
}
|
|
|
|
.title {
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.duration {
|
|
flex: none;
|
|
color: var(--muted);
|
|
font-variant-numeric: tabular-nums;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.remove {
|
|
flex: none;
|
|
border: 0;
|
|
background: transparent;
|
|
color: var(--muted);
|
|
font: inherit;
|
|
font-size: 1.2rem;
|
|
line-height: 1;
|
|
padding: 2px 6px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.remove:hover {
|
|
background: #46203c;
|
|
color: #ff8a5c;
|
|
}
|
|
|
|
#empty {
|
|
color: var(--muted);
|
|
text-align: center;
|
|
padding: 30px 0;
|
|
}
|
|
|
|
/* --- footer ------------------------------------------------------------- */
|
|
|
|
footer {
|
|
margin-top: 32px;
|
|
padding-top: 18px;
|
|
border-top: 1px solid #331630;
|
|
}
|
|
|
|
footer .switcher + .switcher {
|
|
margin-top: 18px;
|
|
}
|
|
|
|
#backgrounds,
|
|
#animations {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
#backgrounds button,
|
|
#animations button {
|
|
font: inherit;
|
|
padding: 8px 18px;
|
|
border-radius: 999px;
|
|
border: 1px solid #43213a;
|
|
background: var(--panel);
|
|
color: var(--text);
|
|
cursor: pointer;
|
|
}
|
|
|
|
#backgrounds button.active,
|
|
#animations button.active {
|
|
background: var(--accent);
|
|
border-color: var(--accent);
|
|
color: var(--ink);
|
|
font-weight: 600;
|
|
}
|