diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor
index 051827b..02067ad 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor
@@ -27,8 +27,11 @@ else
-
+
+
+
+
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs
index 6fa678e..d2f8366 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.cs
@@ -38,7 +38,7 @@ public partial class AudioPlayerBar : ComponentBase, IAsyncDisposable
/// Display time - shows seek position while dragging, otherwise current playback time.
///
private double DisplayTime => _isSeeking ? _seekPosition : (PlayerService?.CurrentTime ?? 0);
- private string PlayerModeClass => Fixed ? "player-fixed" : "player-docked";
+ private string PlayerModeClass => Fixed ? "player-fixed" : "player-dock";
protected override void OnParametersSet()
{
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css
index 49a9d6d..f9b9fcb 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/AudioPlayerBar.razor.css
@@ -71,29 +71,53 @@
}
}
-/* Unified responsive player layout.
- Wide and narrow shapes are pure CSS — no runtime breakpoint subscription.
- Children are targeted by their stable classes (transport-zone, volume-zone,
- seek-zone) rather than positional nth-child, since all three render a .mud-stack
- root and positional selectors would be fragile. */
+/* Unified responsive player layout — CSS Grid with named areas redefined per breakpoint.
+ The metadata (meta-zone) detaches from the waveform (seek-zone) in the mid band, which a
+ flex order-swap can't express, so each of the four zones is placed by grid-area and the three
+ shapes are pure template-area swaps — no runtime breakpoint subscription. min-width:0 on the
+ shrinkable centre zones lets the title truncate and the waveform shrink instead of overflowing. */
.player-layout {
- display: flex;
- flex-wrap: wrap;
+ display: grid;
align-items: center;
gap: 8px;
padding-right: 2.5rem; /* clear the abs-positioned PlayerWindowControls */
}
-/* Wide (>= 600px): single row, seek zone grows and sits between transport and volume */
-@media (min-width: 600px) {
- ::deep .transport-zone { order: 1; }
- ::deep .seek-zone { order: 2; flex-grow: 1; flex-basis: 0; }
- ::deep .volume-zone { order: 3; flex-shrink: 0; }
+::deep .transport-zone { grid-area: transport; }
+::deep .meta-zone { grid-area: meta; min-width: 0; }
+::deep .seek-zone { grid-area: waveform; min-width: 0; }
+::deep .volume-zone { grid-area: volume; }
+
+/* Wide (>= 900px): single row — transport and volume flank the centre column; the metadata
+ sits directly under the waveform (transport/volume span both rows, centred). */
+@media (min-width: 900px) {
+ .player-layout {
+ grid-template-columns: auto minmax(360px, 1fr) auto;
+ grid-template-areas:
+ "transport waveform volume"
+ "transport meta volume";
+ }
}
-/* Narrow (< 600px): transport + volume on top row, seek full-width below */
-@media (max-width: 599.98px) {
- ::deep .transport-zone { order: 1; }
- ::deep .volume-zone { order: 2; }
- ::deep .seek-zone { flex-basis: 100%; order: 3; }
+/* Mid (600–900px): metadata rides the top row between transport and volume; the waveform gets
+ the whole bottom row to itself rather than being squeezed beside the metadata. */
+@media (min-width: 600px) and (max-width: 899.98px) {
+ .player-layout {
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ grid-template-areas:
+ "transport meta volume"
+ "waveform waveform waveform";
+ }
+}
+
+/* Narrow (< 600px): transport + volume share the top row; waveform then metadata stack full-width
+ below — the most compressed shape. */
+@media (max-width: 599.98px) {
+ .player-layout {
+ grid-template-columns: auto 1fr auto;
+ grid-template-areas:
+ "transport . volume"
+ "waveform waveform waveform"
+ "meta meta meta";
+ }
}
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor
index 10a0688..0232f65 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor
@@ -5,5 +5,4 @@
OnSeekChange="OnSeekChange"
OnSeekEnd="OnSeekEnd"
Class="seek-waveform"/>
-
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs
index eccf29d..b290448 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/PlayerSeekZone.razor.cs
@@ -1,17 +1,16 @@
-using DeepDrftModels.DTOs;
using Microsoft.AspNetCore.Components;
namespace DeepDrftPublic.Client.Controls.AudioPlayerBar;
///
-/// Centre zone of the player: the over the now-playing metadata row
-/// (). The seeker owns the pointer-gesture seek logic and reads playback
-/// state off the cascaded player service directly; this zone just forwards the seek callbacks up to
-/// (whose wiring is unchanged) and renders the current track's metadata.
+/// Centre zone of the player: the . The seeker owns the pointer-gesture
+/// seek logic and reads playback state off the cascaded player service directly; this zone just
+/// forwards the seek callbacks up to (whose wiring is unchanged).
+/// The now-playing metadata () is a sibling zone in the grid, not nested
+/// here, so the responsive layouts can place it independently of the waveform.
///
public partial class PlayerSeekZone : ComponentBase
{
- [Parameter] public TrackDto? CurrentTrack { get; set; }
[Parameter] public EventCallback OnSeekStart { get; set; }
[Parameter] public EventCallback OnSeekEnd { get; set; }
[Parameter] public EventCallback OnSeekChange { get; set; }
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor
index 5748711..a4909d9 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor
@@ -7,7 +7,7 @@
@Track.TrackName
- -
+ -
@Track.Artist
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css
index caaa3bc..0bb89d1 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/TrackMetaLabel.razor.css
@@ -40,3 +40,56 @@
::deep .track-meta-year {
opacity: 0.75;
}
+
+/* The metadata's three shapes track the dock's layout bands (same breakpoints as the grid in
+ AudioPlayerBar.razor.css), not the label's own slot width — in the <600 band the slot is actually
+ full-width yet we still want it fully vertical, which a container query can't express.
+
+ Mid band (600–900): 2×2 — title over artist on the left (start-justified), genre over year on the
+ right (end-justified). The row stays a row; only the two inner groups go vertical. */
+@media (min-width: 600px) and (max-width: 899.98px) {
+ .track-meta-row {
+ align-items: flex-start;
+ }
+
+ .track-meta-identity {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0;
+ }
+
+ .track-meta-accents {
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 2px;
+ }
+
+ ::deep .track-meta-sep {
+ display: none;
+ }
+}
+
+/* Narrow band (<600): fully vertical — title / artist / genre / year all stacked, left-aligned. */
+@media (max-width: 599.98px) {
+ .track-meta-row {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 4px;
+ }
+
+ .track-meta-identity {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0;
+ }
+
+ .track-meta-accents {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 2px;
+ }
+
+ ::deep .track-meta-sep {
+ display: none;
+ }
+}
diff --git a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor
index a1e6a22..e3e1d71 100644
--- a/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor
+++ b/DeepDrftPublic.Client/Controls/AudioPlayerBar/VolumeZone.razor
@@ -1,7 +1,7 @@
@namespace DeepDrftPublic.Client.Controls.AudioPlayerBar
-
+