Compare commits

..

9 Commits

Author SHA1 Message Date
funman300 f63db769ae docs: cut v0.21.6 — Move Log panel + scrub-UX polish
Patch release rolling up six post-v0.21.5 commits under the
through-line "Move Log panel + scrub-UX polish":

- d3cb1a5: HC-mode coverage for scrub track + notches
- 2e25476: continuous scrub on key-held ← / → at 100ms cadence
- d6f32d3: Move Log panel + active row (header + format helpers)
- 140251b: 2 prev rows above active
- e7345ae: active-row highlight with ACCENT_PRIMARY background
- 4437a1a: 2 next rows below active

The Move Log panel is the first replay-overlay surface that
isn't attached to the banner — it lives at a separate screen
anchor (bottom: 0) with its own spawn/despawn lifecycle.
Establishes the multi-anchor replay UI pattern that the
remaining B-2 sub-piece (mini-tableau preview) will inherit.

Panel grows 56 → 84 → 112 px across the four move-log commits.
HighContrastBackground primitive lifted to ui_theme parallel
to HighContrastBorder; settings_plugin gains
update_high_contrast_backgrounds for the BackgroundColor
repaint cycle. Continuous scrub uses a per-key accumulator
resource (ReplayScrubKeyHold) gated on SCRUB_REPEAT_INTERVAL_SECS
(0.1s).

Tests: 1250 → 1273 (+23 net new). Clippy clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:46:24 -07:00
funman300 4437a1aaf9 feat(replay): add 2 next rows below active row in Move Log panel
Symmetric to the prev-rows commit. Adds 2 about-to-apply move
rows below the active row so the panel now shows a full 5-row
window: prev offset 2 → prev offset 1 → active → next offset 1
→ next offset 2. Panel grows from 84 → 112 px to fit the
additional rows.

Format helper `format_kth_next_row(state, k)` returns the kth
about-to-apply move's text:
- k=1 → moves[cursor], displayed as "{cursor + 1} │ {body}"
- k=2 → moves[cursor + 1], displayed as "{cursor + 2} │ ..."
- Returns empty when cursor + k - 1 >= moves.len() (under-fill
  late in the replay) or k=0 (degenerate).

Symmetric implementation:
- New `ReplayOverlayMoveLogNextRow { offset: u8 }` component
- Spawn loop iterates 1..=MOVE_LOG_NEXT_ROWS in order so offset
  1 sits directly below active, offset 2 below that
- Per-frame `update_move_log_next_rows` system mirrors the
  prev-rows updater
- TEXT_SECONDARY (matching prev rows) keeps the active row's
  highlight as the focal point

For post-game replays the next rows aren't spoilers (the game
is already won). If a future use case reuses the panel during
live play, the preview-shape would need rethinking.

4 new tests:
- format_kth_next_row: k=1, 2 in-range cases + k beyond
  moves.len() out-of-range + k=0 degenerate.
- move_log_next_rows_spawn_with_panel: cardinality matches
  MOVE_LOG_NEXT_ROWS.
- move_log_next_rows_paint_helper_strings_at_spawn: text
  matches helper output per offset.
- move_log_next_rows_underfill_at_replay_end: offset 1
  populates at cursor=9/10, offset 2 stays empty.

