diff --git a/DeepDrftPublic.Client/Controls/MixWaveformVisualizer.razor.css b/DeepDrftPublic.Client/Controls/MixWaveformVisualizer.razor.css
index 78a7d01..91583b2 100644
--- a/DeepDrftPublic.Client/Controls/MixWaveformVisualizer.razor.css
+++ b/DeepDrftPublic.Client/Controls/MixWaveformVisualizer.razor.css
@@ -1,8 +1,19 @@
/* Full-viewport fixed backdrop. Sits behind the detail content (.mix-detail-foreground is z-index:1)
- and never intercepts pointer events — except the zoom slider, which re-enables them on itself. */
+ and never intercepts pointer events — except the zoom slider, which re-enables them on itself.
+
+ Footer clip (Phase 10 W1, spec §2c): the backdrop must stop cleanly ABOVE the audio player bar so
+ no lava/waveform pixel paints over or under it. `overflow: hidden` clips the canvas to this box, and
+ `bottom` is inset by the player bar's LIVE height — `--player-height`, the custom property the player
+ already publishes on :root via its ResizeObserver (AudioPlayerBar + Interop/layout/spacer.ts). That
+ var tracks the expanded bar's border-box height across breakpoints/error-banner reflow, and resets to
+ 0 when the bar is minimized — so the clip line follows the bar's actual current height with no extra
+ coupling: when minimized the var is 0 and the backdrop reaches the viewport bottom (the floating FAB,
+ z-index 1300, simply sits over it — there is no full-width bar to clip to), matching spec §2c. The
+ 0px fallback keeps the backdrop full-height on any page that doesn't host the player. */
.mix-waveform-bg {
position: fixed;
inset: 0;
+ bottom: var(--player-height, 0px);
z-index: 0;
pointer-events: none;
overflow: hidden;
diff --git a/DeepDrftPublic/Interop/visualizer/MixVisualizer.ts b/DeepDrftPublic/Interop/visualizer/MixVisualizer.ts
index e6d2a08..e2952dc 100644
--- a/DeepDrftPublic/Interop/visualizer/MixVisualizer.ts
+++ b/DeepDrftPublic/Interop/visualizer/MixVisualizer.ts
@@ -855,9 +855,13 @@ void main() {
// most effective "this is glass" cue (spec §4f.4).
float fresnel = pow(1.0 - max(dot(N, V), 0.0), GLASS_FRESNEL_POWER);
- // Frosted translucency: a subtle noise modulation of alpha so edges read soft/lit
- // rather than hard — the "frosted glass" cue done in-shader (no CSS blur, §4f.3).
- float frost = 0.85 + 0.15 * valueNoise(vec2(screenX * 0.05, screenYTop * 0.05));
+ // REMOVED (Phase 10 W1 de-noise, spec §3): the screen-space "frost" alpha noise —
+ // frost = 0.85 + 0.15 * valueNoise(vec2(screenX*0.05, screenYTop*0.05)). It was a
+ // static value-noise keyed to SCREEN coordinates (not the moving fluid), so it sat as
+ // a fixed grainy/dirty film over the whole ribbon — exactly the "static-looking texture
+ // that makes the screen look dirty" Daniel rejected. Alpha is now the clean backdrop
+ // opacity with no grain. (Fluid-tied noise — the bubble swell and the colour-field drift,
+ // both keyed to mix-time — is retained: it moves with the audio and does not read as dirt.)
// Compose the lit glass colour: field base + warped refraction, lifted by sheen and
// a Fresnel rim toward the VIVID moss accent, plus a white-hot specular dot. Using the
@@ -867,9 +871,10 @@ void main() {
lit = mix(lit, vividAccent * 1.3, fresnel * 0.7); // rim glows vivid moss
lit += spec * vec3(1.0); // specular is white light
- // Alpha: the backdrop opacity, lifted at the rim (Fresnel) so edges catch light, and
- // softened by the frost. Pre-multiplied output for the ONE/ONE_MINUS_SRC_ALPHA blend.
- float alpha = inside * RIBBON_OPACITY * frost;
+ // Alpha: the backdrop opacity, lifted at the rim (Fresnel) so edges catch light.
+ // (Frost removed — see the de-noise note above.) Pre-multiplied output for the
+ // ONE/ONE_MINUS_SRC_ALPHA blend.
+ float alpha = inside * RIBBON_OPACITY;
alpha = clamp(alpha + inside * fresnel * RIBBON_OPACITY * 0.8, 0.0, 1.0);
fragColor = vec4(lit * alpha, alpha);
diff --git a/DeepDrftShared.Client/Common/DDIcons.cs b/DeepDrftShared.Client/Common/DDIcons.cs
index 271a28f..ab6f6d0 100644
--- a/DeepDrftShared.Client/Common/DDIcons.cs
+++ b/DeepDrftShared.Client/Common/DDIcons.cs
@@ -24,17 +24,24 @@ public static class DDIcons
""";
///
- /// Lava lamp - the Mix visualizer settings glyph. Inner path/shape markup for MudBlazor's Icon= slot
- /// (no outer <svg> wrapper — MudBlazor supplies that). Tapered base, tall rounded glass vessel,
- /// a cap, and three suspended blobs at varied heights. The silhouette is currentColor so it themes
- /// with its context (Color.Secondary tint, light/dark). The blobs carry a warm two-tone accent à la
- /// the gas-lamp flame so the lamp reads as "lit" at icon size; coordinates are in the 24×24 space
- /// that matches MudBlazor's viewBox="0 0 24 24" wrapper.
+ /// Lava lamp - the Mix visualizer settings glyph. Classic 1970s "Lava" silhouette, redrawn (Phase 10
+ /// W1). Inner path/shape markup for MudBlazor's Icon= slot (no outer <svg> wrapper — MudBlazor
+ /// supplies that); coordinates in the 24×24 space matching viewBox="0 0 24 24".
+ ///
+ /// Bottom→top: a WIDE truncated-cone metal BASE (widest at the very bottom, tapering up to a narrow
+ /// waist); a tall tapered GLASS VESSEL on the base — bulbous/rounded at the bottom, tapering up to a
+ /// roundedly-pointed (teardrop/bullet) top; a small truncated-cone metal CAP on top mirroring the base.
+ /// The metal base + cap are currentColor so the silhouette stays tintable with its context
+ /// (Color.Secondary, light/dark). The fluid + blobs are hard navy/moss so the lamp reads as "lit" at
+ /// icon size: navy (#17283F) vessel fluid with 3 varied moss (#429D6A) lava blobs suspended in it.
+ /// NOTE: these hexes mirror the app theme tokens (navy ~#17283F/#0D1B2A, moss ~#3D7A68/#429D6A).
///
public const string LavaLamp = """
-
-
-
-
+
+
+
+
+
+
""";
}