# Where things stand — end of Tue 28 July

**Historical snapshot. Superseded by [STATUS.md](STATUS.md) — don't act on the
list below.** It describes the single-file React build, which was ported to Nuxt
and deleted; several of its "tomorrow morning" items are long since built and the
files and commands it names are gone.

Working tree is clean, everything is pushed. `index.html` is 2,541 lines
(was 1,283 this morning). 11 commits.

---

## What got built today

**Recording is real**
- Mic capture via MediaRecorder, permission handling with an in-keeping
  "NO MIC" error on the LCD
- Review step between STOP and SEND — play back, re-record, delete, then send
- Sent replies persist into the thread, visually subordinate to incoming:
  inset, dimmed, labelled YOU, no unread LED, excluded from badges and from
  the auto-play chain

**Friends tab (new, 4th tab)**
- `FRIENDS` is now the single source of truth; `CONTACTS` derives from it
- Cassette spine library with ghost-outline empty state
- Add-friend flow: name → generated invite link → clipboard copy with
  COPIED/FAILED states → retro share tray (deliberately not a native sheet)
- Tape customiser: shell, label, font — live preview, spins into place on save
- `TAPE PARTS` block is walled off and labelled for Kat

**Home**
- Reorganised by person — swipeable carousel of friend cassettes
- Selected tape loads into the deck, messages filter to that friend
- Unknown callers (Alex, Olli) group under a blank UNKNOWN CALLER tape
- Unread count badges per cassette

---

## Tomorrow morning, in order

### 1. Split the file — done, by the Nuxt port

*(The prompt that was here asked for `app.jsx` + `tapes.jsx` and ended in "run
server.py". Both files and that command are gone — the port split the file
properly instead.)*

### 2. Sequential playback with beeps — still not built

The interaction the meeting kept returning to, and the one that makes the app
feel like the same object as the hardware. `BEEP.mp3` currently only fires when
you start recording.

PLAY should run the whole tape for the loaded friend — oldest first, BEEP
between each, reels spinning, LCD showing message N of M, unread counting down
live, "END OF MESSAGES" at the end. STOP must halt cleanly mid-chain; the radio
tab already does this with `radioSessionIdRef`, reuse that pattern. Skip
outgoing replies.

### 3. Demo reset

`friends` initialises from `FRIENDS` with five people. Your demo script opens on
the ghost cassette — right now you can't get back there without editing code,
and you'll want to rehearse more than once.

Hidden long-press on the JULI-FONE 850 badge → clears friends and messages,
drops you on the friends tab empty state.

### 4. iPad scaling

`.device` is hardcoded at 380px with no media queries anywhere in the file. On
an iPad that's a phone-sized column adrift in a big screen. Scale the whole
device up with a CSS transform above ~820px — don't reflow, just make the
machine bigger.

### 5. Nav tab unread dots

Small. Makes ARCHIVE and RADIO feel alive rather than decorative.

---

## Worth simplifying while you're in there

- **37 `useState` calls in one component.** Some look vestigial — `showModal`,
  `pressedBtn` and `playRate` each appear about twice, which usually means
  declared and never really used. Ask Claude to find and remove genuinely dead
  state. Do it as its own commit so it's easy to revert if something was load-bearing.
- **Archive still keys off `person` name strings** even though `friendId` now
  exists. It works, but it's the one place the old model survives — worth
  aligning if you touch archive at all.
- **`CLAUDE.md` is thin.** Adding the conventions you keep re-explaining would
  save context in every new chat: TAPE PARTS is Kat's, every cassette draws
  through the `tapeParts` resolver, outgoing replies stay visually subordinate
  and out of the auto-play chain.

---

## Leave alone

Radio tab, custom greeting, transcription, import, storage. All either agreed
out of scope today or Patrick's side of the line.
