diff --git a/web/src/App.vue b/web/src/App.vue
index 5bbed9b..d7dbbf0 100644
--- a/web/src/App.vue
+++ b/web/src/App.vue
@@ -6,6 +6,7 @@
+
@@ -17,12 +18,38 @@
{{ currentSong.name }}
{{ currentSong.artist }}
-
-
+
+
+
+
+
+
+
+
+
+
+
+ {{ mobileVolume }}
+
@@ -57,6 +84,7 @@ import Navbar from './components/Navbar.vue';
import Player from './components/Player.vue';
import CoverArt from './components/CoverArt.vue';
import Toast from './components/Toast.vue';
+import Queue from './components/Queue.vue';
const playerStore = usePlayerStore();
const theme = computed(() => playerStore.theme);
@@ -64,6 +92,18 @@ const route = useRoute();
const router = useRouter();
const { connect } = useWebSocket();
const currentSong = computed(() => playerStore.currentSong);
+const mobileVolume = computed(() => playerStore.activeBot?.volume ?? 75);
+const mobileMode = computed(() => playerStore.activeBot?.playMode ?? 'seq');
+const mobileModeOrder = ['seq', 'loop', 'random', 'rloop'];
+const mobileModeIcons: Record = {
+ seq: 'mdi:arrow-right',
+ loop: 'mdi:repeat',
+ random: 'mdi:shuffle',
+ rloop: 'mdi:repeat-once',
+};
+const mobileModeIcon = computed(() => mobileModeIcons[mobileMode.value] ?? mobileModeIcons.seq);
+const mobileVolumeOpen = ref(false);
+const mobileQueueOpen = ref(false);
const mobileProgressPct = ref(0);
let syncTimer: ReturnType | null = null;
@@ -77,6 +117,29 @@ function updateMobileProgress() {
mobileRaf = requestAnimationFrame(updateMobileProgress);
}
+function onMobileVolumeChange(e: Event) {
+ const volume = Number((e.target as HTMLInputElement).value);
+ playerStore.setVolume(volume);
+}
+
+function toggleMobileVolume() {
+ mobileVolumeOpen.value = !mobileVolumeOpen.value;
+ if (mobileVolumeOpen.value) mobileQueueOpen.value = false;
+}
+
+function toggleMobileQueue() {
+ mobileQueueOpen.value = !mobileQueueOpen.value;
+ if (mobileQueueOpen.value) mobileVolumeOpen.value = false;
+}
+
+function cycleMobileMode() {
+ const currentIndex = mobileModeOrder.indexOf(mobileMode.value);
+ const nextMode = mobileModeOrder[(currentIndex + 1) % mobileModeOrder.length] ?? mobileModeOrder[0];
+ mobileVolumeOpen.value = false;
+ mobileQueueOpen.value = false;
+ playerStore.setMode(nextMode);
+}
+
onMounted(() => {
playerStore.loadTheme();
connect();
@@ -132,6 +195,14 @@ onUnmounted(() => {
}
}
+.mobile-queue {
+ display: none;
+
+ @media (max-width: 768px) {
+ display: flex;
+ }
+}
+
.m-player-progress {
position: absolute;
top: 0;
@@ -151,6 +222,13 @@ onUnmounted(() => {
min-width: 0;
}
+.m-player-controls {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ flex: 0 0 auto;
+}
+
.m-player-name {
font-size: 13px;
font-weight: 500;
@@ -168,16 +246,64 @@ onUnmounted(() => {
}
.m-player-btn {
- width: 32px;
+ width: 28px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
- font-size: 22px;
+ font-size: 20px;
opacity: 0.85;
flex-shrink: 0;
}
+.m-volume-popover {
+ position: absolute;
+ right: 8px;
+ bottom: calc(100% + 8px);
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ width: min(260px, calc(100vw - 32px));
+ padding: 10px 12px;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius-md);
+ box-shadow: var(--shadow-dropdown);
+ cursor: default;
+}
+
+.m-volume-icon {
+ flex: 0 0 auto;
+ font-size: 18px;
+ color: var(--text-secondary);
+}
+
+.m-volume-slider {
+ flex: 1 1 auto;
+ min-width: 0;
+ height: 4px;
+ appearance: none;
+ background: var(--border-color);
+ border-radius: 2px;
+ outline: none;
+
+ &::-webkit-slider-thumb {
+ appearance: none;
+ width: 16px;
+ height: 16px;
+ background: var(--color-primary);
+ border-radius: 50%;
+ }
+}
+
+.m-volume-value {
+ flex: 0 0 30px;
+ font-size: 12px;
+ color: var(--text-secondary);
+ text-align: right;
+ font-variant-numeric: tabular-nums;
+}
+
// Mobile bottom tab bar
.m-tabbar {
position: fixed;
diff --git a/web/src/main.ts b/web/src/main.ts
index c2812ed..e20f04b 100644
--- a/web/src/main.ts
+++ b/web/src/main.ts
@@ -3,6 +3,7 @@ import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router/index.js';
import './styles/global.scss';
+import './styles/mobile.scss';
const app = createApp(App);
app.use(createPinia());
diff --git a/web/src/stores/player.ts b/web/src/stores/player.ts
index 4c1c970..9bc817d 100644
--- a/web/src/stores/player.ts
+++ b/web/src/stores/player.ts
@@ -376,11 +376,15 @@ export const usePlayerStore = defineStore('player', {
async setVolume(volume: number) {
if (!this.activeBotId) return;
await axios.post(`/api/player/${this.activeBotId}/volume`, { volume });
+ const bot = this.bots.find((b) => b.id === this.activeBotId);
+ if (bot) bot.volume = volume;
},
async setMode(mode: string) {
if (!this.activeBotId) return;
await axios.post(`/api/player/${this.activeBotId}/mode`, { mode });
+ const bot = this.bots.find((b) => b.id === this.activeBotId);
+ if (bot) bot.playMode = mode;
},
async fetchHomeData() {
diff --git a/web/src/styles/mobile.scss b/web/src/styles/mobile.scss
new file mode 100644
index 0000000..a8729b9
--- /dev/null
+++ b/web/src/styles/mobile.scss
@@ -0,0 +1,1050 @@
+/* ===== 手机端适配补丁,不改原组件 ===== */
+
+@media (max-width: 768px) {
+ :root {
+ --navbar-height: 52px;
+ --mobile-tabbar-height: 60px;
+ --mobile-mini-player-height: 74px;
+ }
+
+ html,
+ body,
+ #app {
+ overflow-x: hidden !important;
+ }
+
+ * {
+ min-width: 0;
+ }
+
+ button,
+ input,
+ textarea,
+ select {
+ max-width: 100%;
+ }
+
+ button,
+ a,
+ .nav-link,
+ .m-tab,
+ .bot-ctrl-btn,
+ .link-dialog-btn,
+ .play-all-btn,
+ .expand-btn,
+ .source-tab,
+ .source-tab-label {
+ min-width: 0;
+ overflow-wrap: anywhere;
+ }
+
+ body {
+ -webkit-text-size-adjust: 100%;
+ }
+
+ input,
+ textarea,
+ select {
+ font-size: 16px !important;
+ }
+
+ /* 页面主体 */
+ .main-content {
+ padding: calc(var(--navbar-height) + 14px) 14px calc(var(--mobile-tabbar-height) + var(--mobile-mini-player-height) + env(safe-area-inset-bottom) + 18px) !important;
+ max-width: 100vw !important;
+ overflow-x: hidden !important;
+ }
+
+ /* 顶部导航 */
+ .navbar {
+ height: var(--navbar-height) !important;
+ min-height: var(--navbar-height) !important;
+ padding: 0 12px !important;
+ flex-wrap: nowrap !important;
+ align-items: center !important;
+ gap: 8px !important;
+ }
+
+ .logo {
+ font-size: 16px !important;
+ line-height: 36px !important;
+ margin-right: auto !important;
+ white-space: nowrap !important;
+ }
+
+ .nav-right {
+ margin-left: 0 !important;
+ gap: 8px !important;
+ }
+
+ .nav-links {
+ display: none !important;
+ }
+
+ .nav-links::-webkit-scrollbar {
+ display: none !important;
+ }
+
+ .nav-link {
+ flex: 0 0 auto !important;
+ min-width: max-content !important;
+ padding: 8px 12px !important;
+ font-size: 13px !important;
+ line-height: 1 !important;
+ writing-mode: horizontal-tb !important;
+ white-space: nowrap !important;
+ border-radius: 10px !important;
+ background: var(--bg-card) !important;
+ }
+
+ .bot-selector-btn {
+ max-width: min(180px, 54vw) !important;
+ min-height: 36px !important;
+ padding: 7px 10px !important;
+ font-size: 13px !important;
+ }
+
+ .bot-selector-name {
+ max-width: 96px !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .settings-btn {
+ width: 36px !important;
+ height: 36px !important;
+ display: grid !important;
+ place-items: center !important;
+ background: var(--bg-card) !important;
+ border-radius: 10px !important;
+ }
+
+ .bot-dropdown {
+ position: fixed !important;
+ top: calc(var(--navbar-height) + 4px) !important;
+ left: 12px !important;
+ right: 12px !important;
+ width: auto !important;
+ min-width: 0 !important;
+ max-width: none !important;
+ }
+
+ .bot-dropdown-row {
+ min-width: 0 !important;
+ }
+
+ .bot-dropdown-item {
+ min-width: 0 !important;
+ }
+
+ .link-dialog {
+ width: calc(100vw - 28px) !important;
+ min-width: 0 !important;
+ max-width: calc(100vw - 28px) !important;
+ padding: 16px !important;
+ }
+
+ .link-dialog-actions {
+ flex-wrap: wrap !important;
+ }
+
+ .link-dialog-btn {
+ flex: 1 1 120px !important;
+ }
+
+ .m-tabbar {
+ height: calc(var(--mobile-tabbar-height) + env(safe-area-inset-bottom)) !important;
+ padding-bottom: env(safe-area-inset-bottom) !important;
+ }
+
+ .m-tab {
+ flex: 1 1 0 !important;
+ max-width: 25% !important;
+ padding: 6px 4px !important;
+ text-align: center !important;
+ }
+
+ .m-tab .tab-label {
+ display: block !important;
+ width: 100% !important;
+ line-height: 1.15 !important;
+ white-space: nowrap !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ }
+
+ .m-player {
+ bottom: calc(var(--mobile-tabbar-height) + env(safe-area-inset-bottom) + 8px) !important;
+ left: 8px !important;
+ right: 8px !important;
+ width: auto !important;
+ min-width: 0 !important;
+ gap: 6px !important;
+ padding-left: 8px !important;
+ padding-right: 8px !important;
+ }
+
+ .m-player .cover-art {
+ flex: 0 0 40px !important;
+ }
+
+ .m-player-info {
+ min-width: 0 !important;
+ }
+
+ .m-player-controls {
+ display: flex !important;
+ align-items: center !important;
+ gap: 3px !important;
+ flex: 0 0 auto !important;
+ }
+
+ .m-player-name,
+ .m-player-artist {
+ display: block !important;
+ max-width: 100% !important;
+ line-height: 1.25 !important;
+ }
+
+ .m-player-btn {
+ width: 26px !important;
+ height: 32px !important;
+ flex: 0 0 26px !important;
+ padding: 0 !important;
+ font-size: 19px !important;
+ }
+
+ .m-volume-popover {
+ right: 0 !important;
+ width: min(260px, calc(100vw - 32px)) !important;
+ }
+
+ .section-title {
+ min-width: 0 !important;
+ max-width: 100% !important;
+ flex-wrap: wrap !important;
+ align-items: center !important;
+ gap: 8px 10px !important;
+ line-height: 1.25 !important;
+ }
+
+ .section-title > span:first-child,
+ .page-title {
+ min-width: 0 !important;
+ overflow-wrap: anywhere !important;
+ }
+
+ .source-tabs {
+ margin-left: 0 !important;
+ max-width: 100% !important;
+ flex-wrap: wrap !important;
+ }
+
+ .source-tab,
+ .source-tab-label {
+ flex: 0 1 auto !important;
+ white-space: nowrap !important;
+ line-height: 1.1 !important;
+ }
+
+ /* 歌单详情页 */
+ .playlist-page {
+ width: 100% !important;
+ max-width: 100vw !important;
+ overflow-x: hidden !important;
+ }
+
+ .playlist-hero {
+ display: flex !important;
+ flex-direction: column !important;
+ align-items: flex-start !important;
+ gap: 16px !important;
+ margin-bottom: 22px !important;
+ }
+
+ .playlist-hero .cover-art,
+ .playlist-hero img {
+ width: 150px !important;
+ height: 150px !important;
+ max-width: 42vw !important;
+ max-height: 42vw !important;
+ flex-shrink: 0 !important;
+ }
+
+ .playlist-meta {
+ width: 100% !important;
+ min-width: 0 !important;
+ }
+
+ .playlist-title {
+ font-size: 24px !important;
+ line-height: 1.25 !important;
+ margin-bottom: 8px !important;
+ word-break: break-word !important;
+ white-space: normal !important;
+ }
+
+ .playlist-desc,
+ .playlist-stats {
+ font-size: 12px !important;
+ }
+
+ .play-all-btn {
+ width: 100% !important;
+ justify-content: center !important;
+ padding: 12px 16px !important;
+ border-radius: 14px !important;
+ }
+
+ /* 歌曲列表 */
+ .song-list {
+ width: 100% !important;
+ max-width: 100% !important;
+ overflow-x: hidden !important;
+ }
+
+ .song-item {
+ grid-template-columns: 28px 44px minmax(0, 1fr) auto !important;
+ gap: 8px !important;
+ padding: 8px 10px !important;
+ }
+
+ .song-cover {
+ width: 44px !important;
+ height: 44px !important;
+ }
+
+ .song-info,
+ .song-text,
+ .song-name,
+ .song-artist {
+ min-width: 0 !important;
+ }
+
+ .song-name,
+ .song-artist {
+ overflow: hidden !important;
+ white-space: nowrap !important;
+ text-overflow: ellipsis !important;
+ }
+
+ .song-name {
+ font-size: 12px !important;
+ }
+
+ .song-artist {
+ font-size: 11px !important;
+ }
+
+ .song-card {
+ display: flex !important;
+ align-items: center !important;
+ gap: 8px !important;
+ width: 100% !important;
+ padding: 8px 6px !important;
+ }
+
+ .song-card .cover-art {
+ width: 42px !important;
+ height: 42px !important;
+ }
+
+ .song-card .song-index {
+ width: 22px !important;
+ flex: 0 0 22px !important;
+ font-size: 12px !important;
+ }
+
+ .song-card .song-info {
+ flex: 1 1 auto !important;
+ min-width: 0 !important;
+ }
+
+ .song-card .song-name-row {
+ min-width: 0 !important;
+ max-width: 100% !important;
+ }
+
+ .song-card .song-name,
+ .song-card .song-artist {
+ min-width: 0 !important;
+ max-width: 100% !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .song-card .platform-badge {
+ max-width: 58px !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .song-card .song-album {
+ display: none !important;
+ }
+
+ .song-card .song-duration {
+ width: auto !important;
+ flex: 0 0 auto !important;
+ font-size: 11px !important;
+ }
+
+ .song-card .song-actions {
+ flex: 0 0 auto !important;
+ opacity: 1 !important;
+ gap: 2px !important;
+ max-width: 96px !important;
+ }
+
+ .song-card .action-btn {
+ width: 30px !important;
+ height: 30px !important;
+ display: grid !important;
+ place-items: center !important;
+ padding: 0 !important;
+ font-size: 18px !important;
+ background: var(--bg-card) !important;
+ }
+
+ .song-duration {
+ font-size: 11px !important;
+ }
+
+ /* 底部播放器 */
+ .player-bar {
+ height: auto !important;
+ min-height: var(--player-height) !important;
+ display: grid !important;
+ grid-template-columns: minmax(0, 1fr) auto !important;
+ grid-template-areas:
+ "left right"
+ "center center" !important;
+ row-gap: 8px !important;
+ column-gap: 10px !important;
+ padding: 10px 12px calc(10px + env(safe-area-inset-bottom)) !important;
+ align-items: center !important;
+ }
+
+ .player-left {
+ grid-area: left !important;
+ width: auto !important;
+ min-width: 0 !important;
+ gap: 10px !important;
+ }
+
+ .player-left .cover-art {
+ width: 40px !important;
+ height: 40px !important;
+ }
+
+ .player-center {
+ grid-area: center !important;
+ width: 100% !important;
+ justify-content: center !important;
+ gap: 14px !important;
+ }
+
+ .player-right {
+ grid-area: right !important;
+ width: auto !important;
+ gap: 6px !important;
+ }
+
+ .player-bar .song-name {
+ max-width: 52vw !important;
+ }
+
+ .player-bar .song-artist {
+ max-width: 52vw !important;
+ }
+
+ .control-btn {
+ width: 34px !important;
+ height: 34px !important;
+ font-size: 21px !important;
+ }
+
+ .play-btn {
+ width: 38px !important;
+ height: 38px !important;
+ font-size: 21px !important;
+ }
+
+ .volume-icon,
+ .volume-slider,
+ .time-display,
+ .mode-label {
+ display: none !important;
+ }
+
+ .lyrics-btn {
+ margin-left: 0 !important;
+ }
+
+ .queue-panel {
+ top: var(--navbar-height) !important;
+ right: -100vw !important;
+ bottom: calc(var(--mobile-tabbar-height) + env(safe-area-inset-bottom)) !important;
+ width: 100vw !important;
+ max-width: 100vw !important;
+ border-left: 0 !important;
+ }
+
+ .queue-panel.open {
+ right: 0 !important;
+ }
+
+ .queue-header,
+ .queue-item,
+ .queue-song-info,
+ .queue-song-name,
+ .queue-song-artist {
+ min-width: 0 !important;
+ }
+
+ .queue-title,
+ .queue-count,
+ .queue-song-name,
+ .queue-song-artist {
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ /* 首页网格 */
+ .daily-grid,
+ .playlist-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
+ gap: 16px 14px !important;
+ }
+
+ .daily-card,
+ .playlist-card {
+ min-width: 0 !important;
+ }
+
+ .daily-name,
+ .daily-artist,
+ .playlist-name,
+ .playlist-count {
+ min-width: 0 !important;
+ max-width: 100% !important;
+ overflow-wrap: anywhere !important;
+ }
+
+ .daily-card .cover-art,
+ .playlist-card .cover-art {
+ width: 100% !important;
+ height: auto !important;
+ aspect-ratio: 1 / 1 !important;
+ }
+
+ .daily-card .cover-img,
+ .daily-card .cover-placeholder,
+ .playlist-card .cover-img,
+ .playlist-card .cover-placeholder {
+ height: 100% !important;
+ }
+
+ .now-playing,
+ .fm-card {
+ gap: 12px !important;
+ padding: 14px !important;
+ }
+
+ .now-playing .cover-art {
+ width: 58px !important;
+ height: 58px !important;
+ }
+
+ .now-playing-name,
+ .now-playing-artist,
+ .fm-title,
+ .fm-desc {
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .fm-icon-wrapper {
+ width: 44px !important;
+ height: 44px !important;
+ }
+
+ .fm-play-icon {
+ flex: 0 0 auto !important;
+ font-size: 30px !important;
+ }
+
+ .section-title {
+ font-size: 19px !important;
+ }
+
+ /* 搜索/历史/空状态 */
+ .search-page,
+ .history-page {
+ width: 100% !important;
+ }
+
+ .search-input-wrap {
+ padding: 11px 12px !important;
+ }
+
+ .search-input {
+ width: 100% !important;
+ }
+
+ .loading,
+ .empty {
+ padding-left: 16px !important;
+ padding-right: 16px !important;
+ }
+
+ .page-title {
+ font-size: 24px !important;
+ margin-bottom: 20px !important;
+ line-height: 1.2 !important;
+ }
+
+ /* 设置页 */
+ .settings-section,
+ .account-card {
+ padding: 16px !important;
+ border-radius: 12px !important;
+ }
+
+ .setting-row,
+ .bot-item,
+ .account-header {
+ align-items: flex-start !important;
+ min-width: 0 !important;
+ }
+
+ .setting-label,
+ .account-info,
+ .profile-toggle-text,
+ .profile-section-hint,
+ .empty-state,
+ .empty,
+ .loading {
+ min-width: 0 !important;
+ overflow-wrap: anywhere !important;
+ }
+
+ .bot-item {
+ flex-direction: column !important;
+ gap: 12px !important;
+ }
+
+ .bot-info {
+ width: 100% !important;
+ justify-content: space-between !important;
+ }
+
+ .bot-actions {
+ width: 100% !important;
+ justify-content: flex-end !important;
+ flex-wrap: wrap !important;
+ }
+
+ .login-methods,
+ .quality-options {
+ grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
+ display: grid !important;
+ }
+
+ .login-btn,
+ .quality-btn {
+ width: 100% !important;
+ justify-content: center !important;
+ }
+
+ .form-row,
+ .prefix-input-wrap,
+ .modal-actions {
+ flex-direction: column !important;
+ align-items: stretch !important;
+ }
+
+ .form-row .form-group {
+ flex: none !important;
+ }
+
+ .input,
+ .textarea,
+ .input-sm {
+ width: 100% !important;
+ max-width: none !important;
+ }
+
+ .qr-image {
+ width: min(200px, 70vw) !important;
+ height: min(200px, 70vw) !important;
+ }
+
+ .qr-status {
+ flex-wrap: wrap !important;
+ justify-content: center !important;
+ text-align: center !important;
+ }
+
+ .edit-modal {
+ width: calc(100vw - 28px) !important;
+ max-width: calc(100vw - 28px) !important;
+ max-height: calc(100vh - 28px) !important;
+ padding: 18px !important;
+ }
+
+ /* 歌词页 */
+ .lyrics-page {
+ align-items: stretch !important;
+ justify-content: flex-start !important;
+ overflow: hidden !important;
+ }
+
+ .lyrics-page .back-btn {
+ top: calc(12px + env(safe-area-inset-top)) !important;
+ left: 14px !important;
+ }
+
+ .lyrics-content {
+ flex-direction: column !important;
+ gap: 20px !important;
+ width: 100% !important;
+ height: 100vh !important;
+ padding: calc(56px + env(safe-area-inset-top)) 18px calc(var(--player-height) + 18px) !important;
+ }
+
+ .lyrics-left {
+ flex-direction: row !important;
+ justify-content: flex-start !important;
+ gap: 14px !important;
+ }
+
+ .lyrics-left .cover-art {
+ width: 76px !important;
+ height: 76px !important;
+ }
+
+ .lyrics-left .song-meta {
+ min-width: 0 !important;
+ text-align: left !important;
+ }
+
+ .lyrics-left .song-name,
+ .lyrics-left .song-artist {
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .lyrics-right {
+ flex: 1 1 auto !important;
+ min-height: 0 !important;
+ }
+
+ .lyrics-line .lyrics-text {
+ font-size: 16px !important;
+ }
+
+ .lyrics-line.active .lyrics-text {
+ font-size: 20px !important;
+ }
+
+ .lyrics-line .lyrics-translation {
+ font-size: 13px !important;
+ }
+
+ .no-song {
+ width: 100% !important;
+ padding: 96px 18px 0 !important;
+ text-align: center !important;
+ }
+
+ /* 首次设置向导 */
+ .setup-wizard {
+ width: 100% !important;
+ padding-top: 12px !important;
+ }
+
+ .steps {
+ gap: 6px !important;
+ margin-bottom: 30px !important;
+ }
+
+ .step-label {
+ font-size: 11px !important;
+ }
+
+ .step-content h2 {
+ font-size: 24px !important;
+ }
+}
+
+@media (min-width: 769px) and (max-width: 1024px) {
+ :root {
+ --navbar-height: 58px;
+ --player-height: 72px;
+ }
+
+ html,
+ body,
+ #app {
+ overflow-x: hidden !important;
+ }
+
+ * {
+ min-width: 0;
+ }
+
+ .main-content {
+ padding: calc(var(--navbar-height) + 18px) 28px calc(var(--player-height) + 26px) !important;
+ max-width: 100vw !important;
+ overflow-x: hidden !important;
+ }
+
+ .navbar {
+ height: var(--navbar-height) !important;
+ min-height: var(--navbar-height) !important;
+ padding: 0 24px !important;
+ gap: 14px !important;
+ }
+
+ .logo {
+ flex: 0 0 auto !important;
+ margin-right: 4px !important;
+ font-size: 17px !important;
+ white-space: nowrap !important;
+ }
+
+ .nav-links {
+ flex: 1 1 auto !important;
+ gap: 10px !important;
+ overflow-x: auto !important;
+ white-space: nowrap !important;
+ scrollbar-width: none !important;
+ }
+
+ .nav-links::-webkit-scrollbar {
+ display: none !important;
+ }
+
+ .nav-link {
+ flex: 0 0 auto !important;
+ padding: 8px 10px !important;
+ font-size: 13px !important;
+ white-space: nowrap !important;
+ }
+
+ .nav-right {
+ flex: 0 1 auto !important;
+ gap: 8px !important;
+ }
+
+ .bot-selector-btn {
+ max-width: min(220px, 28vw) !important;
+ padding: 8px 12px !important;
+ }
+
+ .bot-selector-name {
+ max-width: min(130px, 16vw) !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .section-title {
+ flex-wrap: wrap !important;
+ gap: 8px 12px !important;
+ line-height: 1.25 !important;
+ }
+
+ .daily-grid,
+ .playlist-grid {
+ grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
+ gap: 18px !important;
+ }
+
+ .daily-card,
+ .playlist-card,
+ .song-card {
+ min-width: 0 !important;
+ }
+
+ .daily-name,
+ .daily-artist,
+ .playlist-name,
+ .playlist-count,
+ .song-name,
+ .song-artist {
+ min-width: 0 !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .song-card {
+ gap: 10px !important;
+ }
+
+ .song-card .song-album {
+ width: min(140px, 18vw) !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ .player-bar {
+ height: var(--player-height) !important;
+ padding: 0 20px !important;
+ gap: 14px !important;
+ overflow: hidden !important;
+ }
+
+ .player-left {
+ width: min(260px, 30vw) !important;
+ gap: 10px !important;
+ }
+
+ .player-center {
+ flex: 1 1 auto !important;
+ min-width: 0 !important;
+ gap: 12px !important;
+ }
+
+ .player-right {
+ width: min(210px, 24vw) !important;
+ gap: 6px !important;
+ }
+
+ .player-bar .song-name,
+ .player-bar .song-artist {
+ max-width: min(190px, 20vw) !important;
+ }
+
+ .time-display {
+ min-width: 34px !important;
+ font-size: 11px !important;
+ }
+
+ .volume-slider {
+ width: min(82px, 9vw) !important;
+ }
+
+ .mode-label {
+ display: none !important;
+ }
+
+ .control-btn {
+ width: 34px !important;
+ height: 34px !important;
+ font-size: 21px !important;
+ }
+
+ .play-btn {
+ width: 40px !important;
+ height: 40px !important;
+ font-size: 22px !important;
+ }
+
+ .queue-panel {
+ top: var(--navbar-height) !important;
+ bottom: var(--player-height) !important;
+ width: min(390px, 44vw) !important;
+ }
+
+ .settings-section,
+ .account-card {
+ padding: 20px !important;
+ }
+
+ .login-methods,
+ .quality-options {
+ grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
+ }
+
+ .playlist-hero {
+ gap: 24px !important;
+ }
+
+ .playlist-title,
+ .page-title {
+ line-height: 1.2 !important;
+ overflow-wrap: anywhere !important;
+ }
+}
+
+@media (max-width: 380px) {
+ :root {
+ --navbar-height: 52px;
+ }
+
+ .logo {
+ display: none !important;
+ }
+
+ .nav-right {
+ width: 100% !important;
+ justify-content: space-between !important;
+ }
+
+ .bot-selector {
+ flex: 1 !important;
+ min-width: 0 !important;
+ }
+
+ .bot-selector-btn {
+ width: 100% !important;
+ max-width: none !important;
+ }
+
+ .nav-link {
+ padding-left: 8px !important;
+ padding-right: 8px !important;
+ }
+
+ .playlist-title {
+ font-size: 22px !important;
+ }
+
+ .daily-grid,
+ .playlist-grid,
+ .login-methods,
+ .quality-options {
+ grid-template-columns: 1fr !important;
+ }
+
+ .song-card .song-duration {
+ display: none !important;
+ }
+
+ .m-player {
+ gap: 4px !important;
+ padding-left: 8px !important;
+ padding-right: 8px !important;
+ }
+
+ .m-player .cover-art {
+ flex-basis: 34px !important;
+ width: 34px !important;
+ height: 34px !important;
+ }
+
+ .m-player-controls {
+ gap: 2px !important;
+ }
+
+ .m-player-btn {
+ width: 24px !important;
+ flex-basis: 24px !important;
+ font-size: 18px !important;
+ }
+
+ .player-center {
+ justify-content: space-between !important;
+ gap: 8px !important;
+ }
+}