Lightbox: bump close 2.5→3rem and prev/next 3→3.5rem so the hit area
is forgiving — random "click an arrow but the modal closes" reports
were almost always near-misses landing on the backdrop. Drop the
:active scale(.96) entirely (it was the jarring part) and soften the
hover bg from .8 to .7 with a slightly faster transition so taps feel
crisp instead of twitchy.
Wohnungen list: clicking the empty whitespace next to the chevron now
toggles the row open/closed, same as clicking the chevron itself.
Implemented as expandTriggerFor(target) wrapped around the existing
delegate — direct chevron clicks are short-circuited first; row clicks
fall through unless the target is inside an interactive element
(a/button/input/label/form/.partner-badge) or inside the already-
opened detail pane (where the gallery and "Zur Original-Anzeige" link
have their own meaning).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Logs from the user's last session showed that after walking through
all images and trying to go back from the last one, a backdrop click
fired (target===overlay) and closed the modal — even though the user
believed they clicked the prev arrow. Two reinforcing causes:
1. The image (.lightbox-image) is a sibling AFTER the buttons in the
DOM with no z-index, so paint order put the image on top of the
absolute-positioned arrows. Where the image's max-width/height box
overlapped the arrows, clicks landed on the image instead of the
arrow, and clicks in the gap between image and arrow hit the
overlay backdrop.
2. Even when an arrow handler did fire, the click bubbled up to the
overlay's click handler. While target===overlay was false in that
path, the next click sometimes did land on the backdrop, and the
close button had the same exposure.
Fix:
- Stack the controls above the image: image gets z-index:1, every
.lightbox button gets z-index:2.
- stopPropagation on prev/next/close button clicks AND on the image
click — guarantees they can never bubble into the overlay's
backdrop-close handler. Backdrop close still works on actual
backdrop clicks.
- Bump button background to rgba(0,0,0,.55) (was .08 white on dark)
so the arrows are clearly visible against the image.
Also strip the [lazyflat.lightbox] DEBUG(lightbox) tracer logs and
the window.error catch-all — original symptom is fixed and the
existing flow is confirmed working in user's logs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- notifications: round sqm_price to whole € in Telegram match messages
(was emitting raw float like "12.345614 €/m²").
- wohnungen: remove the admin-only "Bilder nachladen (N)" button. It
flickered into view whenever a freshly-scraped flat was still in
pending state, which was effectively random from the user's point of
view, and the manual backfill it triggered isn't needed anymore — new
flats are auto-enriched at scrape time. Also drops the dead helpers
it was the sole caller of: enrichment.kick_backfill,
enrichment._backfill_runner, db.flats_needing_enrichment,
db.enrichment_counts.
- lightbox: the modal didn't appear because Tailwind's Play CDN injects
its own .hidden { display: none } rule at runtime, which kept fighting
our class toggle. Switch the show/hide to inline style.display so no
external stylesheet can mask it. Single-class .lightbox now only owns
the layout — the initial-hidden state is on the element via
style="display:none".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Map: replace Leaflet's default marker with a divIcon SVG pin coloured
per state — green when the user has already successfully applied
(status.chip === "ok"), brand-blue otherwise. Same condition also hides
the action buttons in the popup, matching the list view, which already
hid both Bewerben and Ablehnen on success — so the only remaining
action on an applied flat is opening the original ad link.
Image gallery: clicks now open a global lightbox modal instead of a new
tab. The viewer fits each image into the viewport via max-width/height
+ object-fit: contain (uniform sizing regardless of source aspect),
shows × top-right, prev/next arrows on the sides, ←/→/Esc keyboard
nav, and click-on-backdrop to close. Prev arrow is hidden on the first
image and next on the last. Tile changes from <a target="_blank"> to
<button> since the new-tab fallback is no longer wanted.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New Telegram match layout:
Karl-Ziegler-Straße 7 (linked → Google Maps)
12489 Treptow-Köpenick
Miete: 944.12 (18.51 €/m²)
Fläche: 51.0
Zimmer: 2.0
WBS: nicht erforderlich
Zur original Anzeige (→ flat URL)
Zur lazyflat Seite (→ /?flat=<id>)
Deep-link behavior on lazyflat: ?flat=<id> expands the matching row,
scrolls it into view, and pulses a yellow highlight for 3s. The query
param is stripped from history afterwards so reload stays clean.
Unknown flat IDs drop the param silently.
Helpers: _address_lines splits the scraper's "Street, PLZ, District"
into two display lines; _gmaps_url falls back to a maps.google query
when the payload has no explicit link; _wbs_label normalises the
German WBS variants to "erforderlich" / "nicht erforderlich".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Container names, FastAPI titles, email subjects, filenames, brand text,
session cookie, User-Agent, docstrings, README. Volume lazyflat_data and
/data/lazyflat.sqlite already used the new name, so on-disk data is
preserved; dropped the now-obsolete legacy-rename comments.
Side effect: SESSION_COOKIE_NAME change logs everyone out on deploy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
base.html shrinks from a 150-line inline stylesheet to a single <link>;
the CSS moves to web/static/app.css byte-for-byte so there's no visual
change, but the stylesheet is now cacheable independently of the HTML.
Drop hx-on::before-request="this.disabled=true" from the Bewerben /
Ablehnen buttons — it duplicates hx-disabled-elt="find button" on the
parent form, which htmx already applies per request.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>