Hearts pink (`#fb9fb1`), Diamonds gold (`#ddb26f`), Clubs lime
(`#acc267`), Spades gray (`#d0d0d0`) — each suit picks up its
own base16-eighties accent so a player scanning the table can
distinguish the suit by hue alone (faster recognition than the
2-colour traditional red/black scheme; common in poker decks).
All four colours already exist in the palette as semantic
state-token accents, so this is a pure remapping at the suit-
glyph site, not a palette extension.
The outlined-glyph differentiation (♦ ♣ outlined, ♥ ♠ filled)
is preserved on top of the colour split — it stays the always-
on colour-blind fallback per `design-system.md` §Accessibility,
and matters more than ever now that CBM hearts (lime) and
default clubs (lime) share a hue.
### Changes
- `card_face_svg.rs`: split `SUIT_RED` / `SUIT_DARK` into four
per-suit constants (`SUIT_HEART` / `SUIT_DIAMOND` / `SUIT_CLUB`
/ `SUIT_SPADE`). `suit_paint()` returns each suit's own
colour. Card border picks up the suit colour automatically
via the existing `(colour, paint)` destructure.
- `card_plugin.rs`: new `DIAMOND_SUIT_COLOUR` + `CLUB_SUIT_COLOUR`
constants; `text_colour()` rewritten as a per-suit match (was
red/black bifurcation). Both rendering paths (PNG production +
constant fallback under MinimalPlugins) stay in lockstep.
- CBM behaviour clarified: only hearts swap to lime now;
diamonds + clubs + spades are already hue-distinct from
the heart pink and stay unchanged. Under CBM the heart
(lime) and club (lime) share a hue but stay distinguishable
via the always-on filled-vs-outlined glyph differentiation.
- HC behaviour: only hearts (→ HC red) and spades (→ HC white)
have defined boosts. Diamonds (gold) and clubs (lime) are
already mid-luminance accents and stay at their default.
New test `text_colour_diamonds_and_clubs_are_immune_to_accessibility_flags`
pins all four flag combinations as no-ops for the gold +
lime suits.
- `design-system.md` §Suit Colors retitled "Four-color deck"
with the 4-colour table; CBM section text updated to
describe the hearts-only swap and the hearts/clubs hue
collision under CBM.
- `card_face_svg_pin.rs` rebaselined: 26 hashes drift
(13 clubs + 13 diamonds — the two suits whose colours
changed). Hearts, spades, and the 5 backs all keep their
prior hashes. Surgical scope, exactly what the pin test
was designed to surface.
### Tests
1191 passing / 0 failing — net 0 from the prior baseline:
two old 2-colour tests removed
(`text_colour_is_red_for_hearts_and_diamonds`,
`text_colour_is_black_for_clubs_and_spades`), one consolidated
4-colour test added
(`text_colour_4_colour_deck_assigns_each_suit_its_own_hue`)
plus a pairwise-distinct invariant guard, and one new test
covering the gold/lime suits' immunity to CBM/HC flags. Six
existing CBM/HC tests rewritten to use only the suits each flag
actually affects under the new scheme (hearts for CBM, hearts +
spades for HC).
Workspace clippy clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Project-wide palette shift at user request. Replaces the cyan
primary accent everywhere it surfaces — splash boot screen,
home menu glyphs, action chevrons, replay overlay banner +
scrub fill + chip border, achievement checkmarks, leaderboard
#1 indicator, radial menu fill, focus ring, card-back canonical
badge, etc. — with `#a54242` from the same base16-eighties
family as the existing pink suit colour.
Knock-on changes that all land in this commit per the
lockstep rule:
- ui_theme.rs: ACCENT_PRIMARY (#a54242), ACCENT_PRIMARY_HOVER
(#c25e5e brightened companion), FOCUS_RING (same hue, 0.85
alpha). Module-level palette comment + STOCK_BADGE_FG +
CARD_SHADOW_ALPHA_DRAG doc strings updated to match.
- card_plugin.rs: card_back_colour(0) now returns the brick-red
ACCENT_PRIMARY (was cyan). RED_SUIT_COLOUR_CBM swapped from
cyan to lime #acc267 — the CBM alternative needs to stay
hue-distinct from the new red-family primary, lime is the
next-best non-red base16-eighties accent. text_colour doc
+ CBM tests renamed cyan→lime in lockstep
(text_colour_color_blind_mode_swaps_red_suits_to_lime).
- card_face_svg.rs: BACK_ACCENTS[0] now "#a54242" (canonical
Terminal back).
- splash_plugin.rs / ui_modal.rs / replay_overlay.rs /
selection_plugin.rs: descriptive "cyan" comments swapped to
"accent" / "primary-accent" wording so the doc strings stay
decoupled from any specific hue. Future palette tweaks won't
require comment churn.
- design-system.md: YAML token frontmatter updated (primary,
surface-tint, suit-red-cb, primary-container,
on-primary-container, inverse-primary). Palette table gains
a project-specific `base08` slot for the new red. CTA /
Selection / Card-back badge / Primary button / Bottom-bar
active-icon / glow / CBM swap text all retuned. Historical
references preserved (e.g. "Was cyan #6fc2ef before the
2026-05-08 swap") so the audit trail stays in the spec.
- card_face_svg_pin.rs: rebaselined. Exactly one hash drift
(back_0 — the canonical Terminal back's badge changed
colour). Other 56 hashes identical (face SVGs don't
reference the accent; back_1..4 use unchanged accents). The
one-hash-drift signal confirms the change scope was
surgical.
Workspace clippy + cargo test --workspace clean, 1184 passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The user noticed the bottom-right large suit glyphs were
rendering upside-down — point-up hearts, stem-up spades — because
the SVG transform pipeline applied a `rotate(180)` to match the
traditional playing-card inverted-corner convention.
That convention exists so a card reads correctly when flipped or
read from the opposite side of the table. Single-orientation
digital play doesn't benefit from it; most modern digital decks
have abandoned it. User preference is upright.
Drops the rotate from face_svg's bottom-right `<g transform>`
and adjusts the translate so the visible glyph still lands at
(178, 286)–(242, 350) — same screen footprint, same scale, just
no flip.
design-system.md § Game Cards updated in lockstep — line 220
no longer says "rotated 180°", instead documents the deliberate
deviation from the traditional convention.
Knock-on lockstep changes in this commit:
- EXPECTED in tests/card_face_svg_pin.rs rebaselined: 52 face
hashes shift, 5 back hashes unchanged.
- assets/cards/faces/*.png regenerated (52 face PNGs).
- solitaire_engine/assets/themes/default/*_*.svg regenerated
(52 theme face SVGs that production rasterises at startup).
Workspace clippy + cargo test --workspace clean. Pin test
passes against the new hashes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Lays out the lockstep migration from legacy white-card PNGs +
constants to the Terminal aesthetic. Steps 4 + 5 (artwork +
constant + test updates) must land in one commit so the PNG
path and the constant-fallback path don't visually diverge.
Tracks Option D from the SESSION_HANDOFF Resume prompt.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Closes the spec gap flagged after v0.20.0: the 24 mockups in
docs/ui-mockups/ are 23 mobile + 1 desktop, but desktop is still
the primary delivery surface. Stitch's variant generation kept
timing out on layout-only adaptation prompts, so the deterministic
fix is rules-based: a markdown spec that captures (a) the desktop
viewport assumptions, (b) seven universal adaptation rules that
apply to every screen, and (c) per-screen geometry rules for the
priority surfaces (Game Table, Win Summary, Settings, Help, Pause,
Home, Splash, Stats, Profile / Achievements / Theme Picker / Daily
Challenge).
Why rules > visual mockups for this gap:
- Apply uniformly to every screen — including the 9 missing-plugin
surfaces (splash, challenge, time-attack, weekly-goals, leader-
board, sync, level-up, replay-overlay, radial-menu) that have
only mobile mockups today.
- Reference-able from code comments and commit messages without
loading an image.
- Layout-agnostic by construction: tells the engine "use percent /
flex / min(720, 50%) widths" instead of pinning a specific
desktop pixel layout.
- Cheaper than re-running Stitch generation per screen, which is
flaky for layout-only adaptation work.
Cross-check confirms that v0.20.0's port (modal scaffold, toasts,
table chrome, card chrome, gameplay-feedback, splash cursor) is
already layout-agnostic — the spec gap mattered for *next* ports,
not the work that just shipped.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the spec the recent visual-identity port pass referenced:
- design-system.md — base16-eighties palette, type scale, spacing
scale, motion budget, component library, accessibility notes
(color-blind toggle, high-contrast mode, glyph differentiation),
and the canonical "Terminal" card-back theme.
- 24 Stitch-rendered mockups (HTML + PNG): 12 redesigned existing
screens, 1 desktop home variant, 2 onboarding steps, and 9
missing-plugin screens (splash, challenge, time-attack,
weekly-goals, leaderboard, sync, level-up, replay, radial-menu).
These mockups are the source the engine plugins were ported
against in commits 0d477ac through 9891ae4 (token system,
modal scaffold, gameplay-feedback layer, toasts, table chrome,
card chrome, splash cursor, hint highlight). Future plugin work
should diff against the matching mockup before touching pixels.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>