The 24-image pool and its re-encoding rules, and the six-font upload cap with namespaced families.
media.ts: pool of 24, downscaled to 1600px max edge at quality 0.82. PNG and WebP re-encode to WebP, everything else to JPEG, and the re-encode is discarded if it came out bigger.
Small files under 400KB skip re-encoding entirely — deliberately, so small GIFs keep their animation, which a canvas round-trip would kill. One unreadable file is swallowed so the rest of a drop survives.
Drag from the pool onto an image placeholder fills it at the slot’s size; drop on bare canvas places it where you dropped it.
fonts.ts: 8 built-in stacks chosen so nothing has to be downloaded. Uploads are capped at 6 fonts, 400KB each, stored as data URLs in localStorage and registered through the FontFace API.
Families are namespaced FCC <label> <timestamp> so an uploaded "Inter" cannot shadow a system face. FontUpload teaches what a usable font file is, because most people have never downloaded a .woff2 and will otherwise drop in a 3MB .ttf and hit the cap with no idea why.