16 KiB
Track Card Theming — align fallback + text with NowPlayingCard
Status: completed. Author: product-designer. Date: 2026-06-05. Implementer: maintenance-engineer. Landed 2026-06-05.
Goal
Make the public tracks-page track cards match the NowPlayingCard's established visual language:
- Fallback background (no album art) → navy-blue glassy look (translucent + blur),
as used by
.now-playing. - Card text → moss-green accent (
--deepdrft-green-accent=#3D7A68) for the label-grade text, matching.np-label/ waveform bars.
Scope constraint (read before implementing)
TrackCard.razor lives in DeepDrftShared.Client, which is consumed by both the
public site (light + dark) and the CMS host (DeepDrftManager, light-only). Any change
to TrackCard's defaults is inherited by the CMS. The NowPlayingCard aesthetic is a
dark-on-dark treatment; applying it unconditionally would break legibility on the CMS's
off-white surfaces.
Therefore the fix must be theme-aware, not a flat recolor. The dark/navy-glass +
moss-green treatment applies under .deepdrft-theme-dark; light/CMS keeps a legible
on-light treatment. The hooks below are written so a single CSS file carries both.
The card CSS lives in DeepDrftPublic/wwwroot/styles/deepdrft-styles.css section 8. That
stylesheet is served by the public host and (per its own header comment) is shared across
server and client of the public app. It is not loaded by the CMS host. This is
actually convenient: putting the navy-glass treatment in section 8 means it only reaches
the public site. The CMS gets TrackCard with no .deepdrft-track-card-* styling beyond
whatever MudBlazor defaults apply. Confirm during implementation that the CMS still
renders TrackCard legibly (it currently relies on the same classes; if the CMS does not
link this stylesheet, the fallback mud-theme-secondary is the only thing styling it).
If the CMS does not actually use TrackCard in any live page, this concern is moot — verify
before spending effort on the light path.
1. Current problems
1a. Fallback background resolves to white
TrackCard.razor line 11:
<MudPaper Class="deepdrft-track-card-fallback mud-theme-secondary" Elevation="0">
mud-theme-secondary paints the element with the theme's Secondary palette color.
In the dark palette (DeepDrftPalettes.Dark), Secondary = "#FAFAF8" (off-white). So a
track with no album art renders as a white card on the navy page — the opposite of the
intended navy-glass look, and it makes the white-intended text invisible-by-collision.
(In the light/CMS palette, Secondary = #1A3C34 deep green — a dark card on a light page,
also not the intended look but at least legible. Either way mud-theme-secondary is the
wrong abstraction here.)
1b. All card text resolves to near-invisible navy
Every MudText in TrackCard uses Color="Color.Surface" (lines 20, 26, 36, 57). MudBlazor's
Color.Surface maps to the palette Surface color. In the dark palette,
Surface = "#162437" (navy-mid). So all text is navy-mid:
- On the current buggy white fallback: barely legible (low contrast dark-on-white, but the white itself is wrong).
- On the intended navy-glass fallback: near-invisible (navy-mid text on a navy-translucent ground — contrast well below WCAG AA).
- On a real album-art background (
.deepdrft-track-card-bg,brightness(0.7)): unreliable, depends entirely on the artwork.
Color.Surface is semantically "the color of a surface," never intended as a text color.
This is the root mistake.
1c. No per-component scoped CSS exists
There is no TrackCard.razor.css. All TrackCard styling is global in section 8 of
deepdrft-styles.css plus MudBlazor utility classes applied inline. The fix can stay in
section 8 (preferred — keeps the public-only scoping described above) rather than
introducing a scoped file.
2. Proposed changes
Two coordinated edits: (A) remove the wrong MudBlazor color utilities from the Razor so CSS can own the colors, (B) add navy-glass + moss-green rules to section 8.
2a. Razor changes — DeepDrftShared.Client/Components/TrackCard.razor
Goal: stop hard-binding to palette Secondary/Surface; hand color control to CSS via stable class hooks.
Fallback MudPaper (line 11): remove mud-theme-secondary. Replace the class list with
a single semantic hook:
<MudPaper Class="deepdrft-track-card-fallback" Elevation="0">
The navy-glass background moves into the .deepdrft-track-card-fallback CSS rule (2b).
Text elements (lines 19–23, 25–29, 35–39, 57–60): remove the Color="Color.Surface"
attribute from each MudText. Add class hooks so CSS can assign the moss-green / hierarchy
colors. Suggested hooks (match the NowPlayingCard's title/label/sub hierarchy):
- Track name (line 19,
Typo.subtitle1) → adddeepdrft-track-titleto itsClass. CurrentlyClass="text-truncate mb-1"→Class="deepdrft-track-title text-truncate mb-1". - Artist (line 25,
Typo.caption) → adddeepdrft-track-artist.Class="text-truncate mb-2"→Class="deepdrft-track-artist text-truncate mb-2". - Album (line 35,
Typo.caption) → adddeepdrft-track-meta.Class="text-truncate"→Class="deepdrft-track-meta text-truncate". - Release year (line 57,
Typo.caption) → adddeepdrft-track-meta. Has noClasstoday → addClass="deepdrft-track-meta".
Do not add inline Style or MudBlazor Color values; all color lives in CSS so the
theme-aware split works.
2b. CSS changes — DeepDrftPublic/wwwroot/styles/deepdrft-styles.css section 8
Reference values from NowPlayingCard (NowPlayingCard.razor.css):
- glass background:
rgba(250, 250, 248, 0.06) - glass border:
1px solid rgba(250, 250, 248, 0.12) - blur:
backdrop-filter: blur(8px) - label/accent text:
var(--deepdrft-green-accent)(#3D7A68) - title text:
var(--deepdrft-white)(#FAFAF8) - sub text:
rgba(250, 250, 248, 0.45)
Note: NowPlayingCard's glass is a light-tinted translucency (rgba(250,250,248,…))
over the navy page, which reads as navy-glass because the navy page shows through. To make
the fallback unambiguously "navy-blue glassy" even where the page behind it is not pure
navy (e.g. over a gradient), tint with navy explicitly. Use the navy token at low alpha
plus the same light border/blur. Both options below are acceptable; Option A matches
NowPlayingCard literally, Option B is more robustly navy. Recommend Option B for
the fallback since the card is a discrete object on a varied page, where NowPlayingCard
sits in a known navy context.
Replace the existing .deepdrft-track-card-fallback rule (currently only position/size)
and add the text rules. Proposed block (dark-mode treatment scoped under
.deepdrft-theme-dark; base rule keeps layout only):
/* Fallback panel — layout (theme-agnostic) */
.deepdrft-track-card-fallback {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* Fallback panel — navy-glass treatment, dark theme only.
Mirrors NowPlayingCard's .now-playing glass. */
.deepdrft-theme-dark .deepdrft-track-card-fallback {
/* Option A (literal NowPlayingCard match):
background: rgba(250, 250, 248, 0.06); */
/* Option B (recommended — explicit navy tint): */
background: color-mix(in srgb, var(--deepdrft-navy) 55%, transparent);
border: 1px solid rgba(250, 250, 248, 0.12);
backdrop-filter: blur(8px);
}
/* Card text — dark theme. Moss-green for label-grade text, off-white title. */
.deepdrft-theme-dark .deepdrft-track-title {
color: var(--deepdrft-white);
}
.deepdrft-theme-dark .deepdrft-track-artist {
color: var(--deepdrft-green-accent);
}
.deepdrft-theme-dark .deepdrft-track-meta {
color: rgba(250, 250, 248, 0.55);
}
Decision needed (1 of these): the user said "track card text → the moss-green color." Two readings:
- Title in moss-green, supporting text muted — strongest match to "card text is the
moss green," puts the green on the most prominent line. Use:
.deepdrft-track-title { color: var(--deepdrft-green-accent); }and demote the artist to off-white or muted. - NowPlayingCard hierarchy (title off-white
#FAFAF8, accent green on the label, sub muted) — the block above. This is the literal NowPlayingCard mapping: green is the accent/label color, not the title color.
The block above implements a hybrid (artist line in green). Recommend reading 1 — it most directly satisfies "card text → moss green" and reads well on the navy-glass ground: title in moss-green, artist + meta in muted off-white. If the user wants the literal NowPlayingCard hierarchy instead, swap to reading 2. Flag this back to the user if ambiguous; otherwise default to reading 1:
/* Reading 1 (recommended default) */
.deepdrft-theme-dark .deepdrft-track-title { color: var(--deepdrft-green-accent); }
.deepdrft-theme-dark .deepdrft-track-artist { color: rgba(250, 250, 248, 0.70); }
.deepdrft-theme-dark .deepdrft-track-meta { color: rgba(250, 250, 248, 0.55); }
2c. Text legibility over real album art
When album art is present (.deepdrft-track-card-bg), the same text classes now apply.
Moss-green/off-white over arbitrary artwork at brightness(0.7) can still be low-contrast.
NowPlayingCard never sits over artwork, so it gives no precedent. Recommend a scrim behind
the content to guarantee contrast in both art and fallback cases:
.deepdrft-track-card-content {
/* existing rules unchanged; add: */
background: linear-gradient(to top,
rgba(13, 27, 42, 0.75) 0%,
rgba(13, 27, 42, 0.35) 45%,
rgba(13, 27, 42, 0.0) 100%);
}
This is optional but recommended — it makes the green/off-white text legible over both the
fallback glass and any album art, and reinforces the navy identity. If the user prefers the
fallback glass to read cleaner without a scrim, gate the scrim to art-only by moving it to
.deepdrft-track-card-bg as an ::after overlay instead. Recommend the content-level
scrim for uniformity. Confirm with the user if the glassy fallback should stay scrim-free.
2d. Light / CMS path
With the dark treatment scoped under .deepdrft-theme-dark, light mode currently gets no
explicit text color (the removed Color.Surface) and no fallback background beyond the
base layout rule. That means:
- Light fallback card → transparent (shows the page behind it). Likely undesirable.
- Light text → inherits MudBlazor body text (navy
#0D1B2A), which is legible on a light ground. Acceptable.
Add a minimal light treatment so the public site's light mode and the CMS don't regress to a transparent fallback:
.deepdrft-theme-light .deepdrft-track-card-fallback {
background: color-mix(in srgb, var(--deepdrft-navy) 8%, var(--deepdrft-white));
border: 1px solid var(--deepdrft-border);
}
Text in light mode can be left to inherit (navy on light reads fine) or, for consistency
with the green identity, set the title to --deepdrft-green-accent in light too — the
accent green has adequate contrast on a near-white card. Recommend leaving light text to
inherit unless the user wants the green identity carried into light mode.
CMS caveat: the CMS host does not link deepdrft-styles.css (it is in DeepDrftPublic/wwwroot).
If the CMS renders TrackCard, none of these rules reach it and the fallback will be
unstyled. Verify whether the CMS uses TrackCard at all before investing in the CMS path; if
it does, the light-mode rules need to live in the shared token/style layer the CMS does
load, not in deepdrft-styles.css. This is the one open structural question — resolve
it before implementing the light path.
3. Other theming issues spotted on the tracks page
Beyond the two the user called out:
3a. Genre chip uses Color.Primary — green-on-navy collision (dark)
TrackCard.razor line 48: <MudChip Color="Color.Primary">. In the dark palette
Primary = "#3D7A68" (the same moss-green we're about to use for text). A green chip sitting
next to green text on a navy-glass card flattens the hierarchy — everything is one green.
Recommend giving the chip its own treatment: filled navy-mid with green text/border, or a
subtle outlined variant, so it reads as a distinct tag rather than blending into the text.
Suggested: Variant="Variant.Outlined" with a .deepdrft-genre-chip color override to
--deepdrft-green-accent border + text on transparent. Low priority; raise with user.
3b. Play FAB uses Color.Primary — same green, but here it's correct
Line 67: <MudFab Color="Color.Primary">. Green FAB on navy is the intended interactive
accent (matches the dark palette's "green-accent is the primary interactive color" note in
DeepDrftPalettes.Dark). No change — this is the one place the green-as-primary mapping
is right. Noting it so the implementer doesn't "fix" it while touching the chip.
3c. Loading skeletons are theme-default gray
TracksView.razor lines 30, 37 use bare MudSkeleton. MudBlazor skeletons render in a
neutral gray that does not match the navy-glass language — on the navy dark page they'll be
light-gray rectangles, a jarring pre-load flash before the navy cards appear. Recommend
tinting skeletons toward the navy-glass treatment (rgba(250,250,248,0.06) pulse) so the
loading state previews the real cards. Low priority, but it's the most visible remaining
mismatch with the NowPlayingCard aesthetic on this page. Defer unless the user wants polish.
3d. Card container has no border / elevation language matching the glass
.deepdrft-track-card-container (section 8) sets size + overflow: hidden and relies on
MudCard Elevation="4" (a drop shadow). NowPlayingCard uses a 1px translucent border + no
shadow for its flat-glass look. The track cards' Material drop-shadow is a different visual
vocabulary. For full alignment, consider Elevation="0" on the MudCard plus a
1px solid rgba(250,250,248,0.12) border on the container (dark) to match the glass edge.
Medium priority — this is what most distinguishes "Material card" from "NowPlayingCard glass
panel." Worth doing if the goal is genuine aesthetic match, not just color.
3e. --deepdrft-green-accent is not defined inside .deepdrft-theme-dark
The token block (deepdrft-tokens.css) defines --deepdrft-green-accent: #3D7A68 only in
:root. The .deepdrft-theme-dark block re-declares the alias layer but inherits the raw
--deepdrft-* wireframe tokens from :root. NowPlayingCard already uses
var(--deepdrft-green-accent) successfully under dark, so the cascade resolves fine — no
action needed, just confirming the token is in scope for the new rules. Noting it so the
implementer doesn't worry the var is undefined in dark.
4. Summary of edits for the implementer
| File | Change | Priority |
|---|---|---|
DeepDrftShared.Client/Components/TrackCard.razor |
Drop mud-theme-secondary from fallback; drop Color="Color.Surface" from all 4 MudText; add class hooks deepdrft-track-title / -artist / -meta |
required |
DeepDrftPublic/wwwroot/styles/deepdrft-styles.css §8 |
Navy-glass fallback (dark), moss-green/off-white text (dark), light fallback fallback-bg, optional content scrim | required |
| same §8 / §9 | Genre chip distinct treatment (3a) | optional |
DeepDrftShared.Client/Components/TrackCard.razor |
MudCard Elevation="0" + glass border on container (3d) |
recommended for true match |
TracksView.razor skeleton tint (3c) |
polish | defer |
5. Open questions to resolve before / during implementation
- Green on title vs. green on label (§2b reading 1 vs 2). Default to reading 1 (title in moss-green) unless the user says otherwise.
- Does the CMS host render TrackCard, and does it link
deepdrft-styles.css? Determines whether the light-mode rules belong indeepdrft-styles.cssor the shared token layer. This is the only blocker for the light path; the dark path (what the user actually asked for) is unblocked. - Scrim or no scrim over album art (§2c). Recommend yes; confirm.
- Match the glass edge (Elevation 0 + border, §3d) — confirm the user wants full aesthetic match vs. color-only.