today we taught plan1 how to open apps without leaving the room.
the big architectural win: WINDOWMANAGERALLOW_LIST. elves in the list — ur-shell, paper-pocket, lore-baby — can dispatch open-app custom events that bubble up to multi-task and open a new tray. no imports, no circular dependencies, no routing. paper-pocket doesn't know what multi-task is. it just says "open this" and the window manager decides what to do. this is how objects are supposed to talk to each other.
the system menu was always-visible because we'd moved its CSS class name to .mt-system-menu but left the HTML element as class="system-menu". the display: none rule was pointing at nothing. fixed by restoring consistency. this is a good category of bug: the component works perfectly in isolation, fails silently in composition.
the quadrant layout was bleeding under the taskbar because window.innerHeight / 2 doesn't know the taskbar exists. we measure target.querySelector('.taskbar').offsetHeight at idle time and subtract it before halving. the trays now sit flush.
for the flip-book darkroom: the play preview was getting a scrollbar because .tray-body has overflow: auto. when the darkroom opens we set overflow: hidden on the tray-body and restore it on close. we tried fullscreen via and via position: fixed viewport compensation — both had the same problem: CSS scope. $.style scopes all rules to the elf name, so portaling an element outside the elf breaks its styles. we landed on position: absolute; inset: 0 filling the tray window, which is what "preview inside the window" actually means. controls float over the top, fade after two seconds of inactivity, return on pointer move or touch. white-space: nowrap on the controls bar so the buttons don't wrap on small trays.
flip-book state is shared across all instances because plan98 creates one singleton store per elf name. every in the dom reads and writes the same store. strokes are stored in frameStrokes as plain json arrays, replayed onto each instance's local canvas by replayStrokes. two windows into the same flipbook, perfectly synchronized, no network required. this felt like a discovery but it's actually the architecture working as designed.
lint is green. four checks: css class conflicts, bare html tag selectors in event handlers, object-merge-nuance calls, cross-elf data-attribute conflicts.
clownbot is starting to feel like a place you can actually be in.