Files
gacha-event-tracker/docs/handoffs/2026-10-17-redesign-second-rejection-handoff.md
T
Lucas WintherandClaude Opus 5.5 5be04a7439 feat(tour): highlight each step, and make the comparing steps try both looks
Owner feedback on the forced tour. Each step rings what it is about and,
while forced, dims the rest of the page around it. "Pick a layout" and the
Timeline step hold Continue until both options have been on screen, scroll
their subject to the top of the window and, on wide screens, move the card
to the right edge so the page has room to show the difference.

Guards for the reported snap-back and endless tour, which did not
reproduce: the effect that moves an unseen reader to Relaxed fires at most
once per page load and never after the tab saw the tour done, and setup
saves only the prefs it changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 05:10:42 +02:00

971 lines
68 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Redesign handoff: second implementation rejected
Date: 2026-10-17. Repository: `/home/user/gacha-event-tracker`.
## Start here: launch the current server, then ask the owner
**Explicit owner instruction for the next agent:** launch the current server, make it accessible
on `0.0.0.0`, give the owner its browse URL, **then ask the owner for the biggest differences from
the mockup**. Get that feedback before making more UI changes. Do not begin another broad visual
rewrite or substitute your own audit for this conversation.
Suggested question after the server is reachable:
> The current build is running at [URL]. What are the biggest differences you see compared with
> the approved mockup? Which screen and interface should we fix first?
The owner has not yet identified the specific screen, viewport or visual differences behind this
second rejection. Do not guess that it is Checklist, Structured, a font-loading problem, or stale
cache. An optional screen/layout question was sent, but the owner instead requested this handoff.
At the handoff, the current build was running at **http://10.20.20.2:41908**, listening on all
interfaces (`*:41908`), Bun PID **2536610**. `/api/health` responded successfully. The process may
not survive the session; check rather than assuming it is running. `serve.ts` uses `Bun.serve`'s
all-interface default even though its log prints `localhost`. Verify the actual listener.
If it needs restarting, from the repository root:
```bash
PORT=41908 bun run serve.ts
```
If that port is occupied by the current server, reuse it; do not kill unknown processes. If the
shell is rebuilt, use a fresh port to avoid a previous service worker serving an old shell.
For a missing/stale build, rebuild only the shell, preserving the existing feed:
```bash
bun run build:css && bun run build:js && bun run build:static
PORT=<fresh-port> bun run serve.ts
```
Use the machine's reachable network address in the URL, not `0.0.0.0` as a destination. The owner
uses WireGuard `10.20.20.2`. Binding may require command escalation in the agent sandbox. Do not
fetch community sources just to start the UI.
## Current acceptance and scope
The owner asked for a faithful implementation of the already-approved mockups, then explicitly
said: **“Also make the structure layout the default.”** Structured is now the absent-preference
and new-setup default; an explicitly saved Relaxed choice is preserved.
After this agent claimed the correction was complete and started the build for the owner, the owner
said:
> “This is still not even close to the mockup.”
The owner then stopped further implementation and requested a handover specification. **The current
implementation is rejected. The previous completion claim and visual-review verdict do not establish
acceptance.** This handoff turn makes documentation changes only, retaining two audit screenshots
captured by a browser inspection that had already started when the owner asked to stop.
The unrelated request about sorting PDF-export examples was explicitly withdrawn as a message meant
for another agent. It is not part of this repository's task.
## Approved visual authority
1. Latest owner feedback, including the launch-and-ask instruction above.
2. `design/mockups/round7/converged.html` — Relaxed.
3. `design/mockups/round6/b-rail.html` — Structured, specifically B.
4. Approved functional/state requirements in
`docs/superpowers/specs/2026-10-16-ui-redesign-design.md`.
Read `AGENTS.md`, relevant product/design/domain docs, and the previous handoff
`docs/handoffs/2026-10-16-redesign-fidelity-handoff.md`. The earlier handoff remains useful for the
first failure, reference-file anchors and invariants. This document supersedes its current-status
and next-action instructions. Historical statements that Relaxed is the default are superseded by
the owner's Structured-default instruction.
The reference HTML files contain multiple generations of render functions and CSS overrides. The
fully rendered final file is the reference, not the first function with a matching name. Preserve
composition, proportions, hierarchy, typography, controls, density, responsive behavior and page
organization when translating HTML into React. Do not treat the reference as inspiration.
Necessary authorized adaptations remain narrow: focus pills in both interfaces, real data and
account-aware state, independent placements and servers, and the copy “Event data may be out of
date.” Never ship the prototype's fixed clock, synthetic events/history, demo toolbar or demo state.
## What this attempt changed
This is an inventory, **not a list of accepted presentation decisions**:
- `src/client/ReaderApp.tsx`: central shared UI composition, navigation counts, release notice,
settings routing, dedicated checklist components, archive-detail routing.
- `components/redesign/ChecklistEvent.tsx`: new event rows and `NextDeadline`, replacing old
`EventRow`/`NextUp` usage in the active Checklist.
- `FocusPicker.tsx`, `DailyPanel.tsx`, `RoutineGroup.tsx`: rail and direct progress controls.
- `RoutinesPage.tsx`, `RoutineEditor.tsx`: reset/game grouping, table columns, progress bars,
library, independent pin controls and native custom-routine drawer.
- `TimelinePage.tsx`: shared time grid for events and routine periods, sticky names, progress fill,
resets, zoom and mixed deadline queue. Sticky bar labels were repaired after review.
- `ArchivePage.tsx`, `ArchiveStory.tsx`, `ArchiveDetail.tsx`: outcome story/filter/sidebar/list/history
and a saved-record dialog. The archive dialog reads recorded progress rather than today's live
event state.
- `SettingsLayout.tsx`, `GameSettings.tsx`, `AppearancePage.tsx`, `TrackingChoices.tsx`: individual
game navigation, separate settings pages, interface/scheme controls, tracking/server/colour/reset
groups. The final profile uses tabs to choose which server's tracking choices are edited.
- `SetupWizard.tsx`, `EventDetail.tsx`: modified setup/detail presentation, retaining much existing
form content.
- `src/client/redesign.css`: large stylesheet, with initial rules plus later overrides. It is about
2,900 lines and contains repeated selectors and superseded layout rules.
- `state/usePrefs.ts`, `state/appearance.ts`, `index.html`: Structured default and interface grounds.
- Tests and docs were updated. No change in this attempt intentionally reminted event/account IDs.
Component shorthand above resolves to `src/client/components/redesign/`, except `EventDetail.tsx`,
which is `src/client/components/EventDetail.tsx`. `state/` shorthand resolves under `src/client/`.
`AppNavigation.tsx` was also changed: live counts and Settings placement. The new component files
introduced by this attempt were `ChecklistEvent.tsx`, `FocusPicker.tsx`, `RoutineEditor.tsx` and
`ArchiveDetail.tsx`; many other untracked files were already present from the preceding agent.
Additional implementation details worth retaining:
- `prefs.routineGroup` is a new optional stored preference: absent/`reset` means By reset; `game`
means By game. It uses the existing permissive preferences envelope, with no new storage key.
- `appearance.ts` applies Structured Slate grounds/surfaces separately from Relaxed, while keeping
contrast adjustment and existing custom palettes. The CSS and runtime tokens must be examined
together: runtime variables can override apparent reference values in the stylesheet.
- `TimelinePage` exports `routinePeriod`, also used for Routines reset countdowns. It uses resolved
reader clocks, not guessed UTC boundaries. Custom timeline occurrences respect account event intent.
- `placementAccounts` in `RoutinesPage` combines bulk pin changes per account. Reverting to one stale
full-account write per row can silently undo an earlier row's placement.
- `ArchiveDetail` displays the stored outcome/date/note/check-ins/amounts; Restore uses the existing
reducer. Already-ended records can be reconciled back into history. It is intentionally separate
from the live `ReaderDetail` adapter.
- `RoutineControl` keeps a numeric draft during editing so a transient empty input is usable.
Game colour previews use the rendered, contrast-adjusted game metadata.
- The profile server tabs are an implementation adaptation, not a separately approved owner design.
The reviewer accepted them within its narrow follow-up; the owner's overall rejection supersedes
that. Revisit them if they are among the differences the owner identifies.
Tests changed during this attempt:
| File under `test/` | Change |
| --- | --- |
| `appearance.test.ts` | Structured default and retained explicit Relaxed distinction |
| `prefs.test.ts` | Default/fallback expectations and saved Relaxed normalization |
| `reader-store.test.ts`, `reader-restore.test.ts` | Test choices adjusted so writes/restores still change the now-Structured default |
| `redesign-timeline.test.tsx` | Routine resets participate in mixed Ending soonest order |
| `redesign-routines.test.tsx` | Bulk placement combines per account and preserves the other view's pin |
| `game-settings.test.tsx` | Updated expected guidance for independent server progress |
Documentation touched by this attempt includes `AGENTS.md`, `docs/PRD.md`, `DATA-MODEL.md`,
`DESIGN.md`, `ARCHITECTURE.md`, the approved spec/plan, the first handoff, the correction report,
and `.superpowers/sdd/2026-10-16-ui-redesign/progress.md`. Other dirty docs and ingestion files may
belong to the earlier agent; do not attribute all of `git diff HEAD` to this attempt. There is no
clean per-agent commit boundary. The real changed code remains in the working tree.
## What went wrong
### 1. Translation remained approximate
The first rejected agent had wrapped old presentation with new CSS. This agent replaced more actual
markup, but still recreated the reference piecemeal instead of establishing a complete translation
of the final reference structure. It retained old form internals and filled gaps with implementation
choices, then added CSS overrides until selected screenshots looked closer.
Concrete examples caught during this attempt's review were substituted Settings navigation, a
routine Cycle column and missing live summary, invisible timeline bar text, and game colour above
tracking with repeated tall account blocks. Those particular defects were subsequently corrected.
**Their correction is not proof that the remaining screens or overall design are faithful.** The
owner's latest rejection requires a fresh understanding of the gaps, starting with their feedback.
### 2. Comparison fixtures made the evidence narrower than the claim
`docs/design-reviews/fidelity-capture.mjs` freezes the clock, intercepts the event-feed request with
mockup events, and seeds disposable routine/archive state. That can isolate visual differences, but
it is not the app the owner browsed. For Checklist it explicitly hides `.updates-panel` and
`.release-update` to align the first viewport. The comparison's event/account counts also differ
from the prototype, and the custom prototype routine was not seeded.
A real-feed capture after the rejection shows two prominent notice bands above Running now, many
short title-only events, and much different content density. A fixture-based image with hidden
notices did not validate that real first impression. Do not suppress production UI in an acceptance
capture. If fixture comparison remains useful, label it as a separate diagnostic and also capture
the exact normal-use state the owner is judging.
### 3. Functional checks became a proxy for the visual task again
Tests, no-overflow checks, correct IDs, working locks and successful actions are necessary. They
cannot certify fidelity. This attempt's final response led with rebuilt screens and test success
and reported that review cleared the issues. That was too strong for the evidence and the owner's
actual experience.
### 4. The independent review's scope was stretched
The reviewer found a finite list of material issues, then scored fixes to that list. Its final
verdict was **“ship the reviewed corrections”**, explicitly limited to those findings, not blanket
acceptance. Subsequent passes were instructed not to reopen a wider hunt. That process could verify
local repairs while leaving broader divergence undiscovered. The owner rejected the result anyway.
Do not continue from the review's ship verdict. Treat the supplied user feedback as the next primary
input, then review the whole affected composition against the rendered reference.
### 5. Documentation presented implementation as the design truth
`docs/DESIGN.md` and the 2026-10-17 correction report describe the implemented design confidently.
They are records of what was built, not evidence that it is approved. Earlier failure had the same
pattern. Keep requirements, current implementation, functional verification and owner acceptance
separate. Do not rewrite the spec to make the implementation look compliant.
## Evidence and limits
- Historical correction report and staged comparison images:
`docs/design-reviews/2026-10-17-redesign-fidelity.md` and its linked assets.
These now carry a rejection warning. They document a rejected attempt, not new visual goldens.
- Fresh real-feed audit image:
`docs/design-reviews/assets/2026-10-17-second-rejection/current-structured-checklist.png`.
- Fresh first-visit setup image:
`docs/design-reviews/assets/2026-10-17-second-rejection/current-structured-setup.png`.
The two fresh images used Chrome at 1440×1000 on `http://10.20.20.2:41908`. The setup was a clean
browser context. For Checklist, that disposable context was marked onboarded and limited to
Genshin/HSR/ZZZ/Wuwa; the actual feed and notices were retained, with no request interception.
**These are not screenshots of the owner's browser or stored preferences.** The browser reported
Structured and loaded Barlow/Barlow Condensed. This rules out missing fonts in that test context
only; it does not identify the owner's complaint or prove their environment matches it.
One observable item for later inspection: the actual audit showed a Checklist header count of 46
and Focus All count of 60. They currently count different row sets. Do not claim this is the owner's
main concern without asking. Likewise, correct shorter rows without descriptions are an approved
requirement, so do not fabricate summaries merely to match fixture density.
## Preserve the working state and domain work
HEAD remained `ee41389`. The checkout is dirty on `main`; the last status had 89 modified/untracked
entries including work that predates this agent. No commit, push, PR or deployment was made. Running
a local preview server was explicitly authorized. Do not reset, clean untracked files, discard the
reader implementation or create a new branch/worktree without a new reason/owner instruction.
Preserve, or carefully test any necessary changes to:
- v2 reader envelope, migration/recovery, unchanged IDs and legacy bytes;
- account-specific progress, saved clocks and archive snapshots;
- Web Locks plus IndexedDB serialization fallback, save failures and cross-tab synchronization;
- backup/export/import/recovery and independent code seen/redemption state;
- unknown-end/date-precision semantics and community-source conduct;
- insecure HTTP identity generation using `crypto.getRandomValues`, not `crypto.randomUUID`;
- new Structured default and explicit saved Relaxed preference;
- useful fixes from this attempt: bulk routine placements saved together per account, row keys
containing account+routine, and archived details using saved snapshots.
The most recent successful checks before handoff were 1,594 tests passing, TypeScript passing,
production build `a28021bbe1a8`, ordinary HTTP migration/setup/server/reset/backup checks, numeric
progress and routine creation, completion/Undo/archive Restore, and separate concurrent/offline
browser checks. The Docker-equivalent file layout passed 1,593 tests with one intentional skip;
no Docker image was built. This is functional evidence only, not visual acceptance.
## Recommended continuation after owner feedback
1. Write down the owner's biggest differences in their words, with the relevant interface, screen
and viewport. Launch-and-ask comes before implementation.
2. Render that exact approved reference state and current app state. Compare actual content,
visible notices and first-visit/returning conditions as appropriate. Record differences in
topology, dimensions, type hierarchy and controls, not just a list of CSS values.
3. Repair that bounded surface by translating the final reference markup and styles into the real
component tree. Replace rejected structure when needed; avoid another stylesheet of corrective
overrides over structurally different elements.
4. Keep an explicit list of necessary real-data/accessibility adaptations, with reasons. Ask the
owner when an adaptation changes a visible product decision instead of silently choosing it.
5. Show the normal running build to the owner at the chosen checkpoint. A fixture capture, passing
detector or subagent approval cannot substitute for checking their reported differences.
6. Then carry accepted treatment across the remaining screens, checking both interfaces and mobile,
with functional regression checks proportional to the change. Correct docs only to reflect what
has actually been established.
No further UI implementation was performed after the owner requested this handoff.
## New-session continuity checklist
- Start the new session in **this same checkout**. All implementation files, reference HTML,
screenshots, plans and handoffs are on disk, including untracked files. A fresh clone of HEAD
will NOT contain this work; no commit/push was authorized or performed.
- This handoff plus the linked spec, previous handoff and review records contain the material
decisions and continuation context. They are not a verbatim chat transcript. The owner's exact
visual objections beyond “not even close” are deliberately marked unknown because they were
never supplied; the next session must ask, not reconstruct them from guesses.
- The latest user instruction is to pause implementation for handoff, then have the next agent
launch the current server and ask about the biggest differences. No new design was approved
after either rejection. No permission to commit/publish was given.
- `public/` and `public/data/` are ignored build artifacts. Keep the current feed when starting;
if it is absent, use the documented offline feed build, not a network refresh. A changed port
is a different browser origin, so it will not automatically carry the owner's saved progress.
Do not clear or migrate the owner's browser storage merely to obtain a clean screenshot.
- Durable reproduction entry: `docs/design-reviews/fidelity-capture.mjs`, with reference fixtures
beside its images. Its staged-state limitations are described above. Chrome is at
`/usr/bin/google-chrome-stable`; install/use Puppeteer in scratch, not project dependencies.
- `/tmp/fidelity-http-final.mjs`, `/tmp/fidelity-journeys.mjs`, `/tmp/fidelity-matrix.mjs` and logs
were scratch functional checks, not durable requirements. They may still exist, but have fixed
ports and scratch imports; do not assume they survive or run unchanged. Standard test commands,
checked-in test sources and the recorded browser scenarios are the durable verification contract.
- Preview/mockup processes may survive: this run used app ports 41902–41908 and mockup41901.
Inspect before starting/stopping; never `pkill -f serve.ts`. PID2536610 was the owner preview at
recording time, not a permanent identity. Do not treat old port numbers or tool session IDs as
proof of the build currently being served.
- No UI edits were made in the handoff/continuity-check turns. The second-rejection warnings in
the older report, plan and design documentation exist to prevent another agent mistaking their
earlier positive wording for owner acceptance.
## Session 3 (2026-10-17): owner feedback on new-user setup, and the rebuild
The owner chose to start with new-user setup, against Round 6 (`b-rail.html`, final `onboarding()`).
Their differences, in their words, summarised:
1. Screen 1: “The margin/padding, sizing and placement of buttons is off.”
2. Screen 2: “The games are way too big, and not grouped together, not shown with colors, no
choose all games instead. The back button does work better though.”
3. Screen 3: no table to choose events/dailies/weeklies; instead the per-game subscription block
was “copy pasted” for every game. “Show events that haven't started” was “a random, flowing
button”; in the mockup it sits between dividers with a description.
4. Screen 4: “a weird checklist-timeline switch, instead of the drawing and descriptions the
mockup has.”
What changed: `SetupWizard.tsx` was rewritten as a translation of the rendered mockup markup
(`.ob`, `.preference-grid`, `.gpick`, `.type-guide`, `.availability`, `.mtx`/`.tg` with a
“Same for all” row and mixed state, `.upcoming-choice`, `.vcard` previews, `.ob-foot`), and the
scattered `.setup-wizard` overrides in `redesign.css` were replaced by one block at the end of the
file translated from the mockup's rules. Game order follows `GAMES`; colours use the app's
contrast-adjusted `meta`.
Deliberate deviations, for the owner to confirm:
- The Interface select and the “Everything stays in this browser” line were removed from step 1:
neither is in the mockup or the spec's setup list. New installs still get Structured, and
Interface remains in Settings → Appearance.
- The back link reads “Back” on every step (the mockup says “Preferences” on step 2), because the
owner said the current back button works better.
- The tracking table's row headers are `<th scope="row">` rather than `<td>`, for screen readers.
Evidence is functional and side-by-side capture only (1440 and 390, dark, fresh browser, real
feed, no interception). **Owner acceptance of these screens is still pending.**
### Setup accepted as “much better”; Checklist requests (same session)
The owner then asked, for the Checklist: “Add the time left bar to the compact screen. Make the
pill menu smaller. Let users sleep/dismiss the event data may be out of date for up to 7 days.”
- Compact rows now show the time-left meter on every row, in a fixed 120px column left of the
time (under the time on phones). Standard rows are unchanged: the meter only accompanies a
description.
- Focus pills are smaller (24px high, 11.5px text, tighter gaps), kept at 30px on coarse pointers.
- The source-age notice offers “Hide for 1 day / 3 days / 7 days”. It stores
`prefs.staleSnooze = { until, games }` in the existing permissive prefs envelope (no new storage
key). It returns when the time passes, when a game outside the snoozed set goes stale, or if the
saved value is malformed or more than seven days ahead. Settings → Source status and the
per-event detail notice are not snoozed.
### Checklist follow-up (same session)
Owner: “In compact view, there needs to be some more air, like there is in the mockup compact
view. In standard view, the space between the bottom of the Running now [heading] and the first
event in the list is too big. The Next to expire is too small, compared to the easier to read one
in the mockup, and it doesn't show the next 3 ones to expire, like it does in the mockup.”
- Compact is now a translation of the Round 6 B ledger (`table.led`): column headings Game /
Event / Time left / Ends in, a 3px game stripe with the short name, 15px titles, a 34%-wide
meter and a 20px condensed time, in 51px rows. It is drawn as a CSS grid over the existing
`<li>` rows (`LedgerColumns`, `ChecklistEvent compact`) so archive fade/confirm transitions keep
working. Under 860px the game column hides, the game name moves above the title and the meter
spans the row. This replaced the earlier compact `.event-entry` rules entirely.
- Note on references: Round 6 **B** and Round 7 render but hide the rail's “then” list
(`.rail .then{display:none}`); Round 6 **A** shows it with a 30px title and 64px countdown. The
owner asked for the mockup's larger rail with the next three, so the rail head now follows A's
proportions (52px under 1050px; the phone sizes and hidden list at 700px are unchanged).
- `.list-heading` bottom padding 22px → 8px (Relaxed 18px → 8px).
- Relaxed was not visually captured for these changes.
- Rail routines heading (owner): title is “Routines” with “Showing only pinned” as its subtext;
the “Focus on a game to open its routines.” hint was removed as not worth the text (groups still
auto-open on focus).
### Timeline (same session)
Owner: the implemented Timeline resembles the mockup well, but lost the liked resemblance to the
paimon.moe-style board on the live site; keep the new design and add a switch between the looks.
The scroll-following bar text of the new look is liked. Dailies should not be on the timeline. Add
a checkbox for time left vs end date. Add a divider where routines start when they have their own
section, and rename “Separate reset strips” to “Show routines in own section”. Later: in new-user
setup, when Timeline is chosen, show both designs and ask.
Owner's answers to clarifying questions: default look **New**; switch in the **Timeline controls
bar**; classic **reproduced as production** (no added scroll-following text); routines in classic
go in **their own section** under a divider.
What was built:
- `prefs.timelineLook` (`"new"` default | `"classic"`) and `prefs.timelineLabel` (`"left"` default
| `"end"`), both in the permissive prefs envelope. The classic look reuses the production board
(`components/Timeline.tsx`) with its own By game / Ending soonest, zoom and Jump to today
controls; the new look keeps its controls. The look switch sits first in the options bar.
- Classic gained an optional `routines` section (`ClassicRoutine`): a divider labelled Routines,
then per-game lanes of dashed-edge bars in the board's style, clamped to the board's window and
with names pinned like its event bars.
- Dailies (`cadence === "day"`) never appear on either look (`onTimeline`). The Routines page shows
a dash instead of a Timeline pin for dailies, and hides bulk “pin to Timeline” on daily-only bands.
- “Show end dates instead of time left” switches new-look bar text to “Ends 20 Oct” and routine
bars to “resets <date time>”. It does not change the classic look, which shows titles only.
- New-look divider: a dashed rule with a sticky ROUTINES label before each game's routine rows
when “Show routines in own section” is on.
- Setup step 4: choosing Timeline reveals “Which timeline design?” with drawn New / Classic cards;
`SetupDraft.timelineLook` is saved only when the reader starts on Timeline.
### Timeline follow-up: shared pill header, look in Settings, focus bar setting
Owner: the options (By game / Ending soonest, routines in own section, end dates) must work in the
classic look too; the classic board's small pill toggles look better than the big options bar; the
New/Classic switch belongs in Settings. Then: the focus bar moves under the pill header on the
Timeline, with a Settings option to show it on the Checklist and/or Timeline.
- `BoardHeader` and `TogglePill` (exported from `components/Timeline.tsx`) are the one header for
both looks: stacking pills, “Show routines in own section” and “Show end dates” toggle pills,
small −/+ and Jump to today. The old `.timeline-options` bar and its CSS are gone.
- Classic now honours both options: `routinesInline` (off → routines at the end of each game's
lane; on → own section under the divider) and `label` (time left / end date shown inside the
pinned name, after the title, shrinking before the title does; omitted on bars under 150px).
- Settings → Appearance: “Timeline design” (New / Classic) and “Focus bar” with “Show on the
Checklist” / “Show on the Timeline” (`prefs.focusBar = { checklist, timeline }`, absent = both).
A view whose focus bar is hidden ignores `focusGame`, so a focus chosen elsewhere can never
filter a page with no visible way to clear it. `TimelinePage` now receives `focus` and
`focusBar` from `ReaderApp` instead of reading `focusGame` itself.
- The classic board keeps its header and focus bar when it has nothing to plot, and draws the
board when only routines exist.
- Setup copy now points to Settings → Appearance for switching designs.
### Timeline polish (same session)
Owner: focus bar needs one row on large screens and no “Focus” text; By game / Ending soonest
should share an outline; the two options need an off affordance (checkboxes); routine items could
not be opened, so progress could not be tracked; the classic NOW chip was almost unreadable; open
far enough back / zoomed out so most text shows; always prefer the title over time left / end date.
- Header: the stacking pair is one rounded outline with the chosen side filled; the options are
small checkboxes (`ToggleOption`, replacing `TogglePill`).
- Timeline focus row (`.timeline-focus`): pills and Next on one row, heading hidden; wraps on
phones.
- Routines open a modal dialog (`RoutineDetail` in `TimelinePage.tsx`) from both looks: game and
server, title, reset time, and the shared `RoutineControl` for progress. It replaced the
off-screen `.timeline-routine-detail` section.
- Opening position (`openingLeft`, both looks; also Jump to today): back to the median running
start, with now kept between 25% and 50% across. The default zoom (32px/day) is unchanged;
readers who already zoomed keep their saved width.
- Classic NOW chip: inline critical background and ground-coloured bold text (`.eyebrow` had been
overriding the text colour with faint ink).
- Classic labels: shown only when `labelFits` estimates room for the whole title and the label.
- **Deferred by the owner:** an option, per routine or for all routines, to show routine dates
only without tracking progress.
- Footer (owner: “sometimes sticky… should not stick and take up space unless you've scrolled all
the way down”): the footer was never sticky. The Timeline boards scrolled inside a pane capped at
72vh, so the page bottomed out early and left the footer on screen while the board scrolled.
Both panes (`.timeline-scroller`, classic `.scroll-pane`) are now capped at `100dvh`: with the
board filling the window the footer is below the fold, and appears only past the board's end.
### NOW chip, server names, labels (same session)
Owner: make “now” even more readable; drop “europe” unless a game has two regions; if title and
end date cannot both be shown in full, drop the end date rather than truncating it.
- Classic NOW chip: 12px bold display caps, white on a fixed `#d42a47` (≈5:1), 2px ground ring.
- `state/reader/servers.ts`: `manyServers` / `serverSuffix`. Reading views (Checklist rows, Next to
expire, dailies, rail routine groups, Routines table, both Timeline looks, routine dialog,
updates, archive list/detail) name a server only when the game has more than one active account
(archives also count retired ones). Settings views still name servers, where they are the subject.
The “New since you last looked” row now names the game instead of the server.
- Classic bar names are one-line wrapping rows with overflow hidden: the title truncates only when
it alone is too long; labels (and routine progress) never shrink and simply wrap out of view
when they do not fit whole. `labelFits` was removed.
- Header options are now three either/or pill pairs (`PillChoice`, which also draws the stacking
pair): By game / Ending soonest, Show time left / Show end dates, Group routines and events / Show
routines in own section. `ToggleOption` (checkboxes) was removed.
### Routines view (same session)
Owner: Timeline accepted (“looking good now”). Routines: the Checklist/Timeline pin icons are not
centred and look odd against the mockup; text does not sit together as in the mockup; keep the
game colour bars; an always-open editor adds clutter — match the mockup, but show that progress
is editable and let the reader enter their own.
- The table is now a translation of Round 6 B `table.rt`: quiet 11px headings with the list/bars
icons on the pin columns, `.gcell` colour bar + short name (server only when several), 15px/500
titles muted when met, `.pin` 34×28 icon buttons (plain when off; near-tinted outline when on),
and a `.kebab` “⋯” summary for the existing menu.
- `RoutineProgress.tsx` replaces `RoutineControl` in this table only: `.tick` (Done / To do, or
“n of m days”) and `.amt` (bar + “**2** / 3 runs”, unit from the task or built-in). Amounts read
as text; a pencil (brightens, number gets a dashed underline on hover/focus) signals they are
editable. Click opens an inline number field + Save; Enter saves, Escape or leaving cancels.
`RoutineControl` still serves the Checklist daily panel and the Timeline routine dialog.
- All `.routine-table`/`.routine-pin`/`.routine-progress`/`.progress-track`/`.rtitle` rules
(51, including phone variants) were removed rather than overridden; a single `.rt` block holds
the replacement. On phones, hidden Routine/Progress headings keep their cells so pin headings
stay aligned.
- Owner follow-up: pins fade (150ms colour/background/border, skipped under reduced motion), and a
pinned pin previews “unpin” on hover (thinner tint, dashed outline). Ticks no longer carry
“To do / Done” text; multi-day routines keep “n of m days”, and the aria-label keeps the state.
### Library and create shelves (same session)
Owner: Routines accepted. Library and Create “lack a lot from the mockup… they are shelves in the
mockup, where they are weird in the live”. Owner chose to add all four missing create fields now
(Every day, Another hour, Note, Link) rather than defer the data changes.
- `RoutineDrawer.tsx`: one right-docked modal `<dialog>` (580px, dimmed backdrop, Escape) with two
panes translated from Round 6 B `libraryDrawer` / `createDrawer`:
- Library: Create-your-own card, intro, search, “New follows also show in Checklist/Timeline”,
per-game sections (“n of m followed · k servers”, Follow all weeklies/monthlies/cycles/
everything), rows with “Every Monday at 04:00 · 3 runs · Community wiki, checked 14 Oct 2026”
and a Follow/Following button, or one button per server (EU/NA/Asia) when several.
- Create/Edit: examples (mockup's five), What is it, Game, Server (select when several, note
otherwise), Repeats (day/week/month/N days + its detail row), Resets at (game reset / another
hour), Done when (once / several days / a number), Note, Link, Also show in (Timeline disabled
for dailies), live Preview, Create and follow / Cancel with a “Still needed” line.
- The library page mode and `RoutineEditor.tsx` (+ `.routine-editor` CSS) were removed. New
routines now follow on the chosen server only, with the chosen pins; edits keep placements.
- Data: `PeriodSchema` + `{unit:"day"}`; `TaskSchema` + optional `resetHour`, `note`, `link`
(http/https only); `GoalStatus.scope` + "day"; a task's `resetHour` swaps only the hour on its
row clock (same revision key). Notes show under the title in the table; links feed the menu's
Source item. Page summary no longer counts dailies as timeline pins.
- schema-guardian review of the routine format change: no blocker. Nothing stored is dropped or
re-keyed; the HEAD build keeps unreadable tasks raw and carries unknown fields through edits, so
new-format routines survive (a `day` routine is just invisible there). Fixed its two should-fix
items: the edit form warns when a reset-hour change will move which day logged ticks count for,
and `RoutineHistory` computes “today” and the catch-up window from a routine's own reset hour.
Notes left as-is: legacy `Dailies.tsx`/`migration.ts` paths cannot meet `day` routines today
(no caller for the legacy strip filter; legacy data cannot contain `day`).
- Owner accepted the create shelf. Library Follow/Following buttons now fade (150ms, skipped under
reduced motion), matching the Routines pins.
### Top bar (same session)
Owner: the logo and the tabs sit at different heights, so the bar feels off-centre. Measured: the
logo's text baseline was 3px above the tab labels' (38 vs 41px; the mockup bottom-aligns boxes,
which reads the same way with a 20px logo beside 15px tabs). Structured `.reader-ui .top` now uses
`align-items: baseline` and `.mark` has no bottom padding, so logo, tabs and Settings share one
baseline at the same 57px header height. Relaxed keeps `center` (its tabs are rounded pills).
- Owner: “the logo still looks higher than the tabs”. A shared baseline still left the logo's 15px
capitals centred 2px above the tabs' 11px capitals. `.mark` now also has `position: relative;
top: 0.1em` (half the cap-height difference), so both sets of capitals centre at the same line
(measured 35.5px). Reset to 0 in Relaxed and on phones, where the logo is not beside the tabs.
### Settings: About and Data & sources (same session)
Owner: dates and event-data refresh do not belong in About; move them to Data & sources, and make
the implemented pages look more like the mockup.
- `AboutPage.tsx` (replaces the `Colophon` render in Settings): the Round 6 B single-column
`.about-prose` — intro, Made by (author, GitHub, source code / report a problem / request a
feature / support), source editors (derived from every feed source via Colophon's `siteFor`),
Game-Time-Master, studios, idea credits, Unofficial and unaffiliated, and a “See data freshness
and source status” button. No dates or freshness.
- `DataSourcesPage.tsx`: intro (incl. which timezone dates use), Check for new data (shares the
footer's handler, now `refreshFeed` in ReaderApp), “Event data last refreshed … · ago”, a stale
warning naming the affected games, and one `.source-row` per game with each source's last
successful check, last content change, a status sentence in the mockup's four cases
(`sourceReason`) and Check source page. `.source-record` CSS removed.
- Every settings title now sits on the mockup's `.ptitle` rule.
- `Colophon.tsx` is no longer rendered by the reader app; its exported constants and `siteFor`
are reused.
- Owner follow-up: About's “The studios and games” lists every game again in its own (contrast-
adjusted) colour after the studios; the “See data freshness” button was removed from About.
### Changelog (same session)
Owner: make the changelog look like the mockup, keeping the commit history, spec links and the
New / Games & sources / Fixed kinds. `ChangelogPage.tsx` now renders its own Round 6 B
`.changelog-page .rel` markup (the sheet still uses `ChangelogContent`): an uppercase date line
with the note's kinds, a 26px condensed title, summary paragraphs, the covered commits as a bullet
list each ending in a coloured kind tag and its hash link, then “Commits a…b” and “Spec: …” links;
loose commits follow under “Other changes” by month.
### Reload keeps your place (same session)
Owner: refreshing always returned to the default view. The page was React state only
(`useState(prefs.view)`). `state/route.ts` now maps the page, the Settings section and a game's
settings page to the address hash (`#checklist`, `#timeline`, `#routines`, `#archive`,
`#settings/<section>`, `#settings/games/<game>`). ReaderApp starts from a valid hash, keeps it in
sync with `history.replaceState` (no history entry per click) once onboarded, follows manual hash
edits, and rewrites an unknown hash to the current page. No hash still opens the default view.
Browser-checked: Timeline, Settings → Changelog, a game page and Archive all survive a reload.
### Region & time (same session)
Owner: timezone search did not seem to work; is it needed, or should the full list just appear?
Cause: the search box filtered the options of a closed select (no visible effect until opened)
and matched raw IANA ids only. Decision: removed the search. `TimezoneSelect.tsx` is one native
select — Automatic (device zone + offset) first, then every zone grouped by region (`optgroup`),
named by city (“Buenos Aires, Argentina · GMT-3”); typing in the open list jumps to a city. Used by
Settings and new-user setup. `TimeSettings.tsx` now follows Round 6 B: intro, Default game server
as a segmented control, Your timezone with a “Currently displaying …” note, and Reset timing for
your games — one row per server with its automatic/custom reset, your local time and countdown,
and a Reset timing select (Automatic or a whole hour) that appends a clock revision like the game
page's override (earlier progress kept). Rows resolve the clock at max(now, real time) so a just-
saved revision shows immediately.
### Default view moved into Appearance (same session)
Owner: move Default view under Appearance and match the mockup's iconography. The separate
“general” settings section is gone; Appearance has a Default view group with the Round 6 B drawn
view cards (`ViewCards.tsx`, shared with new-user setup), the mockup's copy, and Replay the
introduction. `#settings/general` and a bare `#settings` now open Appearance. The view-card CSS was
un-scoped from `.setup-wizard` (with its border token defined on `.viewpick`).
- Owner: Lists options move into Data & sources. The “lists” settings section is gone; Data &
sources ends with an “In your lists” group (Show events that haven't started; Detect daily
events from source descriptions), each with a one-line explanation. `#settings/lists` opens Data
& sources. Appearance's menu subtitle is now “Theme, colours & default view”.
- Owner: list options belong before the long source list. “In your lists” now sits directly under
the refresh line and stale warning, above the per-game source rows.
- Owner: “In your lists” goes even before the source explanation. It is now the first group
under the title; everything about sources follows under a matching “Sources” heading.
### Backup (same session)
Owner: Backup must match the mockup much more closely. `BackupPage.tsx` keeps every action and its
logic (back up now, export/import all, progress-only export/import, undo last restore, restore
preview) in the Round 6 B layout: intro, a 7 days / 4 weeks / 6 months policy strip, the note,
outlined actions (Back up now solid; file inputs hidden behind their labels, still focusable),
then Daily / Weekly / Monthly sections (“n snapshots · span”) whose rows show the date, a summary
of that snapshot's tracked games, followed routines and archived events, and View backup.
`backupTier` (state/reader/backups.ts) classifies snapshots with the same windows
`retainBackups` keeps, tested against it. Old `.backup-*`/`.file-button` CSS was replaced.
Restore itself was not exercised in the browser (it reloads); its logic is unchanged.
- Owner: Back up now must not overwrite the day's automatic snapshot, and manual backups must be
deletable. New key `READER_KEYS.manualBackups` (`gacha-tracker:v2:manual-backups`), with
`readManualBackups` / `saveManualBackup` / `deleteManualBackup`; never pruned by
`retainBackups`, outside exports (only v1 keys are captured) and untouched by restore/undo.
Capped at 20 copies and ~1.5MB so the shared origin quota keeps room for the reader's own save;
entries are parsed one by one so a damaged entry does not discard the rest. The page shows a
“Your backups” list (View backup, Delete with inline confirm) above “Automatic history”.
schema-guardian: no blockers; its quota should-fix is the size cap above. Left as notes: the
error screen's raw recovery download includes every `gacha-tracker:` key, so it now also carries
manual backups (large but read-only).
### Your games: tracking saves on click (2026-10-18)
Owner: “Apply tracking choices” should not exist; choices apply when the panels are clicked. The
button is gone; `AccountSetup` in GameSettings saves the account on each change. It now changes
only the routines of the kind that was toggled (dailies, weeklies & monthlies, or cycles; Events
touches no routines), so a click never resets pins the reader set on the Routines tab — the old
Apply rewrote every kind's placements from the draft. A failed save reverts the panel. Browser-
checked, including a Checklist unpin on Weekly Bosses surviving an Events toggle.
- Owner: the rest of Your games should follow the mockup more closely (padding, margins, dividers,
structure). The Setup tab is now the Round 6 B structure: `.ptitle` (game name in its hue,
studio, Stop following game → hides the game), Codes tab “n new” badge, `.grp` sections with
inline descriptions on a rule — What to track (`.comp` cards with status lines: Shown/Hidden,
“n built in”, dashed “Some, fine-tuned” when partly followed — a click follows the rest — and
dimmed “none built in” that stays selectable per the spec), “Fine-tune in Routines →”; Servers
(`.srvrow` MAIN/ALSO with reset, local time and countdown; Remove only on extra servers); Game
colour (swatch, hex, Reset, preview chip, contrast note); Reset timing (one `ResetTimingRow` per
server, shared with Region & time, replacing the hour/minute editor). `TrackingChoices.tsx` and
30 unused CSS rules were removed; its test now checks the cards. Browser-checked.
- Owner: a game's About tab should match the mockup. It now follows Round 6 B `aboutPage`: “About
<game>”, fact rows (Studio; each server's next reset in your time · automatic/custom override),
then Data sources — each source linked by host with “Event / Banner / Battle pass schedule”,
the editors' thanks, and a “Source status and freshness” button to Data & sources.
- Owner: games under “Other games” should be greyed out like the mockup. Unfollowed rows carry
`data-off`; the name is muted and the colour bar faded to 25% (the mockup's `.srow.off`).
- Owner: “Manage games & order” opened a legacy-looking page that also showed the first game's
full configuration. Then: reorder by drag and drop in the sidebar instead. Now:
- Followed games in Settings → Your games are draggable (HTML5 drag; drop indicator), and
Alt+↑/↓ moves a focused row. Saved as the existing `prefs.gameOrder` (followed games in the new
order, then hidden ones), via `SettingsLayout`'s new `onReorder`. A “Sort A–Z” link replaces
“Manage games & order” and appears only when a custom order exists.
- A game page's title button is “Follow game” for an unfollowed game (switching its events on if
nothing was tracked), “Stop following game” otherwise.
- `#settings/games` without a game now shows only a games-and-order list (follow checkbox, name
linking to the game's page, ↑/↓, Reset to A–Z), never a game's configuration. It is no longer
linked from the sidebar.
- Known gap: HTML5 drag does not work on touch screens; phones can reorder only via that list.
- Owner reversed the drag-and-drop idea (weak affordance, hard to see). Removed: sidebar drag and
Alt+↑/↓, its CSS, the sidebar “Sort A–Z”, and the games-and-order list page. Settings →
Appearance now has a “Game order” section listing only tracked games (not hidden; events or a
followed routine) with 40×36 ↑/↓ buttons (disabled at the ends), working for mouse, touch and
keyboard, and “Sort A–Z” when a custom order exists. Saves `prefs.gameOrder` as tracked games
in the new order followed by the rest in their previous order. `#settings/games` without a game
opens Appearance. Browser-checked at 1440 (click) and 390 (tap).
- Owner: in Appearance, “Dailies on Checklist” and “Routine groups” looked odd on their own
background. `ChecklistDisplay` gained a `plain` variant (just the fields); Appearance now has a
“Checklist” settings group with Event rows, Dailies on Checklist and Routine groups side by side
(stacked on phones) and the note below. The Routines page keeps the mockup's shaded band.
- The “Offer standard-banner pulls in the library” switch (`prefs.standardPulls`) had no control
in the redesigned app (only the unmounted legacy `Controls.tsx`). Owner: put it in Data &
sources with the other list options. It is now the third “In your lists” checkbox, with the
mockup's note “Premium pulls are always offered.” Browser-checked: ticking it makes the library
offer Genshin's “Paimon's Bargains: Acquaint Fates”.
- Owner: the settings sidebar needs the mockup's hover. Unselected rows now take the surface
colour and ink text on hover (the mockup's `.srow:hover`), a step lighter than the selected
row's raised background, with a 120ms fade (skipped under reduced motion). Plain `:hover`, as in
the mockup; headless Chrome cannot emulate `(hover: hover)`, so a guarded rule was unverifiable.
### Round: logo, upcoming heading, routine band names (2026-10-18)
- The EVENTCLOCK logo is a button once the reader is onboarded; it opens the default view
(`changePage(prefs.view)`). Hover shows only the pointer cursor; the owner rejected an underline. During setup it stays plain text.
- The Checklist's "Upcoming events" `h2` had no styles. It is now a second `.list-heading`, "Not started yet",
with an "N events in G games" sub-line. That mirrors "Running now". The sub-line doesn't say "sorted by…",
because the Doing-first sort orders upcoming rows differently. In compact, the ledger header for this
section reads "Duration / Starts in" (`LedgerColumns upcoming`), not "Time left / Ends in".
- Routines bands (By reset) are named Dailies, Weeklies, Monthlies and Cycles, not Today, This week and
This month. A test covers this in `test/redesign-routines.test.tsx`. The checklist rail's `DailyPanel`
still says "Today · …", because it describes the current period rather than naming a group.
- Follow-up: the owner found "Not started yet" easy to miss. The section now has a 48px gap above it and a
2px rule in the accent colour (`--color-near`). Its heading sits on a full-width raised band
(`--color-raised`) with a "Coming up" eyebrow, and the heading is the same 28px as "Running now".
### Round: ticking today's dailies should feel rewarding (2026-10-18)
The owner found ticking a daily in the redesign "way less satisfying" than the live strip. They asked to keep
the live fireworks. `DailyPanel` (the Checklist rail) now works like this:
- **Tap target:** the whole row is the button (`.daily-hit`, `aria-pressed`), as the live pill is, not a
small checkbox at the edge. Rows that measure an amount keep their number field.
- **Done state:** a done row washes in the game's hue (`--g`), and its box fills with the hue. A streak
("3-day streak", from `streakOf`) shows from day 2, as live shows "3d".
- **Tick animation:** only on a tick made in this session (`data-fresh`), so a reload doesn't replay it.
The box pops (an overshoot scale), the check draws in, and a ring glows out from the row.
All of it is off under reduced motion.
- **Progress:** a pip bar in each game's colour and "N of M done" sit under the heading. The last tick
turns them to "All done for today" and flashes the pips (`data-burst`).
- **Fireworks:** the live `Fireworks` component, under the live rule. They fire only when a tick made now
completes the list. A shorter list (focusing a game) or arriving already done never fires them.
- **Tests:** `test/redesign-daily-panel.test.tsx`.
- Follow-up: events with a check-in goal, such as "To Temper Thyself and Journey Far" at 5 days a week,
looked unticked and had no count. The panel read only today's tick, so a week whose goal was met
without today's tick read as not done. `DailyPanel` now counts these as live does:
- **Done:** a row is done when it's ticked today or its goal is met (`hasGoal` and `status.met`).
A met row that isn't ticked draws a dotted check (`data-met`), as the live chip does. Nothing is
ticked on its behalf, so `aria-pressed` stays on today's tick.
- **Counter:** a goal row shows its goal count (`goalCount`: "5/5 wk", "3/5", "12/20 · 6d") in place of
the streak, one counter per row as on live. Its spoken label comes from live's `chipLabel`.
- **Checked:** in the browser with the real Genshin event, a met goal reads done, a tick makes it
"3/3 wk", and the tick survives a reload. Tests are in `test/redesign-daily-panel.test.tsx`.
### Round: pinned routines complete like dailies (2026-10-18)
The owner asked that routines with a target be marked complete like dailies, with fireworks, and that
the completion can be edited or undone. The Checklist rail's pinned routines now use
`redesign/PinnedRoutine.tsx` instead of `RoutineControl`, which still serves the Timeline routine dialog.
- **Look:** the same card language as the daily rows. A met routine washes in the game's colour and reads
"Done this week · resets in 1d 3h".
- **Check-ins** (Realm Depot, Spiral Abyss): the box ticks today. Unticking a met routine removes the
latest tick in the current period (`lastDayInPeriod`), which may be from an earlier day.
- **Amounts** (Weekly Bosses 3 runs, Battle Pass 10,000 EXP), when not met:
- the box completes the routine in one click by setting the amount to the target;
- "+1" steps the amount;
- the count, with a small bar and a pencil, opens an editor.
- **Amounts, auto-complete:** typing a value at or over the target completes the routine without Save,
once typing pauses for `AUTO_COMPLETE_MS` (450ms), so "10000" isn't cut short.
- **Undo for amounts:** unticking puts back the amount from before the completing action, when this
session saw it. After a reload that value isn't known, so the box opens the editor instead.
Nothing is guessed.
- **Completion animation:** only for an action taken in the row; arriving complete never fires. It is
staged: the bar fills from its previous value (`--from`), the row warms, the box pops at about 280ms
and the check draws, then the live `Fireworks` sparks fire at about 300ms. Reduced motion drops all of
it.
- **Tests:** `test/redesign-pinned-routine.test.tsx`. The auto-complete timer and the undo paths were
checked in the browser, not in unit tests, because the suite renders static markup only.
### Round: time-left bars on every standard row (2026-10-18)
Round 6 B hid the meter on Standard rows without a description
(`.event-entry.no-description .meter{display:none}`, b-rail.html:837). The owner asked why
those rows had no timing bar and chose to show it on every row, a deliberate departure from the mockup.
`ChecklistEvent` now always renders the meter. Rows without a description keep their tighter padding and
grow by the meter's height, about 20px.
### Round: the live urgency ramp (2026-10-18)
The owner asked for live's urgency colours: grey for a week or more, blue under a week, yellow under 3
days, red under a day. The redesign had derived them from the theme: "under a week" was the accent, and
"a week+" was the general muted text grey, which read nearly white. The ramp is now its own token set,
`--color-urgency-{calm,near,soon,critical}`:
- **Values:** `urgencyTokens` in `state/appearance.ts` sets live's dark or light values. Each is nudged
only to 3:1 contrast on the scheme's surfaces, the large-text bar; the default dark grey and light grey
move slightly. A custom accent no longer changes urgency.
- **Wiring:** `URGENCY_COLOR` (Meter.tsx) reads `var(--color-urgency-X, var(--color-X))`. The live UI never
sets the urgency tokens, so it falls back to its own unchanged values.
- **No CSS defaults:** none are declared in redesign.css, because that file is imported into the live
stylesheet too.
- **Scope:** `--color-near`, `--color-soon` and `--color-critical` keep their other jobs (accent,
warnings, NOW chip).
### Round: urgency colours editable, game strips, legend, scroll on tab change (2026-10-18)
- **Urgency colours in Settings → Appearance.** A new group sits under Colour scheme with the four steps
for the dark and light themes, a small bar sample per step, and "Use the default colours".
- It works with every scheme, not only Custom.
- Choices are stored in a new pref, `prefs.urgencyPalette`, shaped `{ dark: {calm, near, soon,
critical}, light: {…} }` with hex values.
- `urgencyChoice` reads it; unset or invalid steps keep live's values. `urgencyTokens` applies the
3:1 readability nudge.
- **Schema-guardian:** no risk. Prefs are `z.record(z.unknown())`, patches are shallow merges, and
the pref survives export, backup and restore. One existing behaviour applies to every pref: a v2
import merge keeps the current prefs.
- **Game colour strip on Standard event rows.** `.event-entry::before`, 3px, in the game hue, sits in the
list's side padding, as live's row rail does. It's faded to 55% and comes to full strength with a
glow on hover. Compact rows already had the `.gcell` bar.
- **Live's legend under "Running now"** (`UrgencyLegend` in ChecklistEvent.tsx): "bars = time left ·
colour = ends in a week+ / under a week / under 3 days / under a day". It reuses live's `STEPS`, now
exported from Legend.tsx, and `URGENCY_COLOR`, so it follows the reader's urgency colours.
- **Bug fixed:** changing tab kept the previous page's scroll, so leaving a scrolled Settings page opened
the Checklist part-way down and its rail looked empty. ReaderApp now scrolls to the top when `page`
changes. It skips the first render, so a reload's restored scroll is kept.
- Follow-up: the legend first sat inside the title block. That widened the block, so the sort and density
buttons wrapped under it and the heading looked cluttered. The owner wants one row. The legend is now
the last child of `.list-heading` (`flex-basis: 100%`, a 12px row gap), on its own line under the title
and the buttons. Title and buttons share a row down to 700px. At phone width the buttons wrap as they
always did.
- Follow-up 2: the owner wanted the legend on the same line as "35 events in 4 games · sorted by what
ends first". The Running now heading (`.running-heading`) is now a two-row grid:
- **Row 1:** the title, with the sort and density buttons on the right.
- **Row 2:** `.heading-meta` spans the full width, with the count on the left and the legend on the
right (`space-between`).
- **Narrower screens:** the legend wraps onto its own line under the count only when the line can't
fit, around 1100px. Below 700px the grid is one column, with the buttons left-aligned.
### Round: a grand celebration for finishing a section (2026-10-18)
The owner asked for a bigger celebration when a whole section is done: all of today's dailies, or every
routine in a game's group in the Checklist rail.
- **`Fireworks grand`:** seven bursts in two waves across the section, 14 sparks each, wider reach, 4px
sparks, 1.4s. With `hue` the game's colour joins the sparks. Called without props, it is unchanged for
the live strip and the single-row bursts.
- **`useSectionCelebration(total, done)`** (redesign/useSectionCelebration.ts) is the live strip's rule,
shared by `DailyPanel` and `RoutineGroup`. A section celebrates only when it becomes complete with more
done than a moment ago and the same total. A shorter list or arriving already complete never fires it.
- **Extras on a celebrating section:**
- a sweep of light across it (`section-sweep`, in the group's colour for routines);
- the "All done" line pops (`section-pop`): "All done for today" for dailies, and for routine groups
the summary, which now reads "All N done" when every routine is met (set in ReaderApp), not "N of N
completed".
- A complete group's summary stays bold in the game's colour.
- **Reduced motion and tests:** all motion is off under reduced motion. Tests are in
`test/redesign-routines.test.tsx`.
### Round: the returning-user tour (2026-10-18)
The owner walked through the tour on the reachable build (Settings → Appearance → Replay the
introduction) and asked for three things:
- **Back no longer takes Continue's place.** It used to appear where Continue had been, so clicking
through could land on it. Continue is now always first, in the same spot on every step. Back follows
it from step 2, and "Skip tour" sits apart at the far right. There's also a "2 of 6" counter.
- **The Timeline comes right after the Checklist.**
- **A codes step.** It opens the Codes tab of the first tracked game that has codes, or the Checklist
when none do.
The order is Routines → Checklist → Timeline → Redeem codes → Archive → Settings, which now opens on
Appearance. The welcome reads "Welcome back. A little has moved." Steps live in `TOUR_STEPS`, and
`ReturningTour` reports `onStep(stop)` to ReaderApp, which opens the page. Tests are in
`test/redesign-onboarding.test.tsx`.
- Follow-up: "Replay the introduction" now starts the tour itself. It used to only bring back the welcome
banner on the Settings page. `AppearancePage` takes `onReplayTour`, and ReaderApp sets `tourAutoStart`,
so `ReturningTour autoStart` opens on step 1 (Routines). Finishing or skipping clears it. A returning
reader seeing the tour for the first time still gets the welcome first. Checked twice in a row in
the browser.
### Round: focus pills with live's feel (2026-10-18)
The owner found the redesign's focus pills harsh ("scissors on a blackboard") next to live's chips.
They were cramped: 24px tall, 11.5px text, a 9.5px count and 5px gaps. They also snapped between states
with no easing, and hover only tinted the background.
`.focus-pill` now follows live's `.hue-chip` / GameFocus `Chip`:
- **Size:** 30px tall, 6px 12px padding, 12px text, a 10px tabular count at 70%, 6px gaps.
- **Colour:** an unpressed border in the game's hue at 30%; pressed, it's the full hue with a 14% wash.
- **Motion:** 130ms eased colour, border, background and shadow changes. Hover adds a 1px ring in the
hue and, where motion is allowed, a 1px lift, and an unpressed label brightens to ink. A press
scales to 0.96.
- **Empty games:** a game with nothing outstanding dims to 50% (`data-empty`).
The same pills appear in the Timeline's focus row, where they still fit on one line.
- Follow-up (Checklist rows): the owner found the "›" arrow too far from the time and date. It inherited
the row's 24px column gap (22px in Relaxed, 16px under 1050px). A negative margin on `.event-entry > svg`
now leaves 10px at every width and in both interfaces, measured in the browser.
### Round: closer to the screen edge, a wider rail (2026-10-18)
The owner found the content "weirdly far away" from the screen edge. The page was capped and centred at
1480px (1400px in Relaxed), which left 220px empty bands each side at 1920px.
- **Page width:** `.reader-ui` max-width is now 1920px; Relaxed is 1840px with 20px side padding instead
of 28px. At 2560px the page still centres, with 320px bands.
- **Checklist edges:** the list and its heading use 24px side padding instead of 32px, matching the
rail.
- **The rail** (Next to expire, dailies, routines) is wider, as the owner suggested: 300→360px in
Structured, 320→380px in Relaxed, and at medium widths 240→280px and 280→300px.
- **Checked:** Checklist in both interfaces at 1440, 1920 and 2560px, plus Timeline, Routines, Archive
and Settings at 1920px. Settings keeps its readable column width.
- Follow-up: the owner meant the inset between the content and the page's outer edge, about 24px
(32px on the update rows). It's now two tokens on `.reader-ui`: `--edge: 16px` for outer edges and
`--gutter: 24px` for the gap where a side column meets the content, which the owner asked to keep.
- **Full-width parts** use the edge on both sides: header, footer, Timeline and Routines headers,
the Routines table, Archive.
- **Side columns** use the edge outside and the gutter inside: the Checklist rail, the Settings nav,
the Archive sidebar.
- **The main Checklist column** mirrors that: updates, headings, list, ledger, foot.
- **At ≤700px**, where the columns stack, everything uses the edge, and the game strip moves to
`left: -9px` so it doesn't touch the screen edge.
- **Checked:** measured in the browser at 1920px and 390px, with no horizontal scroll.
- Follow-up (focus bar): the "Focus" label above the pills looked off-centre and off in weight. Cause:
`.reader-ui h2` comes later than `.focus-heading h2` with the same specificity, so it swapped in the
condensed display face at 13px. It also sat beside an 11px regular "Next: …" button and was centred
by box, not text. It's now Barlow 500 12px in muted grey, like the rail's "Next to expire"
(`.game-focus .focus-heading h2`), and `.focus-heading` aligns to the text baseline.
### Shipped as the initial redesign (2026-10-18)
The owner accepted the build: "I think this is ready to be shipped as the initial redesign." Before
committing:
- **Migration review:** a full schema-guardian review of the v1→v2 migration found no blockers. Its
low-severity gaps are in TODO.md.
- **Image check:** the suite ran as the image runs it, without docs (typecheck clean, 1642 pass,
build OK).
- **Docs:** `docs/DESIGN.md`'s redesign section now describes the shipped system.
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.
## Round: the forced tour and trying the looks (2026-10-18)
The owner asked for every reader, new and returning, to be put through the tour before they can use
the app, and for returning readers to start on Relaxed. "Pick a layout" (Checklist) and the Timeline
step switch the page behind in place, and the selected look is kept. See `docs/DESIGN.md` → "The tour"
and `docs/DATA-MODEL.md` for the `redesignTourSeen` values.
Schema review: no data-loss or stuck-state path. Accepted, by the owner's rule: a returning reader who
had picked Structured on purpose is moved to Relaxed once, and the previous value isn't kept. The tour's
layout step puts it back in one click. Left as is (low): a stale second tab can re-force the tour
once, and a save-error banner shown during a forced tour can be read but not clicked.
### Owner feedback on the forced tour (2026-10-18)
- **Highlight, try both, room for the Timeline.** Done; see `docs/DESIGN.md` → "The tour". Each
step rings its subject, the comparing steps hold Continue until both options have been on screen,
and they dock the card to the side and scroll their subject to the top.
- **Not reproduced, paused by the owner's call:** the owner saw the layout and Timeline switches snap
back ("you have to click like 5 times"), and the tour start again right after Finish tour, without
end. It did not reproduce in Chrome with one, two or three tabs, locally or on the live site, from
a fresh setup or a returning reader (a save logger showed each click written once, and nothing
writing it back). The only code that writes `interface` and `redesignTourSeen` on its own is the
"unseen" effect in `ReaderApp.tsx` (Relaxed + `"returning"`), and it would cause both symptoms if
it fired in some tab after the tour was finished; it now fires at most once per page load and
never after that tab saw the tour done. Setup now saves only the prefs it changed, not the whole
object, so a setup finished in a stale second tab leaves every other setting alone (the ones setup
sets, `redesignTourSeen` among them, it still writes: at worst that tab shows the tour once more). If it recurs:
log every `gacha-tracker:v2:reader` write with a stack (wrap `Storage.prototype.setItem`) in the
owner's own browser, with their data, and note which tabs are open and which build each runs.