feat(offer): sort and align the §4.4 price tables, style them for both themes
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 20s
CI / ui (pull_request) Successful in 1m10s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m47s

- packs sorted by ascending rouble price;
- values grouped hints-only -> no-ads-only -> no-ads+hints -> tournament
  (the tournament group is empty until such products become sellable),
  ascending chip price within each group;
- price columns right-aligned (GFM "---:" separators);
- tables span the full content width; the name column shrinks to its content
  and never wraps;
- muted-but-visible cell borders on the dark theme, where the section rule
  colour blends into the background.
This commit is contained in:
Ilia Denisov
2026-07-11 11:28:56 +02:00
parent b54371845f
commit 40acbcccdd
4 changed files with 171 additions and 25 deletions
+6 -1
View File
@@ -918,7 +918,12 @@ fetches the two catalog tables as markdown from the backend's internal
backend projects the tables from the active catalog through `payments.Money` (no float reaches the
page) and caches them in memory — built at boot, reprojected on any catalog edit — so a served
render issues no query in the steady state and the page always reflects the current catalog without
a redeploy. A backend outage degrades `/offer/` to a 502 rather than a stale price list.
a redeploy. A backend outage degrades `/offer/` to a 502 rather than a stale price list. Packs are
ordered by ascending rouble price; values are grouped by what they grant — hints only, then no-ads
only, then no-ads + hints, then (reserved, empty today) products carrying the **tournament** atom,
which becomes a fourth group once the tournament economy makes them sellable — and ordered by
ascending chip price within each group. Product titles are admin input, so the projection escapes
them (HTML entities + markdown metacharacters) before they reach the un-sanitised renderer.
The alphabet-on-the-wire transport does **not** touch this invariant: the live edge
exchanges alphabet indices, but the persisted journal (and everything derived from it —