Mirrors the three src/ changes into the embedded copy in
torn-attribute-tracker.user.js:
1. Hoist the four let bindings (lastSnapshot, lastAttr, lastDelta,
anchorError) to the top of start(), before dialog.mount() and
applyMode(), so the anchor-miss branch of applyMode() can write
anchorError without tripping the TDZ.
2. Default the floating dialog to bottom-left (left: 20px, bottom: 20px)
in both Dialog.mount() and Dialog.setMode()'s 'free' branch.
3. One-time migration: if prefs.pos has any non-zero coordinate on load
(a residue of the bottom-right era), reset it to {x: 0, y: 0} and log
to the console. Stored position from any subsequent drag is preserved.
4. Wrap the start() body in try/catch and log failures to the console,
so an unexpected error (e.g. TornTools conflict, future regressions)
does not prevent the dialog from appearing.
All four changes are byte-equivalent to the corresponding src/ changes;
the build-time drift tests in tests/build.test.js still pass.
Mirror the three source-level fixes in the embedded copies inside
torn-attribute-tracker.user.js:
1. _wireHeaderDrag: add the .tat-header closest() guard so the bundle
no longer steals focus from inputs/selects.
2. findAnchorElement: replace the narrow 'button[name="train"]' query
with the priority-ordered candidate list and the gym-panel last-
ditch fallback.
3. Inline anchor-error UX: add the anchorError state, include it in
the snapshot, surface it via applyMode, render the note with the
.tat-anchor-err class, and add the corresponding CSS rule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>