Clip references & upload

Video Phase C

Make a clip's reference media actually usable. Picking from the library throws “could not link that library asset,” image references have no plain Upload, and uploads are raw multi-MB files. Phase C fixes all three. First of three phases on the new video floor — C → B → A (fix media → approach-first config → planner handoff). Light app theme · clickable. No caching — refresh for latest.

C · References & upload B · Approach-first config A · Planner handoff
C1 · Library pick that links
Picking a directly-uploaded library asset dead-ends with a toast. Root cause: the asset has no media row, so materialize byte-reads it by HTTP self-fetching the access-controlled file route (403). Fix: read the bytes server-side with overrideAccess — no self-fetch. The user is already authorized.
C2 · A real Upload affordance
Image reference rows today offer only Pick + Generate / ✦ DIY — uploading your own image is buried inside the DIY arm. C2 makes Upload a first-class action on every image reference, next to Pick.
C3 · Crop · resize · WebP
Uploads go in raw — a 4 MB phone photo eats R2 storage. C3 adds a client-side crop + max-width (480–1240, default 720) + WebP encode, so only the small file uploads. Crop depends on role: a start/end frame is locked to the clip's aspect ratio (must match exactly); a reference is free-form / Original, any ratio.
The pages
Scope of Phase C. All three changes live in the existing reference checklist on the video floor — no new stage, no schema migration. C1 rewrites the materialize-media route to read bytes server-side; C2 adds the Upload button to image rows in ResourceChecklist; C3 is a new shared ImageCropUploader client component reused wherever a reference image is uploaded. Approach-aware references (frames → start/end frame · ingredients → free multi-image list) come in Phase B.