diff --git a/AGENTS.md b/AGENTS.md
index 4f5a972..5ddc676 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -387,10 +387,11 @@ Sources are community wikis. Treat them as a guest would:
with `--only`: forcing twenty sources to re-ask a question they answered an hour ago is the
behaviour this bullet exists to prevent, whatever flag authorised it. The run names every source it
asked early, and a run that was due anyway is never reported as forced.
-- **Space requests to one host**, honouring its `Crawl-delay` and defaulting to 2s. Nine of the
- twenty sources are game8.co pages, so the per-source floor alone still permits one cycle to arrive
- as nine back-to-back requests to a single site — which is the shape an edge network throttles, and
- what a burst looks like from the far end regardless of our intent.
+- **Space requests to one host**, honouring its `Crawl-delay` and defaulting to 2s. Nine event
+ sources and nine redeem-code sources (2026-10-18) are game8.co pages, so the per-source floor alone
+ still permits one cycle to arrive as eighteen back-to-back requests to a single site — which is
+ the shape an edge network throttles, and what a burst looks like from the far end regardless of
+ our intent.
- Send `If-None-Match` / `If-Modified-Since`; treat `304` as "skip, unchanged".
- Cache raw snapshots so re-parsing never re-fetches. **Iterate against fixtures, not the network.**
- Record `sourceUrl` on every event and surface attribution in the UI.
diff --git a/TODO.md b/TODO.md
index d5804be..cd6750d 100644
--- a/TODO.md
+++ b/TODO.md
@@ -266,3 +266,14 @@ note only says where to start.
readers could reach the ~5 MB quota. Failures are reported, not silent.
- After a rollback, anything done in the new build lives only in v2 and isn't shown by the old app.
It's stranded, not lost.
+- [ ] Get readers to try the layout choices, not just be told about them (owner, 2026-10-18).
+ - Relaxed vs Structured, and the Timeline's new vs classic look. Each is one switch in
+ Settings → Appearance today, which most readers will never open.
+ - Show the difference live, on the reader's own events: a "try it" that switches the page in place,
+ with an easy way back, rather than a description or a static picture.
+ - Aim this especially at returning readers, who arrive on the default (Structured, new Timeline)
+ without having chosen it.
+ - Offer it even to readers who have already done or skipped the returning-user tour (the tour
+ records `redesignTourSeen`; this needs its own "seen" so it isn't swallowed by that).
+ - Open questions: where it appears (a one-time card on the Checklist and Timeline? a tour step?), and
+ whether trying a look saves it or only previews it until confirmed.
diff --git a/docs/INGESTION.md b/docs/INGESTION.md
index cae93a6..aef3fa8 100644
--- a/docs/INGESTION.md
+++ b/docs/INGESTION.md
@@ -659,3 +659,38 @@ Event adapter schemas are unchanged. scripts/build-codes.ts builds data/codes.v1
snapshots or fixtures and preserves observation timestamps in snapshots/codes-first-seen.json.
Code newness is per game; redemption is per local game/server account and never clears newness by
itself. No code row is synthesized into the event feed.
+
+## Redeem codes for eight more games (2026-10-18)
+
+Codes now come from Game8 for Star Rail (archives/410296), ZZZ (435683), Wuthering Waves (453149),
+Endfield (571509), NTE (593718), P5X (531770), Chaos Zero Nightmare (557967) and Umamusume (536130),
+beside Genshin.
+- **Capture.** game8.co's robots.txt has no rule for our User-Agent or these paths. Each page was
+ fetched exactly once with the refresh User-Agent, 2s apart, all HTTP 200, and pinned as
+ `fixtures//game8-codes-2026-10-18.*`.
+- **Parser.** The pages share Game8's copy-input markup but not their headings or columns.
+ `parseGame8CodeTable` reads the section under each page's own "active codes" heading
+ (`src/ingest/codes/registry.ts`), skips any table there that says its codes have expired
+ (Wuthering Waves keeps one at the top), and reads the reward from the other cells, or from the
+ code's own cell when they share one (Wuthering Waves, P5X).
+- **Expiry stays null.** The pages print "Expires TBA" or a date range without a year, and a guessed
+ year would be a fabricated date.
+- **Umamusume.** The page currently states "No Publicly Released Codes Yet", which is what lets its
+ empty read be stored (`statesNoEvents`). A changed page still fails the gate.
+- **Spot-checked against the live pages:** Star Rail's six codes, WUTHERINGGIFT, Endfield's
+ ENDFIELDSTEAM / ENDFIELDGIFT / ENDFIELD4PC, CZN's NIGHTMARECARNIVAL and P5X's WEBSTORE1YEAR.
+
+**Infinity Nikki is not added.** Game8 stopped updating its Nikki guides and the codes page is still
+titled "All Infinity Nikki Codes (July 2025)", so its twelve "active" codes cannot be presented as
+current. The other games (Arknights, Blue Archive, FGO, hololive Dreams, GFL2, Stella Sora, Nikke,
+Honkai Impact 3rd, PGR, Reverse: 1999) have no Game8 codes page. Searches found only general blogs,
+which are not assessed yet.
+
+**Where to redeem** (`src/shared/redeem.ts`). Each game with a codes source shows its in-game route,
+taken from its Game8 page's "How to redeem" section. An official web page gets a button only when the
+page links one on the publisher's domain. Today that is Genshin, Star Rail and ZZZ on hoyoverse.com.
+Chaos Zero Nightmare names an official coupon page without linking it, and no URL could be confirmed,
+so it shows the in-game route only.
+
+**Refreshing.** These are game8 pages, so the CI caveat in AGENTS.md § Scraping conduct applies: if the
+runner is refused, they refresh by hand like the event pages.
diff --git a/docs/SOURCES.md b/docs/SOURCES.md
index 808c5ed..3ea4957 100644
--- a/docs/SOURCES.md
+++ b/docs/SOURCES.md
@@ -995,3 +995,38 @@ Event adapter schemas are unchanged. scripts/build-codes.ts builds data/codes.v1
snapshots or fixtures and preserves observation timestamps in snapshots/codes-first-seen.json.
Code newness is per game; redemption is per local game/server account and never clears newness by
itself. No code row is synthesized into the event feed.
+
+## Redeem codes for eight more games (2026-10-18)
+
+Codes now come from Game8 for Star Rail (archives/410296), ZZZ (435683), Wuthering Waves (453149),
+Endfield (571509), NTE (593718), P5X (531770), Chaos Zero Nightmare (557967) and Umamusume (536130),
+beside Genshin.
+- **Capture.** game8.co's robots.txt has no rule for our User-Agent or these paths. Each page was
+ fetched exactly once with the refresh User-Agent, 2s apart, all HTTP 200, and pinned as
+ `fixtures//game8-codes-2026-10-18.*`.
+- **Parser.** The pages share Game8's copy-input markup but not their headings or columns.
+ `parseGame8CodeTable` reads the section under each page's own "active codes" heading
+ (`src/ingest/codes/registry.ts`), skips any table there that says its codes have expired
+ (Wuthering Waves keeps one at the top), and reads the reward from the other cells, or from the
+ code's own cell when they share one (Wuthering Waves, P5X).
+- **Expiry stays null.** The pages print "Expires TBA" or a date range without a year, and a guessed
+ year would be a fabricated date.
+- **Umamusume.** The page currently states "No Publicly Released Codes Yet", which is what lets its
+ empty read be stored (`statesNoEvents`). A changed page still fails the gate.
+- **Spot-checked against the live pages:** Star Rail's six codes, WUTHERINGGIFT, Endfield's
+ ENDFIELDSTEAM / ENDFIELDGIFT / ENDFIELD4PC, CZN's NIGHTMARECARNIVAL and P5X's WEBSTORE1YEAR.
+
+**Infinity Nikki is not added.** Game8 stopped updating its Nikki guides and the codes page is still
+titled "All Infinity Nikki Codes (July 2025)", so its twelve "active" codes cannot be presented as
+current. The other games (Arknights, Blue Archive, FGO, hololive Dreams, GFL2, Stella Sora, Nikke,
+Honkai Impact 3rd, PGR, Reverse: 1999) have no Game8 codes page. Searches found only general blogs,
+which are not assessed yet.
+
+**Where to redeem** (`src/shared/redeem.ts`). Each game with a codes source shows its in-game route,
+taken from its Game8 page's "How to redeem" section. An official web page gets a button only when the
+page links one on the publisher's domain. Today that is Genshin, Star Rail and ZZZ on hoyoverse.com.
+Chaos Zero Nightmare names an official coupon page without linking it, and no URL could be confirmed,
+so it shows the in-game route only.
+
+**Refreshing.** These are game8 pages, so the CI caveat in AGENTS.md § Scraping conduct applies: if the
+runner is refused, they refresh by hand like the event pages.
diff --git a/docs/handoffs/2026-10-17-redesign-second-rejection-handoff.md b/docs/handoffs/2026-10-17-redesign-second-rejection-handoff.md
index b72c360..5172127 100644
--- a/docs/handoffs/2026-10-17-redesign-second-rejection-handoff.md
+++ b/docs/handoffs/2026-10-17-redesign-second-rejection-handoff.md
@@ -924,3 +924,17 @@ committing:
The owner chose to commit and push, including `design/`, the redesign docs, `docs/design-reviews/` and
`.superpowers/`. The changelog entry and note follow in their own commit, because they must name the
redesign commit.
+
+### After shipping: Settings width, redeem links, more code sources (2026-10-18)
+
+- **Settings on large screens.** Content was capped at 900px (760px on game, backup and data pages),
+ and the menu's rule stopped partway down. Content now uses up to 1320px; the changelog keeps its
+ reading column. The menu runs the full height.
+- **Codes tab.** It gains "Redeem on the official site ↗" where the publisher has a web page (Genshin,
+ Star Rail, ZZZ), and the in-game route for every game with codes (`src/shared/redeem.ts`).
+ A redeemed checkbox names the server only when there is more than one.
+- **Code sources.** Eight more games come from Game8: `parseGame8CodeTable`, with fixtures, expected
+ files and tests. Infinity Nikki is skipped because its page is stale, and ten games have no Game8
+ page. See docs/SOURCES.md § Redeem codes for eight more games.
+- **Owner's TODO:** let readers try Relaxed/Structured and the new/classic Timeline live, including
+ returning readers who've done the tour.
diff --git a/fixtures/czn/game8-codes-2026-10-18.expected.json b/fixtures/czn/game8-codes-2026-10-18.expected.json
new file mode 100644
index 0000000..44a5ad5
--- /dev/null
+++ b/fixtures/czn/game8-codes-2026-10-18.expected.json
@@ -0,0 +1,42 @@
+[
+ {
+ "id": "[\"czn\",\"NIGHTMARECARNIVAL\"]",
+ "game": "czn",
+ "code": "NIGHTMARECARNIVAL",
+ "reward": "Crystals x1,000",
+ "expiresAt": null,
+ "sourceUrl": "https://game8.co/games/Chaos-Zero-Nightmare/archives/557967"
+ },
+ {
+ "id": "[\"czn\",\"CZNNEWPDGIFT3RD\"]",
+ "game": "czn",
+ "code": "CZNNEWPDGIFT3RD",
+ "reward": "Signal Amplification Anchor x10",
+ "expiresAt": null,
+ "sourceUrl": "https://game8.co/games/Chaos-Zero-Nightmare/archives/557967"
+ },
+ {
+ "id": "[\"czn\",\"CZNNEWPDGIFT2ND\"]",
+ "game": "czn",
+ "code": "CZNNEWPDGIFT2ND",
+ "reward": "Signal Amplification Anchor x10",
+ "expiresAt": null,
+ "sourceUrl": "https://game8.co/games/Chaos-Zero-Nightmare/archives/557967"
+ },
+ {
+ "id": "[\"czn\",\"CZNNEWPDGIFT1ST\"]",
+ "game": "czn",
+ "code": "CZNNEWPDGIFT1ST",
+ "reward": "Signal Amplification Anchor x10",
+ "expiresAt": null,
+ "sourceUrl": "https://game8.co/games/Chaos-Zero-Nightmare/archives/557967"
+ },
+ {
+ "id": "[\"czn\",\"epicwithczn\"]",
+ "game": "czn",
+ "code": "epicwithczn",
+ "reward": "Rescue Anchor x3 Unit x300,000",
+ "expiresAt": null,
+ "sourceUrl": "https://game8.co/games/Chaos-Zero-Nightmare/archives/557967"
+ }
+]
diff --git a/fixtures/czn/game8-codes-2026-10-18.html b/fixtures/czn/game8-codes-2026-10-18.html
new file mode 100644
index 0000000..3ee32cb
--- /dev/null
+++ b/fixtures/czn/game8-codes-2026-10-18.html
@@ -0,0 +1,1160 @@
+All Codes and How to Redeem (October 2026) | Chaos Zero Nightmare (CZN)|Game8
+
+
+
+
+
+
+
+
+
Here's a list of all the current and active Chaos Zero Nightmare (CZN) coupons and redeem codes as of October 2026! Check out this list of coupons and redeem codes and learn how to redeem them in-game.
+
+ Tap the Menu icon (three horizontal lines) in the top-right corner.
+
+
+
+
2
+
+
+
+
+
+ Click the Settings option, represented by the gear icon.
+
+
+
+
3
+
+
+
+
+
+ Scroll down to Account Settings at the bottom of the left-hand menu, then click Register Coupon and enter your coupon code.
+
+
+
+
Redeem Coupons on Official Website
+
You can also enter your coupon code on the Chaos Nightmare Zero's Coupon Redemption Page to claim your rewards.
+
+
+
+
Chaos Zero Nightmare Coupons Notes
+
+
+
+ ・Coupon rewards are delivered to the selected character’s in-game mailbox.
+ ・Coupon rewards will be stored for 30 days after registration, so please make sure to claim them within that period.
+ ・Expired coupons cannot be used.
+ ・Coupons that have already been redeemed cannot be used.
+ ・Some coupons may be restricted to specific servers.
+ ・The number of uses and validity period may vary depending on the coupon.
+ ・Coupons obtained through STOVE promotions must be redeemed in the [STOVE Coupon Storage]
+
+
+
+
What are Redeem Codes in Chaos Zero Nightmare?
Special Bonuses and Rewards
+
Redeem codes in Chaos Zero Nightmare are special codes that players can enter to receive in-game rewards, such as currency or other bonuses. These codes are typically released during events, promotions, or updates to give players a head start or extra perks.
+
+
This page will be updated once more information about redeem codes and their rewards becomes available.
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
Arknights: Endfield currently has four active codes available. ENDFIELDGIFT is available for all platforms while ENDFIELD4PC is limited only to PC users and can only be redeemed there.
+
+
+
+
Game8 tip: sign in and use under the page title to get new code updates!
The following codes have already expired and cannot be redeemed anymore. Trying to enter these codes in the redemption screen will only cause them to fail and not redeem.
+
How to Redeem Codes in Arknights: Endfield
Use the Exchange Code feature found in the in-game Settings
+
You can only redeem codes in-game, after completing the tutorial and unlocking the Mail system, which is unlocked during the Break the Siege Main Mission.
+
+
+
Launch the game and load your save (Codes cannot be redeemed at the login screen).
+
Open the Menu via the ESC button (PC) or Options button (PS5).
+
Select the Settings icon on the top left of the screen.
+
Go to the "Platform & Account" tab
+
Select "Exchange Code".
+
Input a valid code from the list above and press Confirm to redeem it.
+
Go back to the Menu, and then open the Mail icon
+
Find the mail in your inbox and Claim All to obtain the rewards.
+
+
Can Only Be Redeemed In-Game
+
As there is currently no redemption portal on the official website, codes must be redeemed in-game.
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
Here are all the active Honkai: Star Rail Codes for October 2026, including the limited-time codes. Check out this list of Star Rail codes and how to redeem them for free Stellar Jades!
There are currently 6 Honkai: Star Rail codes available for October 2026. Use the Redeem Codes above to receive Stellar Jades and get more pulls for Characters and Light Cones!
Players can redeem codes on the game's official redemption website. Just log in with your HoYoverse account and enter your server, character name, and valid redeem code to claim the free rewards.
+
+
Note that for IOS users, using the website is the only way to redeem codes!
Go back to ''More'' and claim rewards from the Mail
+
Return to the Menu then click on the Mail Icon
+
Click the Claim All button to get the rewards.
+
+
+
It is also possible to redeem codes in-game by opening the Menu, then tapping on the ellipsis in the top right corner. Select the Redemption Code option and enter the codes.
+
+
Note that the Redemption Code button will not show up on the IOS version of the game!
+
How to Reedem Codes on Mobile
+
+
+
+
Tap the Phone Icon to bring up the menu
+
Tap on the ''ellipsis'' icon
+
Tap on the ''Redemption Code'' button
+
Input your Redeem Code and tap ''Redeem''
+
Return to the Menu then tap on the Mail Icon
+
Tap on the Claim All button to get the rewards.
+
+
+
Players on Mobile can open the Menu by pressing the Phone icon at the top left of the screen, near the mini-map. Then, tap the ellipsis at the top right as mentioned previously to open the Redemption Code function!
Here is a list of all the latest Honkai: Star Rail redeem codes that were shown in the recent 4.6 Livestream! The 4.6 Livestream redeem codes expire on September 21, 2026 at 10:59 AM (UTC-5).
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
These are the current active redeem codes in Neverness to Everness (NTE) in October 2026. See all active redeem codes, all expired codes, and how to redeem codes for free NTE rewards!
The following codes have already expired and cannot be redeemed anymore. Trying to enter these codes in the redemption screen will only cause them to fail and not redeem.
+
How to Redeem Codes
Redeem From the In-Game Menu
+
+
+
Codes can be entered into the Redeem Code option in the game's main menu.
+
+
+
Log into the game.
+
Tap Menu in the top right-hand corner of the screen.
+
Tap the [...] button.
+
Select Redeem Code.
+
Enter the code.
+
+
Can Only Be Redeemed In-Game
+
As there is currently no redemption portal on the official website, codes must be redeemed in-game.
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
Here are the list of codes for September 2026 in Persona 5: The Phantom X (P5X). Learn how to redeem codes and find out how to claim the rewards on this guide!
Input the following codes to receive special rewards! Do take note that some Redeem Codes are time-sensitive, and may not work after certain conditions have passed.
+
How to Redeem Codes
Select the In-Game Exchange Code in the Menu
+
+
+
Open the menu and select the Exchange Code from the options. Type or paste the code onto the text field and then select "OK" to redeem the code and get the free rewards.
+
Go to the Official Shop Website
+
+
+
Alternatively, players can go to the official top-up shop website of Persona 5: The Phantom X to use the Redeem Gift Codes there!
+
+
More details of this will be available once the website and code goes live!
+
How to Claim Code Rewards
Check the In-Game Mail
+
All redeem code rewards will go through your mail. Your mail should become available before you can even unlock the code exchange in-game.
Check the conditions for each code, like the limit and deadline for them. You won't be able to redeem the codes and get the rewards if the conditions are not met.
+
Redeem Codes Can Only Be Used Once
+
All codes can only be used once and won't be able to work once you redeem them. It means you won't get the rewards over and over again.
+
Some Redeem Codes Have Limits
+
Some of the redeem codes may have limit on them. It may be a time limit where you can only redeem it for a limited time or a redemption limit where a certain number of redeemers may only get them.
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
Here are all active codes in Wuthering Waves as of October 2026 during Version 3.7. Check out this list of the newest redeem codes including livestream codes, learn if there is a code redeem site, as well as how to use them for free Astrite, and other WuWa gifts in this guide.
+
+
+
+
Attention!
+
This page will be updated as soon as new redeem code information is available!
Sign in and select under the page's title to be notified of any updates!
STARRYSTAGE2 and KEEPONSHINING were the two redeem codes announced during the Solaris Starry Stage livestream of Wuthering Waves! Unfortunately, the codes have expired since October 13, 2026 at 08:59AM UTC-7 so hopefully you claimed it in time!
+
+
+## List of All Active Redeem Codes
+
+
+### Starter Redeem Code
+
+
WUTHERINGGIFT - 50 Astrite, 2 Premium Resonance Potions, 2 Medium Revival Inhalers, 2 Medium Energy Bags, 15000 Shell Credits
+
+
+
So far, WUTHERINGGIFT code is the only permanently active code for Wuthering Waves. However, Kuro Games is known to host livestreams before a new Version update that gives away three livestream codes so keep an eye out for that!
+
How to Redeem Wuthering Waves Codes
Use the Redeem Function Found in the Game Settings
+
+
+
+
Open the settings and go to "Other Settings"
+
Use the "Redemption Code" feature
+
Enter your redeem code and confirm
+
Open your mailbox to claim the rewards
+
+
+
Go to Wuthering Waves' "Other Settings", type in your active redeem code, and confirm. A pop-up will appear to let you know if your code was claimed successfully. The rewards will then be sent over to your in-game mailbox.
+
Claim the Code Rewards Immediately
+
The mail containing the redeem code rewards will automatically be deleted after two weeks, so you should claim the goods as soon as you can!
+
Wuthering Waves Code Redeem Site
Wuthering Waves Has No Redeem Site
+
Wuthering Waves has not implemented a redeem site for you to enter your codes. You can only redeem codes in-game by heading to "Other Settings" and using the Redemption Code feature there.
+
+
We will be updating this section if Kuro Games decides to add a Redeem Code feature in their website, so stay tuned!
Players who have Wuthering Waves via Epic Games Store were able to redeem a free Echo Starter Pack containing an Incomplete Echo (gives a random Echo) and Echo enhancement materials.
+
+
The freebie was available only until 6/23 11:59 am EDT.
A Waking of the World bundle was unlockable by subscribing to two Twitch channels playing Wuthering Waves, or by gifting two subs as they play the game. Players that did so were gifted a unique redemption code via Twitch inbox.
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
See the list of Zenless Zone Zero Redeem Codes that can be redeemed as of 3.2 on October 2026 and how to use the codes at the redemption code site in this Zenless Zone Zero (ZZZ) guide!
There are two ways to redeem Zenless Zone Zero gift codes. The easiest way to redeem the codes is through the official redemption code center, but you can also redeem codes with the game's built-in function.
The quickest way to redeem codes is by using Zenless Zone Zero's official code redemption site. You only have to sign up and input active codes to redeem your rewards. The freebies should show up in your in-game mail pretty quickly!
Go back to ''More'' and claim rewards from the Mail
+
+
+
You can also redeem codes with the game's built-in redemption code feature! Just look for the ''More'' tab in the in-game settings, and use the ''Redemption Code'' feature. The rewards are delivered to your in-game mail, which is found in the ''More'' tab too!
The copyrights of videos of games used in our content and other intellectual property rights belong to the provider of the game. The contents we provide on this site were created personally by members of the Game8 editorial department. We refuse the right to reuse or repost content taken without our permission such as data or images to other sites.
+ {redeem.url ? "Or in game:" : "Redeem in game:"}{" "}
+ {redeem.inGame}
+
+
+ )}
{message}
{feed &&
freshness(
@@ -104,7 +125,9 @@ export function CodesPage({
})
}
/>
- Redeemed · {a.region}
+ Redeemed
+ {/* The server only when there is more than one to tell apart. */}
+ {accounts.length > 1 && ` · ${a.region}`}
))}
diff --git a/src/client/redesign.css b/src/client/redesign.css
index 74c7fc1..f68ba61 100644
--- a/src/client/redesign.css
+++ b/src/client/redesign.css
@@ -5338,3 +5338,53 @@ button.mark {
font: 500 12px/1.4 var(--font-body);
color: var(--color-muted);
}
+
+/* Settings on large screens: the content used to stop at 900px, leaving most
+ of a 1920px screen empty, and the menu's rule ended partway down. Forms and
+ card grids now use up to 1320px (paragraphs keep their 75ch measure), and
+ the menu column runs the full height of the page. */
+.settings-layout {
+ min-height: calc(100vh - 130px);
+}
+.settings-layout > nav {
+ align-self: stretch;
+}
+.settings-content {
+ max-width: 1320px;
+}
+@media (max-width: 700px) {
+ .settings-layout {
+ min-height: 0;
+ }
+}
+/* The form pages fill the wider settings column too; the changelog keeps its
+ reading measure. */
+.game-settings,
+.backup-page,
+.reset-row,
+.sources-page .source-row,
+.sources-page .list-options,
+.sources-page .sources-heading {
+ max-width: none;
+}
+
+/* Where to redeem: the official page as a button when the publisher has one,
+ and the in-game route either way. */
+.redeem-where {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px 16px;
+ margin: 12px 0 16px;
+}
+.redeem-where .commit {
+ text-decoration: none;
+}
+.redeem-where p {
+ margin: 0;
+ font-size: 13px;
+ color: var(--color-ink);
+}
+.redeem-where p span {
+ color: var(--color-muted);
+}
diff --git a/src/ingest/codes/game8.ts b/src/ingest/codes/game8.ts
index ec5d45b..303ff53 100644
--- a/src/ingest/codes/game8.ts
+++ b/src/ingest/codes/game8.ts
@@ -89,3 +89,77 @@ export function parseGame8Codes(
}
return [...codes.values()];
}
+
+/**
+ * Game8's per-game codes pages share the copy-input markup but not their
+ * headings or columns, so this reads one page by the heading of its "active
+ * codes" section (an h2 runs to the next h2, an h3 to the next h2/h3).
+ *
+ * Within that section, a table counts only if it carries copy inputs and does
+ * not say its codes have expired — Wuthering Waves keeps an expired table at the
+ * top of its active section. A row's reward is its other cells, or for a single
+ * cell that holds both (Wuthering Waves, P5X) the cell's text after the code.
+ * Expiry is left null: these pages print "Expires TBA" or a range without a
+ * year, and a guessed year is a fabricated date.
+ *
+ * A missing heading throws (the page changed shape). A section with no code
+ * tables returns nothing; whether that is stored is `statesNoCodes`' call.
+ */
+export function parseGame8CodeTable(
+ html: string,
+ ctx: ParseContext,
+ heading: RegExp,
+): Omit[] {
+ const found = [...html.matchAll(/]*>([\s\S]*?)<\/h\1>/gi)].find(
+ (m) => heading.test(text(m[2]!)),
+ );
+ if (!found)
+ throw new Error("The current codes section could not be identified");
+ const after = html.slice(found.index! + found[0].length),
+ end = after.search(found[1] === "2" ? /
>();
+ for (const table of section.matchAll(/
]*>([\s\S]*?)<\/table>/gi)) {
+ if (!/a-clipboard__textInput/.test(table[1]!)) continue;
+ if (/\bexpired\b/i.test(text(table[1]!))) continue;
+ for (const tr of table[1]!.matchAll(/
ZAU2SYXHWX5L4ZH +code for 5k t-creds, 10 weapon upgrade kits