Tests: 1269 → 1273. Clippy clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:44:59 -07:00
funman300 e7345aed6c feat(replay): highlight active row in Move Log panel
Wraps the active-row Text in a Node with
BackgroundColor(ACCENT_PRIMARY) so the row reads as "current
focus" against the panel's elevated background. Inner Text
colour bumps from TEXT_PRIMARY (#d0d0d0) to TEXT_PRIMARY_HC
(#f5f5f5) for legible contrast against the brick-red highlight.

format_active_move_row now prefixes the row with `▶` (the focus
marker) so the visual hierarchy is reinforced even before the
background paints (HC mode, future palette tweaks). The empty
case still returns empty — cursor=0 doesn't paint a stray "▶ "
prefix on an otherwise-empty row.

Mirrors the mockup at docs/ui-mockups/replay-overlay-mobile.html
§ "Move Log Card" where the active row has bg-suit-red-cb
(brick-red equivalent) + dark text + the ▶ marker.

3 new tests:
- active_row_wrapper_carries_accent_primary_background: walks
  from the active-row Text to its parent Node and asserts the
  wrapper carries BackgroundColor(ACCENT_PRIMARY).
- active_row_text_uses_high_contrast_color_for_highlight: pins
  the TextColor as TEXT_PRIMARY_HC.
- active_row_format_includes_focus_prefix: pure-helper guard for
  the ▶ prefix + the cursor=0-stays-empty contract.

Plus 2 existing tests updated for the new prefixed format
(format_active_move_row_handles_cursor_zero_and_positive,
move_log_active_row_repaints_on_cursor_advance).

Tests: 1266 → 1269 (+3 net new, +2 updated). Clippy clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:41:14 -07:00
funman300 140251beae feat(replay): add 2 prev rows above active row in Move Log panel
Extends the Move Log panel's single active-row to a 3-row recent-
history window: 2 prev rows showing the moves applied just before
the active one, then the active row. Display order top-to-bottom:
header → prev offset 2 (oldest) → prev offset 1 → active.

Panel grows from 56 → 84 px to fit the additional rows. Active
row keeps TEXT_PRIMARY; prev rows render in TEXT_SECONDARY so
the active row stands out from context rows even without an
explicit highlight. (Active-row highlight is a follow-up commit.)

The format helper generalises:
- New `format_kth_recent_row(state, k)` returns the text for the
  kth-most-recently-applied move (k=1 is active, k=2 is row above,
  etc.). Returns empty when k > cursor (early-replay under-fill)
  or k = 0 (degenerate).
- `format_active_move_row` becomes a thin wrapper for k=1, kept
  at module scope so call sites stay readable.

New `ReplayOverlayMoveLogPrevRow { offset: u8 }` component carries
the row's offset (1 = just-before-active, 2 = before that). Spawn
loop iterates `MOVE_LOG_PREV_ROWS..=1` in reverse so the highest-
offset (oldest) row sits topmost in the panel's flex column.

Per-frame `update_move_log_prev_rows` system reads each row's
offset, computes k = offset + 1, and repaints via
format_kth_recent_row. Empty-when-out-of-range means panels gracefully
under-fill at cursor=1 (only active populated) and cursor=2
(active + offset 1, offset 2 empty).

4 new tests:
- format_kth_recent_row: k=1, 2, 3 in-range cases + k>cursor
  out-of-range + k=0 degenerate.
- move_log_prev_rows_spawn_with_panel: cardinality matches the
  MOVE_LOG_PREV_ROWS const.
- move_log_prev_rows_paint_helper_strings_at_spawn: text matches
  helper output per offset.
- move_log_prev_rows_repaint_on_cursor_advance: drives cursor=2
  → cursor=5 and asserts offset 1 / offset 2 texts follow.

Tests: 1262 → 1266. Clippy clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:35:07 -07:00
funman300 d6f32d3154 feat(replay): add Move Log panel with active-row readout
First slice of the move-log mockup at
docs/ui-mockups/replay-overlay-mobile.html § "Move Log Card".
Adds a separate root UI entity anchored to the viewport's bottom
edge (sibling-of-banner pattern, mirrors ReplayFloatingProgressChip
lifecycle) carrying a `▌ MOVE LOG · N/M` header plus a single row
showing the most-recently-applied move.

Subsequent commits in this multi-session arc add prev/next rows,
active-row highlight, and auto-scroll on cursor advance. Splitting
the work at "panel + active row only" lands the structural piece
(panel exists, lifecycle works, format helpers proven) before
tackling the harder questions about rendering un-applied future
moves and scrolling.

Position decision: bottom-of-viewport (matches mockup), separate
root entity from the 92 px top banner. Keeps the banner from
growing further into a top-heavy 170+ px strip; the
top-status + bottom-info paradigm reads as vim/IDE-style buffer
chrome that players intuitively scan.

Four pure helpers handle the formatting:
- format_pile(p) → lowercase, 1-indexed display string
  ("foundation 3" rather than enum's 0-indexed Foundation(2))
- format_move_body(m) → "{from} → {to}" or "stock cycle"
- format_move_log_header(state) → "▌ MOVE LOG · N/M",
  "▌ MOVE LOG · COMPLETE" for `Completed`, empty for `Inactive`
- format_active_move_row(state) → "{cursor} │ {body}" with
  1-based cursor for player display, empty at cursor=0

Two per-frame update systems (update_move_log_header,
update_move_log_active_row) repaint the texts on resource change
with the standard early-exit-on-no-change idiom.

Despawn handling: react_to_state_change gains a third query for
ReplayOverlayMoveLogPanel entities and despawns them on
Playing → Inactive alongside the banner root and floating chip.

Panel border carries HighContrastBorder so the 1 px top edge
bumps under HC mode — same pattern as the keybind footer.

8 new tests:
- format_pile pile-name + 1-index pinning
- format_move_body both-variant pinning
- format_move_log_header three-state coverage
- format_active_move_row cursor=0 vs cursor>0
- move_log_panel spawn cardinality (exactly one)
- move_log_panel header paints helper string at spawn
- move_log_active_row repaints on cursor advance
- move_log_panel despawn parity with overlay tree

Tests: 1254 → 1262. Clippy clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:29:37 -07:00
funman300 8fdc41f36f docs(handoff): record post-v0.21.5 polish; recommend notch-label centering
Two carve-outs land on top of v0.21.5:
- d3cb1a5: HC-mode coverage for scrub track + notches via new
  HighContrastBackground primitive in ui_theme + paint system
  in settings_plugin.
- 2e25476: continuous scrub on key-held ← / → at 100ms cadence;
  matches mockup's "[← →] scrub" terminology while keeping
  single-press = single-step semantics.

Update Since-cut log, status (1250 → 1254 tests passing,
flake cleared), and next-step menu. B-2 keyboard accelerator
coverage + accessibility + scrub UX are all complete; remaining
options are notch-label centering polish (smallest), the
move-log/mini-tableau multi-session arcs that close B-2, or
WIN MOVE marker HC bump (optional).

Recommended next-step: notch label centering (small).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:20:51 -07:00
funman300 2e25476d0a feat(replay): continuous scrub on key-held arrow keys
Holding ← or → now triggers continuous step at 100 ms cadence
(10 steps/sec) — matches the mockup's `[← →] scrub`
terminology while keeping single-press = single-step semantics.

Implementation: per-key accumulators in a new
`ReplayScrubKeyHold` resource. Each frame the key is held, the
corresponding accumulator absorbs `time.delta_secs()`; when it
exceeds `SCRUB_REPEAT_INTERVAL_SECS` (0.1s) the handler fires
another step and resets the accumulator. `just_pressed` events
bypass the accumulator entirely and fire immediately —
release resets to 0 so the next fresh press also fires
immediately rather than at half-interval.

Symmetric handling for ← (backwards step via undo) and →
(forward step). Both keys remain paused-only via the same
destructure-gate pattern in the underlying step helpers.

Footer text unchanged (`[← →] step`) — the only-wired-keybinds
discipline says "list what works"; held-key continuous scrub
is a discoverable enhancement to the same keybind, not a new
keybind.

`handle_arrow_keyboard` gains `Res<Time>` and
`ResMut<ReplayScrubKeyHold>` parameters. `Time` is provided by
MinimalPlugins's TimePlugin so headless tests already have it.

2 new tests (in addition to the 4 existing arrow scenarios):
- arrow_right_keyboard_repeats_while_held: drives time at
  exactly SCRUB_REPEAT_INTERVAL_SECS per tick and asserts that
  a second step fires after the just_pressed one.
- arrow_keyboard_release_resets_accumulator: verifies the
  release branch zeros the per-key accumulator.

Tests: 1252 → 1254. Clippy clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:19:46 -07:00
funman300 d3cb1a51d4 feat(replay): HC-mode coverage for scrub track + notches
The 1 px scrub track and 5 quarter-mark notch ticks paint their
shape via BackgroundColor (not BorderColor — they're tiny
full-bleed Nodes, not borders on wider containers), so the
existing HighContrastBorder marker doesn't apply to them.

Add a parallel primitive in ui_theme: HighContrastBackground
marker carrying default_color, mirroring HighContrastBorder's
shape exactly. Add update_high_contrast_backgrounds system in
settings_plugin alongside update_high_contrast_borders — same
on/off rule (off → marker.default_color, on → BORDER_SUBTLE_HC),
same change-suppression idiom (only mutate when different so
Bevy's change-detection doesn't trigger per-frame repaints).

Tag the scrub track Node and all five notch Nodes with
HighContrastBackground::with_default(BORDER_SUBTLE) so the
existing settings repaint cycle picks them up under HC mode.

The scrub fill (ACCENT_PRIMARY brick-red) and WIN MOVE marker
(STATE_SUCCESS lime-green) don't get the marker — accent and
state colours are already saturated and don't need an HC
luminance variant.

2 new tests: spawn-time marker presence on the track and
cardinality-matches-notch-count on the ticks.

Tests: 1250 → 1252. Clippy clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:14:03 -07:00
funman300 c8358f4275 docs(handoff): refresh post-v0.21.5 — anchor to new tag, reset menu state
Fold the six post-v0.21.4 commit narratives into CHANGELOG §
[0.21.5] (now the source of truth for that release's scope).
Reset the Since-cut log to "no threads in flight." Update
status (HEAD `a2432df`, tags through v0.21.5, tests still
1250/1249 passing pending the time-dependent flake clearing).
Resume prompt now anchors at v0.21.5 with the smaller post-cut
menu of next-finite-steps.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 17:08:56 -07:00
5 changed files with 1596 additions and 247 deletions
+113 -1
View File
@@ -6,9 +6,121 @@ project follows [Semantic Versioning](https://semver.org/).
## [Unreleased] ## [Unreleased]
No threads in flight. v0.21.5 cut on 2026-05-08; CHANGELOG accumulates No threads in flight. v0.21.6 cut on 2026-05-08; CHANGELOG accumulates
the next cycle here. the next cycle here.
## [0.21.6] — 2026-05-08
Patch release for the post-v0.21.5 work. Through-line:
**Move Log panel + scrub-UX polish**. v0.21.5 closed out the
keyboard-accelerator surface (Space / Esc / ← / →) and the
keybind footer; v0.21.6 builds on that with two parallel
threads — accessibility + scrub-on-hold polish for the v0.21.5
surfaces, plus a brand-new Move Log panel anchored to the
viewport's bottom edge that gives players a 5-row recent-and-
upcoming move history alongside the existing top-edge banner.
The Move Log panel is the first replay-overlay surface that
*isn't* attached to the banner — it lives at a separate screen
anchor (bottom: 0) with its own spawn/despawn lifecycle.
Establishes the pattern for "multi-anchor replay UI" that the
remaining B-2 sub-piece (mini-tableau preview) will inherit.
### Added
- **HC-mode coverage for the scrub track + quarter-mark notch
ticks** (`d3cb1a5`). Adds parallel primitive
`HighContrastBackground` to `ui_theme` and a paint system
`update_high_contrast_backgrounds` in `settings_plugin` that
mirrors the existing border-marker pattern but targets
`BackgroundColor` instead of `BorderColor`. Tags the 1 px
scrub track Node and all five quarter-mark notch ticks so
they bump from `BORDER_SUBTLE` (`#505050`) →
`BORDER_SUBTLE_HC` (`#a0a0a0`) under HC mode. Scrub fill
(`ACCENT_PRIMARY`) and WIN MOVE marker (`STATE_SUCCESS`)
don't get the marker — accent and state colours are already
saturated and don't need an HC luminance variant.
- **Continuous scrub on key-held arrow keys** (`2e25476`).
Holding ← or → triggers continuous step at 100 ms cadence
(10 steps/sec) — matches the mockup's `[← →] scrub`
terminology while keeping single-press = single-step
semantics. Per-key accumulators in a new
`ReplayScrubKeyHold` resource; `just_pressed` events bypass
the accumulator and fire immediately. Release resets to 0
so the next fresh press fires immediately rather than at
half-interval.
- **Move Log panel** (`d6f32d3` + `140251b` + `e7345ae` +
`4437a1a`). New bottom-edge UI panel showing a 5-row window
onto recent + upcoming moves: 2 prev rows above the active
row + active row highlighted in `ACCENT_PRIMARY` + 2 next
rows below. Header reads `▌ MOVE LOG · N/M` (or
`▌ MOVE LOG · COMPLETE` when finished). Active row carries
a `▶` focus prefix and `TEXT_PRIMARY_HC` text colour for
legible contrast against the brick-red highlight. Prev /
next rows render in `TEXT_SECONDARY` so the active row
stays the focal point.
- Sibling-of-banner pattern (separate root entity anchored
at viewport bottom, not a banner child) — same
spawn/despawn lifecycle as `ReplayFloatingProgressChip`,
different screen anchor.
- Five pure helpers handle the formatting:
`format_pile`, `format_move_body`,
`format_move_log_header`, `format_kth_recent_row` (active
+ prev), `format_kth_next_row` (next). 1-indexed display
numbers throughout (`Foundation(2)` reads as "foundation
3" rather than the enum's 0-index).
- Panel grows from 56 → 84 → 112 px across the four
move-log commits. `MOVE_LOG_PREV_ROWS` and
`MOVE_LOG_NEXT_ROWS` constants (both = 2) parameterise
the row count; `format_kth_recent_row` and
`format_kth_next_row` return empty for out-of-range k so
panels gracefully under-fill at the start (cursor=1) and
end (cursor=N-1) of a replay.
- HC marker on the panel's top border so the 1 px edge
bumps under HC mode (same pattern as the keybind footer).
### Changed
- **`react_to_state_change` despawns the Move Log panel** on
`Playing → Inactive` alongside the banner root and floating
progress chip. Third query in the same defer-and-despawn
cycle.
- **Move Log panel height grew 56 → 84 → 112 px** across the
prev-rows and next-rows commits. The panel is sized to fit
the chosen row count + header + padding; tunable via the
`MOVE_LOG_PANEL_HEIGHT` const.
- **`format_active_move_row` now prefixes the `▶` focus
marker** (`e7345ae`). Wraps `format_kth_recent_row(state, 1)`
and prepends the prefix when the body is non-empty. Empty
case still returns empty — cursor=0 doesn't paint a stray
`▶` on an otherwise-empty row.
### Documentation
- `SESSION_HANDOFF.md` refreshed twice this cycle — once
recording the HC paint + continuous-scrub polish, then
again as the Move Log arc shipped commit-by-commit. The
Resume menu's B option now traces the full arc:
notches → labels → footer → ESC → HC → arrow keys →
HC paint → continuous scrub → move log.
### Stats
- **1273 passing tests / 0 failing** across the workspace
(net +23 from v0.21.5's 1250 baseline):
- 2 from `d3cb1a5` (HC marker on track + notches).
- 2 from `2e25476` (continuous-scrub repeat-while-held +
release-resets-accumulator).
- 8 from `d6f32d3` (move-log panel init + 5 helpers + 3
spawn / lifecycle scenarios).
- 4 from `140251b` (prev rows: helper k coverage + spawn
cardinality + spawn texts + repaint on cursor advance).
- 3 from `e7345ae` (active row highlight: wrapper bg +
text colour + focus prefix + cursor=0 stays empty).
- 4 from `4437a1a` (next rows: helper k coverage + spawn
cardinality + spawn texts + under-fill at replay end).
- Clippy clean across the workspace.
## [0.21.5] — 2026-05-08 ## [0.21.5] — 2026-05-08
Patch release for the post-v0.21.4 work. One through-line: Patch release for the post-v0.21.4 work. One through-line:
+122 -235
View File
@@ -1,198 +1,101 @@
# Solitaire Quest — Session Handoff # Solitaire Quest — Session Handoff
**Last updated:** 2026-05-08 — **v0.21.4 cut and tagged at **Last updated:** 2026-05-08 — **v0.21.5 cut and tagged at
`23ff62c`**, working tree clean, all post-tag work pushed to `a2432df`**, working tree clean, all post-tag work pushed to
origin. origin.
v0.21.4 is a patch release with one through-line: v0.21.5 is a patch release with one through-line:
**replay-scrubbing accessibility**. The replay overlay used to be **replay-overlay scrubbing affordances + accessibility**.
pure-passive start, watch, wait. v0.21.4 adds the scaffolding v0.21.4 shipped pause / resume / step + the WIN MOVE marker as
for *navigating within* a replay: a WIN MOVE marker on the scrub the first scrubbing-shaped additions to the replay overlay;
bar so the player can see at a glance where the winning move v0.21.5 fills out the rest of the scrubbing UX so the player
sits, plus pause / resume / step controls (with a Space keyboard has both visual anchor points (notches + labels) and a complete
accelerator) so they can stop on any move and inspect the board. keyboard control surface (Space / Esc / ← / →) for navigating a
Also lands the additive `Replay::win_move_index: Option<usize>` paused replay.
data field that makes the marker possible — serde-default so
older on-disk replays load with `None` and simply don't get a
marker (no schema bump).
Three commits on the B-2 replay screen-takeover redesign arc Six commits on the B-2 replay screen-takeover redesign arc land
land here. The remaining sub-pieces (screen-takeover layout, here. Two of them are layout-changing — banner height grew
move-log scroller, mini-tableau preview) share a layout-reflow 60 → 76 → 92 px to make room for the notch labels and keybind
prerequisite the banner can't carry, so they're deferred to a footer. Banner geometry was fixed for every prior B-2 commit;
future cycle as a single multi-session arc. this release establishes the "grow the container, add a
flex-column child" pattern that the remaining B-2 sub-pieces
(move-log scroller, mini-tableau preview) will inherit when
they land.
Full v0.21.4 detail lives in `CHANGELOG.md` § [0.21.4]. This Full v0.21.5 detail lives in `CHANGELOG.md` § [0.21.5]. This
file from here on focuses on what's *open* post-cut and how to file from here on focuses on what's *open* post-cut and how to
resume. resume.
## Status at pause ## Status at pause
- **HEAD locally:** see `git rev-parse HEAD`. The cut commit is - **HEAD locally:** see `git rev-parse HEAD`. The cut commit is
`23ff62c`; any post-cut docs edits ride on top of that. `a2432df`; any post-cut docs edits ride on top of that.
- **HEAD on origin:** matches local. v0.21.4 is fully on origin. - **HEAD on origin:** matches local. v0.21.5 is fully on origin.
- **Working tree:** clean. No WIP outstanding. - **Working tree:** clean. No WIP outstanding.
- **`artwork/` directory:** still untracked. Intentional. - **`artwork/` directory:** still untracked. Intentional.
- **Build:** `cargo clippy --workspace --all-targets -- -D warnings` - **Build:** `cargo clippy --workspace --all-targets -- -D warnings`
clean. clean.
- **Tests:** **1250 total / 1249 passing / 1 pre-existing - **Tests:** **1254 passing / 0 failing** across the workspace
time-dependent flake** across the workspace (1250 in v0.21.5 + 2 from `d3cb1a5`'s HC-marker tests + 2
(1228 in v0.21.4 + 4 from `fe68861`'s scrub-notch tests + 4 from `2e25476`'s continuous-scrub tests). The
from `d322abf`'s notch-label tests + 4 from `1873b3f`'s time-dependent `daily_challenge` flake noted in v0.21.5's
keybind-footer tests + 3 from `90e24d9`'s ESC-accelerator CHANGELOG passes again (UTC clock has moved past the
tests + 1 from `23902cd`'s HC-marker test + 6 from trigger window). Detail in `CHANGELOG.md` § [0.21.5] § Stats
`e5c4f51`'s arrow-keyboard tests). The flake is for the v0.21.5 baseline; post-cut delta tracked in this
`daily_challenge_plugin::tests::check_system_fires_warning_event_only_once_per_day` file's Since-cut log.
— fails when wall-clock UTC is within 30 minutes of midnight - **Tags on origin:** `v0.9.0` through `v0.21.5`. v0.21.5 is on
(the daily-expiry warning window the test asserts against). `a2432df`; v0.21.4 stays on `23ff62c`; v0.21.3 stays on
Verified pre-existing. Detail in `CHANGELOG.md` § [0.21.4]
§ Stats; post-cut delta tracked here.
- **Tags on origin:** `v0.9.0` through `v0.21.4`. v0.21.4 is on
`23ff62c`; v0.21.3 stays on `3d92a91`; v0.21.2 stays on
`f23df3b`; v0.21.1 stays on `daa655a`; v0.21.0 stays on
`04f9bf9`; v0.20.0 stays on `41a009a`.
- **Tags on origin:** `v0.9.0` through `v0.21.3`. v0.21.3 is on
`3d92a91`; v0.21.2 stays on `f23df3b`; v0.21.1 stays on `3d92a91`; v0.21.2 stays on `f23df3b`; v0.21.1 stays on
`daa655a`; v0.21.0 stays on `04f9bf9`; v0.20.0 stays on `daa655a`; v0.21.0 stays on `04f9bf9`; v0.20.0 stays on
`41a009a`. `41a009a`.
## Since the v0.21.4 cut ## Since the v0.21.5 cut
- **`fe68861` — `feat(replay): add quarter-mark notches to scrub - **`d3cb1a5` — `feat(replay): HC-mode coverage for scrub
bar`.** First finite step toward B-2's screen-takeover layout. track + notches`.** Adds a parallel primitive to ui_theme
Five 1px vertical ticks at 0/25/50/75/100 % give the player (`HighContrastBackground` marker carrying `default_color`)
visual anchor points without needing to mentally bisect the and a paint system in settings_plugin
bar. Pure helper `scrub_notch_positions()` returns the fixed (`update_high_contrast_backgrounds`) that mirrors the
array; spawn loop lives next to the WIN MOVE marker spawn so existing border-marker pattern but targets `BackgroundColor`
the lifecycles match. Notches paint in `BORDER_SUBTLE` instead of `BorderColor`. Tags the 1 px scrub track Node and
(matches unfilled-track colour) and rely on extending past the all five quarter-mark notch ticks with the new marker so
1px track (5px tall, anchored 2px above track top) for they bump from `BORDER_SUBTLE` (#505050) → `BORDER_SUBTLE_HC`
visibility — same trick the WIN MOVE marker uses. Spawned (#a0a0a0) under HC mode. Scrub fill (ACCENT_PRIMARY) and
*after* the WIN MOVE marker so a notch and the marker landing WIN MOVE marker (STATE_SUCCESS) don't get the marker
on the same percentage paint the marker on top. Mirrors the accent and state colours are already saturated. 2 new tests;
notch ladder in `docs/ui-mockups/replay-overlay-mobile.html`. 1250 → 1252.
4 new tests; 1228 → 1232. - **`2e25476` — `feat(replay): continuous scrub on key-held
- **`d322abf` — `feat(replay): add percentage labels under arrow keys`.** Holding ← or → now triggers continuous step
scrub-bar notches`.** First **layout-changing** commit in B-2's at 100 ms cadence (10 steps/sec) — matches the mockup's
screen-takeover arc. Banner height grew from 60 → 76 px to make `[← →] scrub` terminology while keeping single-press =
room for a 16 px label row beneath the 1 px scrub track; the single-step semantics. Per-key accumulators in a new
top row's `flex_grow: 1.0` still consumes the same 59 px so no `ReplayScrubKeyHold` resource; `just_pressed` events bypass
ripples on existing content. Pure helper `scrub_notch_labels()` the accumulator and fire immediately. Release resets to 0
returns the fixed `["0%", "25%", "50%", "75%", "100%"]` array, so the next fresh press fires immediately rather than at
paired index-for-index with `scrub_notch_positions()`. Spawn half-interval. Footer text unchanged (`[← →] step`) —
loop applies an "endpoints flush, middle three percent-anchored" held-key scrub is a discoverable enhancement to the same
positioning pattern (Bevy 0.18 UI has no clean keybind, not a new keybind. 2 new tests using
`translate-x: -50%` primitive, so endpoints flush against `TimeUpdateStrategy::ManualDuration`; 1252 → 1254.
banner edges and middle three accept slight right-of-notch
offset). Label colour is `TEXT_SECONDARY` (mockup's
`BORDER_SUBTLE` reads as too low-contrast at 12 px against
`BG_ELEVATED_HI`). 4 new tests; 1232 → 1236.
- **`1873b3f` — `feat(replay): add keybind-hint footer to
overlay banner`.** Second layout-changing commit in B-2's arc.
Banner grew from 76 → 92 px to fit a 16 px footer row at the
bottom edge with a vim-style mode line on the left
(`▌ NORMAL │ replay`) and a keybind-hint on the right
(`[SPACE] pause/resume`). Surfaces the existing Space
accelerator visually so CLAUDE.md §3.3's UI-first contract
holds for keyboard accelerators too. Footer lists *only
wired* keybinds — future commits that wire ESC for stop or
← / → for prev/next will extend the right-hand text in
lockstep. Two pure helpers (`keybind_footer_mode_text`,
`keybind_footer_hint_text`) keep the static text testable;
shared `font_handle_for_labels` clone covers both label and
footer text spawns. 1px top border in `BORDER_SUBTLE`
separates the footer from the labels row. 4 new tests;
1236 → 1240.
- **`90e24d9` — `feat(replay): wire ESC accelerator for stop,
gate pause modal`.** ESC during an active replay now stops it
(mirrors the Stop button click). New `handle_stop_keyboard`
system in `replay_overlay.rs` parallels `handle_pause_keyboard`
in shape. Cross-plugin coordination via `pause_plugin::toggle_pause`:
added a fourth defer-if check
(`replay_state.is_some_and(|s| s.is_playing())`) right after
`other_modal_scrims` and before `selection`. Symmetric to the
existing modal-stack defer pattern. Footer hint extended from
`[SPACE] pause/resume``[SPACE] pause/resume · [ESC] stop`
in lockstep with the wiring; the only-wired-keybinds
discipline holds. 3 new tests + 1 updated helper-pin test;
1240 → 1243.
- **`23902cd` — `feat(replay): HC-mode coverage for
keybind-footer top border`.** Tag the footer's border-carrying
Node with `HighContrastBorder::with_default(BORDER_SUBTLE)` so
the existing `apply_high_contrast_borders` system bumps the
1 px top border from `#505050``#a0a0a0` under HC mode.
Footer text colours don't need bumps —
`TEXT_SECONDARY` (`#a0a0a0`) is already at `BORDER_SUBTLE_HC`
luminance by design (no `TEXT_SECONDARY_HC` constant exists).
The 1 px scrub track, notch ticks, and WIN MOVE marker render
via `BackgroundColor` (not `BorderColor`) so the marker
doesn't apply — HC coverage for those would need a
settings-aware paint system (precedent: `radial_rim_outline`
in `radial_menu`) and is deferred. 1 new test; 1243 → 1244.
- **`e5c4f51` — `feat(replay): wire ← / → keyboard accelerators
for paused stepping`.** New `step_backwards_replay_playback`
in `replay_playback.rs` decrements the cursor and dispatches
`UndoRequestEvent`; the game's `handle_undo` reads it next
frame to reverse its most-recent move — hooking the existing
undo system rather than replaying forward from cursor 0
(every replay-applied move pushes to the undo stack the same
way a player move would, so undo is the right reversal
primitive). Both arrow keys are paused-only via the same
destructure-gate pattern the forward step uses. Footer hint
extended in lockstep:
`[SPACE] pause/resume · [ESC] stop · [← →] step`. Footer
reads "step" not the mockup's "scrub" — single-move step is
what's wired; continuous scrub would need a key-held event
source. `ReplayOverlayPlugin` gains
`add_message::<UndoRequestEvent>()` defensively. 6 new tests
(2 hint pins + 4 keyboard scenarios) + 1 updated helper-pin
test; 1244 → 1250 total tests, 1249 passing.
**Pre-existing flake noted (verified):** Open next-step menu (B-2 keyboard accelerator coverage +
`daily_challenge_plugin::tests:: accessibility + scrub UX are all complete):
check_system_fires_warning_event_only_once_per_day` is 1. **Move-log scroller / mini-tableau preview** — both need
time-dependent — fails when wall-clock UTC is within 30 a much larger banner-height grow (effectively the takeover
minutes of midnight (the daily-expiry warning window the test container itself). Multi-session arcs that close B-2.
asserts against). Verified pre-existing by stashing all Mockup at `docs/ui-mockups/replay-overlay-mobile.html`.
changes and re-running before commit — failure persisted. Same 2. **Polish: notch label centering.** Bevy 0.18 lacks a clean
shape as the `winnable_seed_search` flake from earlier in the `translate-x: -50%` primitive so middle three labels sit
session. Will pass deterministically when UTC isn't in the slightly right-of-notch. Could use a child Text wrapper
warning window. Not introduced by recent work. with computed left-margin compensation. Tiny commit.
3. **Polish: WIN MOVE marker HC bump.** Currently the marker
uses `STATE_SUCCESS` lime which stays visible under HC,
but a slight saturation / contrast bump under HC would
make the marker even more legible alongside the bumped
notches. Optional.
Banner geometry is now mutable — every prior B-2 commit fit Recommended order: option 2 (notch label centering) is the
inside fixed 60 px space, but the notch-labels commit smallest concrete next-step. Option 1 is the multi-session
established the "grow the container, add a new flex-column arc that closes B-2 — natural place to start a fresh session.
child" precedent and the keybind-footer commit applied it
again. The next sub-pieces need significantly more vertical
room and follow the same shape.
Next finite step on B-2: keyboard accelerator coverage is now
complete (`Space` / `Esc` / `←` / `→`). Remaining choices:
1. **HC-mode coverage for the scrub-track / notch ticks /
WIN MOVE marker.** These render via `BackgroundColor` (not
`BorderColor`) so `HighContrastBorder` doesn't apply.
Pattern would mirror `radial_menu::radial_rim_outline`
per-frame paint reading `Settings::high_contrast_mode`.
Small commit, accessibility-progressing.
2. **Continuous scrub on key-held ← / →** instead of
single-move step. Needs a key-held event source (or
accumulator timer in the keyboard handler). Medium scope;
matches the mockup's `[← →] scrub` terminology.
3. **Move-log scroller / mini-tableau preview** — both need a
much larger banner-height grow (effectively the takeover
container itself). Bigger arcs; the natural place to land
the layout reflow that turns the banner into a takeover.
4. **Cut a v0.21.5 patch release** rolling up the four
post-cut commits (`fe68861`, `d322abf`, `1873b3f`,
`90e24d9`, `23902cd`, `e5c4f51`) under the through-line
"replay-overlay scrubbing affordances + accessibility."
Coherent narrative; six commits is a normal-sized patch
bundle for this project.
Recommended order: option 4 (cut release) is a clean next
boundary — six commits with a clear through-line is the right
size to bundle. Option 1 (HC paint for decorative pieces) is
the smallest next-feature commit if continuing past the cut.
## Open punch list ## Open punch list
@@ -233,30 +136,24 @@ palette refresh all shipped in v0.20.0 + v0.21.0. What stays open:
shipped in v0.21.2 (`2fb2d63`). The WIN MOVE scrub-bar marker shipped in v0.21.2 (`2fb2d63`). The WIN MOVE scrub-bar marker
shipped post-v0.21.3 in `ab857bb` (data field) + `52befa6` shipped post-v0.21.3 in `ab857bb` (data field) + `52befa6`
(UI). Playback controls (pause / resume / step + Space (UI). Playback controls (pause / resume / step + Space
accelerator) shipped post-v0.21.3 in `fbe48ac`. Quarter-mark accelerator) shipped post-v0.21.3 in `fbe48ac`. v0.21.5
scrub notches (5 ticks at 0/25/50/75/100 %) shipped bundled six more commits under "replay-overlay scrubbing
post-v0.21.4 in `fe68861` — first decoration step toward the affordances + accessibility" — scrub notches + percentage
takeover layout. Percentage labels under each notch shipped labels + keybind-hint footer + ESC and ← / → accelerators
post-v0.21.4 in `d322abf` — first **layout-changing** commit + HC marker for the footer top border. Banner height grew
(banner 60 → 76 px). Keybind-hint footer shipped in `1873b3f` 60 → 76 → 92 px across two layout-changing commits in
(banner 76 → 92 px — vim-style mode line + `[SPACE] v0.21.5; banner geometry is now mutable. Full per-commit
pause/resume`). ESC accelerator wiring (with cross-plugin detail in `CHANGELOG.md` § [0.21.5]. Keyboard accelerator
gate in `pause_plugin::toggle_pause`) shipped in `90e24d9`. coverage is complete. What still needs to land: HC-mode
HC-mode coverage for the footer's top border shipped in coverage for the scrub-track / notches / WIN MOVE marker
`23902cd`. ← / → keyboard accelerators for paused stepping (they render via `BackgroundColor` so the
shipped in `e5c4f51` (hooks the existing undo system for `HighContrastBorder` marker doesn't apply — needs a
backwards step; footer extended to settings-aware paint), continuous scrub on key-held ← / →
`[SPACE] pause/resume · [ESC] stop · [← →] step`). Banner (vs single-step), then the bigger pieces — a move-log
geometry is mutable; keyboard accelerator coverage is scroller and a mini-tableau preview — both screen-
complete. What still needs to land: HC-mode coverage for takeover-only pieces that need a much larger banner height
the scrub-track / notches / WIN MOVE marker (they render grow (effectively the takeover container itself).
via `BackgroundColor` so the `HighContrastBorder` marker Multi-session.
doesn't apply — needs a settings-aware paint), continuous
scrub on key-held ← / → (vs single-step), then the bigger
pieces — a move-log scroller and a mini-tableau preview —
both screen-takeover-only pieces that need a much larger
banner height grow (effectively the takeover container
itself). Multi-session.
- *Floating `MOVE N/M` chip above the focused card during - *Floating `MOVE N/M` chip above the focused card during
playback — closed 2026-05-08 by `2fb2d63`.* World-space playback — closed 2026-05-08 by `2fb2d63`.* World-space
`Text2d` entity sibling to the banner overlay; uses the same `Text2d` entity sibling to the banner overlay; uses the same
@@ -399,27 +296,25 @@ into a v0.21.1 / v0.22.0 cut.
``` ```
You are a senior Rust + Bevy developer working on Solitaire Quest. You are a senior Rust + Bevy developer working on Solitaire Quest.
Working directory: <Rusty_Solitaire clone path on this machine>. Working directory: <Rusty_Solitaire clone path on this machine>.
Branch: master. v0.21.4 is tagged at 23ff62c (cut 2026-05-08, a Branch: master. v0.21.5 is tagged at a2432df (cut 2026-05-08, a
patch release rolling up replay-scrubbing accessibility: WIN MOVE patch release rolling up replay-overlay scrubbing affordances +
marker on the scrub bar, pause / resume / step playback controls accessibility: scrub-bar notches with percentage labels, keybind-
with a Space keyboard accelerator, and the additive hint footer, ESC + ← / → keyboard accelerators, and HC-mode
`Replay::win_move_index: Option<usize>` data field that makes the coverage for the footer top border). v0.21.4 stays at 23ff62c,
marker possible). v0.21.3 stays at 3d92a91, v0.21.2 at f23df3b, v0.21.3 at 3d92a91, v0.21.2 at f23df3b, v0.21.1 at daa655a,
v0.21.1 at daa655a, v0.21.0 at 04f9bf9. Working tree clean. See v0.21.0 at 04f9bf9. Working tree clean. See CHANGELOG.md §
CHANGELOG.md § [0.21.4] for full detail. [0.21.5] for full detail.
State: HEAD locally — see `git rev-parse HEAD`. Post-cut HEAD is State: HEAD locally — see `git rev-parse HEAD`. The cut commit
`e5c4f51` (six carved-out commits on top of v0.21.4 — scrub-bar is a2432df; any post-cut docs edits ride on top of that.
notches `fe68861`, notch labels `d322abf`, keybind-hint footer Workspace tests: 1250 total / 1249 passing / 1 pre-existing
`1873b3f`, ESC accelerator + pause-modal gate `90e24d9`, HC time-dependent flake (`daily_challenge` warning, fails when UTC
marker for footer border `23902cd`, ← / → keyboard accelerators is within 30 min of midnight; verified not introduced by recent
`e5c4f51`). Workspace tests: 1250 total / 1249 passing / 1 work). Clippy clean.
pre-existing time-dependent flake (clock-near-midnight; verified
not introduced by recent work). Clippy clean.
READ FIRST (in order, before doing anything): READ FIRST (in order, before doing anything):
1. SESSION_HANDOFF.md — this file 1. SESSION_HANDOFF.md — this file
2. CHANGELOG.md — [0.21.4] section is the most recent cut 2. CHANGELOG.md — [0.21.5] section is the most recent cut
3. CLAUDE.md — unified-3.0 rule set 3. CLAUDE.md — unified-3.0 rule set
4. CLAUDE_SPEC.md — formal architecture spec 4. CLAUDE_SPEC.md — formal architecture spec
5. ARCHITECTURE.md — crate responsibilities + data flow 5. ARCHITECTURE.md — crate responsibilities + data flow
@@ -440,33 +335,25 @@ DECISION TO ASK THE PLAYER FIRST:
and Android Keystore stubs that need real bridges. Larger and Android Keystore stubs that need real bridges. Larger
scope; needs an Android device or emulator running. scope; needs an Android device or emulator running.
B. Replay-overlay screen-takeover redesign — multi-session B. Replay-overlay screen-takeover redesign — multi-session
work. Three sub-pieces shipped in v0.21.4: WIN MOVE work. v0.21.4 shipped WIN MOVE marker, pause / resume /
marker (data field + UI) and pause / step / Space step + Space accelerator, plus the floating-MOVE-chip
playback controls. The smaller floating-MOVE-chip piece piece from v0.21.2 (`2fb2d63`). v0.21.5 shipped scrub
shipped in v0.21.2 (`2fb2d63`). Post-v0.21.4: scrub notches + percentage labels + keybind-hint footer + ESC
notches `fe68861`, notch labels `d322abf` (banner and ← / → accelerators + HC marker for the footer top
60 → 76 px), keybind-hint footer `1873b3f` (banner border (six commits across CHANGELOG § [0.21.5]). Banner
76 → 92 px), ESC accelerator + cross-plugin gate height grew 60 → 76 → 92 px across two layout-changing
`90e24d9`, HC-mode coverage for the footer top border commits in v0.21.5; geometry is now mutable. Keyboard
`23902cd`, and ← / → keyboard accelerators for paused accelerator coverage is complete. Natural next finite
stepping `e5c4f51` (hooks the game's undo system for steps:
backwards step; footer extended to 1. **HC-mode coverage** for the scrub-track / notches /
`[SPACE] pause/resume · [ESC] stop · [← →] step`).
Keyboard accelerator coverage is complete. Natural next
finite steps:
1. **Cut a v0.21.5 patch release** rolling up the six
post-cut commits under "replay-overlay scrubbing
affordances + accessibility." Coherent narrative;
clean release boundary.
2. **HC-mode coverage** for the scrub-track / notches /
WIN MOVE marker (render via `BackgroundColor` not WIN MOVE marker (render via `BackgroundColor` not
`BorderColor`, so `HighContrastBorder` doesn't apply `BorderColor`, so `HighContrastBorder` doesn't apply
— needs a settings-aware paint, precedent — needs a settings-aware paint, precedent
`radial_rim_outline`). Small commit. `radial_rim_outline`). Smallest next commit.
3. **Continuous scrub on key-held ← / →** instead of 2. **Continuous scrub on key-held ← / →** instead of
single-step. Needs a key-held event source. Matches single-step. Needs a key-held event source. Matches
the mockup's `[← →] scrub` terminology. the mockup's `[← →] scrub` terminology.
4. **Move-log scroller / mini-tableau preview** — both 3. **Move-log scroller / mini-tableau preview** — both
need a much larger banner-height grow (effectively need a much larger banner-height grow (effectively
the takeover container itself). Multi-session arcs the takeover container itself). Multi-session arcs
that close B-2. that close B-2.
File diff suppressed because it is too large Load Diff
+38 -1
View File
@@ -34,7 +34,8 @@ use crate::ui_modal::{
}; };
use crate::ui_tooltip::Tooltip; use crate::ui_tooltip::Tooltip;
use crate::ui_theme::{ use crate::ui_theme::{
BG_BASE, BG_ELEVATED, BG_ELEVATED_HI, BORDER_SUBTLE, BORDER_SUBTLE_HC, HighContrastBorder, BG_BASE, BG_ELEVATED, BG_ELEVATED_HI, BORDER_SUBTLE, BORDER_SUBTLE_HC, HighContrastBackground,
HighContrastBorder,
RADIUS_SM, SPACE_2, STATE_SUCCESS, TEXT_PRIMARY, TEXT_SECONDARY, TYPE_BODY, TYPE_BODY_LG, RADIUS_SM, SPACE_2, STATE_SUCCESS, TEXT_PRIMARY, TEXT_SECONDARY, TYPE_BODY, TYPE_BODY_LG,
TYPE_CAPTION, VAL_SPACE_2, VAL_SPACE_3, Z_MODAL_PANEL, TYPE_CAPTION, VAL_SPACE_2, VAL_SPACE_3, Z_MODAL_PANEL,
}; };
@@ -365,6 +366,7 @@ impl Plugin for SettingsPlugin {
update_color_blind_text, update_color_blind_text,
update_high_contrast_text, update_high_contrast_text,
update_high_contrast_borders, update_high_contrast_borders,
update_high_contrast_backgrounds,
update_reduce_motion_text, update_reduce_motion_text,
update_tooltip_delay_text, update_tooltip_delay_text,
update_time_bonus_multiplier_text, update_time_bonus_multiplier_text,
@@ -674,6 +676,41 @@ fn update_high_contrast_borders(
} }
} }
/// Repaints `BackgroundColor` on every entity tagged with
/// [`HighContrastBackground`] based on `Settings::high_contrast_mode`.
/// Off → the marker's `default_color`; on → `BORDER_SUBTLE_HC`
/// (`#a0a0a0`). Compares against the current background and only
/// mutates when different so Bevy's change-detection doesn't trigger
/// repaints every frame.
///
/// Parallel to [`update_high_contrast_borders`]. Same on/off rule,
/// same change-suppression idiom, different colour channel —
/// `BackgroundColor` for tick marks, decorative strips, fine
/// separators that paint their shape directly rather than via a
/// `BorderColor` on a wider Node.
///
/// Tagged sites in v0.21.x: the replay overlay's 1 px scrub track
/// + 5 quarter-mark notch ticks (`replay_overlay::spawn_overlay`).
///
/// More sites can be tagged in follow-ups by adding
/// `HighContrastBackground::with_default(...)` to their spawn tuple.
pub(crate) fn update_high_contrast_backgrounds(
settings: Res<SettingsResource>,
mut backgrounds: Query<(&HighContrastBackground, &mut BackgroundColor)>,
) {
let high_contrast = settings.0.high_contrast_mode;
for (marker, mut bg) in backgrounds.iter_mut() {
let target = if high_contrast {
BORDER_SUBTLE_HC
} else {
marker.default_color
};
if bg.0 != target {
*bg = BackgroundColor(target);
}
}
}
fn update_reduce_motion_text( fn update_reduce_motion_text(
settings: Res<SettingsResource>, settings: Res<SettingsResource>,
mut text_nodes: Query<&mut Text, With<ReduceMotionText>>, mut text_nodes: Query<&mut Text, With<ReduceMotionText>>,
+29
View File
@@ -252,6 +252,35 @@ impl HighContrastBorder {
} }
} }
/// Marker for entities whose [`BackgroundColor`] should swap to
/// [`BORDER_SUBTLE_HC`] when `Settings::high_contrast_mode` is on.
/// Parallel to [`HighContrastBorder`] but for sites that paint their
/// shape via `BackgroundColor` rather than `BorderColor` —
/// `bevy::ui` 1 px decorative strips, tick marks, fine separators
/// often render as tiny full-bleed `Node`s, not as borders, so the
/// border-marker pattern doesn't apply.
///
/// `default_color` records the off-state colour the entity was
/// spawned with so the system can revert when HC is toggled back
/// off. The accompanying paint system is
/// [`update_high_contrast_backgrounds`](crate::settings_plugin::update_high_contrast_backgrounds).
///
/// [`BackgroundColor`]: bevy::prelude::BackgroundColor
#[derive(bevy::prelude::Component, Debug, Clone, Copy)]
pub struct HighContrastBackground {
/// Background colour to use when high-contrast mode is *off* —
/// the site's normal idle / active-state colour.
pub default_color: bevy::prelude::Color,
}
impl HighContrastBackground {
/// Convenience constructor —
/// `HighContrastBackground::with_default(BORDER_SUBTLE)`.
pub const fn with_default(default_color: bevy::prelude::Color) -> Self {
Self { default_color }
}
}
/// Strong border — hover outline, focused button, active popover. /// Strong border — hover outline, focused button, active popover.
/// `outline` from the design system. `#505050`. /// `outline` from the design system. `#505050`.
pub const BORDER_STRONG: Color = Color::srgba(0.314, 0.314, 0.314, 1.0); pub const BORDER_STRONG: Color = Color::srgba(0.314, 0.314, 0.314, 1.0);