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>
207 lines
11 KiB
CSS
207 lines
11 KiB
CSS
/* lazyflat — site styling.
|
|
Imported via <link> from base.html. Tailwind utilities (via CDN) handle
|
|
layout/spacing; this file owns our design tokens and component classes. */
|
|
|
|
:root {
|
|
--bg-from: #e4f0fb; --bg-to: #f7fbfe;
|
|
--surface: #ffffff; --border: #d8e6f3;
|
|
--text: #10253f; --muted: #667d98;
|
|
--primary: #2f8ae0; --primary-hover: #1f74c8;
|
|
--danger: #e05a6a; --danger-hover: #c44a59;
|
|
--ghost: #eaf2fb; --ghost-hover: #d5e5f4;
|
|
--accent: #fbd76b;
|
|
}
|
|
|
|
html { color-scheme: light; }
|
|
body {
|
|
background: linear-gradient(180deg, var(--bg-from) 0%, var(--bg-to) 100%);
|
|
background-attachment: fixed;
|
|
color: var(--text);
|
|
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Inter, sans-serif;
|
|
}
|
|
|
|
/* Card + separator hooks */
|
|
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 14px;
|
|
box-shadow: 0 1px 2px rgba(16, 37, 63, 0.04); }
|
|
.border-soft { border-color: var(--border) !important; }
|
|
.divide-soft > :not([hidden]) ~ :not([hidden]) { border-color: var(--border) !important; }
|
|
|
|
/* Buttons */
|
|
.btn { border-radius: 9px; padding: 0.45rem 0.95rem; font-weight: 500;
|
|
transition: background 0.15s, box-shadow 0.15s, transform 0.05s; display: inline-block; }
|
|
.btn:active { transform: translateY(1px); }
|
|
.btn:disabled, .btn[disabled] { opacity: .55; cursor: not-allowed; pointer-events: none; }
|
|
.btn-primary { background: var(--primary); color: white; box-shadow: 0 1px 2px rgba(47,138,224,.25); }
|
|
.btn-primary:hover { background: var(--primary-hover); }
|
|
.btn-danger { background: var(--danger); color: white; }
|
|
.btn-danger:hover { background: var(--danger-hover); }
|
|
.btn-ghost { background: var(--ghost); color: var(--text); border: 1px solid var(--border); }
|
|
.btn-ghost:hover { background: var(--ghost-hover); }
|
|
|
|
/* Auto-apply hot button (unused in current UI, kept for future) */
|
|
.btn-hot { background: linear-gradient(135deg, #ff7a85 0%, #e14a56 100%); color: white;
|
|
box-shadow: 0 2px 6px rgba(225, 74, 86, 0.35); font-weight: 600; }
|
|
.btn-hot:hover { filter: brightness(1.05); }
|
|
.btn-hot.off { background: linear-gradient(135deg, #cfd9e6 0%, #99abc2 100%);
|
|
box-shadow: 0 1px 2px rgba(16, 37, 63, 0.15); }
|
|
|
|
/* Partner-Aktionsbadge — kleiner Kreis oben rechts am Button */
|
|
.btn-with-badge { position: relative; display: inline-block; }
|
|
.partner-badge {
|
|
position: absolute; top: -6px; right: -6px;
|
|
width: 18px; height: 18px; border-radius: 9999px;
|
|
background: var(--primary); color: #fff;
|
|
font-size: 10px; font-weight: 700; line-height: 1;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
border: 2px solid #fff;
|
|
box-shadow: 0 1px 2px rgba(16,37,63,.25);
|
|
pointer-events: auto;
|
|
}
|
|
|
|
/* Inputs */
|
|
.input { background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
|
padding: 0.55rem 0.8rem; width: 100%; color: var(--text);
|
|
transition: border-color .15s, box-shadow .15s; }
|
|
.input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(47,138,224,.18); }
|
|
|
|
/* Chips */
|
|
.chip { padding: .2rem .7rem; border-radius: 999px; font-size: .75rem; font-weight: 500; display: inline-block; }
|
|
.chip-ok { background: #e4f6ec; color: #1f8a4a; border: 1px solid #b7e4c7; }
|
|
.chip-warn { background: #fff4dd; color: #a36a1f; border: 1px solid #f5d48b; }
|
|
.chip-bad { background: #fde6e9; color: #b8404e; border: 1px solid #f5b5bf; }
|
|
.chip-info { background: #e3effc; color: #1f5f99; border: 1px solid #b6d4f0; }
|
|
|
|
/* Countdown — tabular digits + fixed width so the text doesn't wobble
|
|
while the seconds tick down. */
|
|
.countdown { font-variant-numeric: tabular-nums; display: inline-block;
|
|
min-width: 4.2em; text-align: left; }
|
|
.sep { color: var(--muted); user-select: none; }
|
|
|
|
/* iOS-style toggle switch */
|
|
.switch { position: relative; display: inline-block; width: 46px; height: 26px; flex-shrink: 0; }
|
|
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
|
|
.switch-visual { position: absolute; cursor: pointer; inset: 0;
|
|
background: #cfd9e6; border-radius: 999px; transition: background .2s; }
|
|
.switch-visual::before { content: ""; position: absolute; width: 20px; height: 20px;
|
|
left: 3px; top: 3px; background: #fff; border-radius: 50%;
|
|
box-shadow: 0 1px 3px rgba(16,37,63,0.25); transition: transform .2s; }
|
|
.switch input:checked + .switch-visual { background: var(--primary); }
|
|
.switch input:checked + .switch-visual::before { transform: translateX(20px); }
|
|
.switch.warn input:checked + .switch-visual { background: var(--danger); }
|
|
.switch input:focus-visible + .switch-visual { box-shadow: 0 0 0 3px rgba(47,138,224,.25); }
|
|
|
|
/* View toggle (Liste / Karte) — segmented pill, CSS-only via :has() */
|
|
.view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 999px;
|
|
overflow: hidden; background: var(--surface); font-size: 0.85rem; font-weight: 500; }
|
|
.view-toggle label { padding: 0.35rem 0.95rem; cursor: pointer; user-select: none;
|
|
color: var(--muted); transition: background .15s, color .15s; }
|
|
.view-toggle input { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }
|
|
.view-toggle label:hover { color: var(--text); background: var(--ghost); }
|
|
.view-toggle label:has(input:checked) { background: var(--primary); color: #fff; }
|
|
.view-map { display: none; }
|
|
body:has(#v_map:checked) .view-list { display: none; }
|
|
body:has(#v_map:checked) .view-map { display: block; }
|
|
#flats-map { height: 520px; border-radius: 10px; }
|
|
|
|
/* Flat detail expand */
|
|
.flat-row { border-top: 1px solid var(--border); }
|
|
.flat-row:first-child { border-top: 0; }
|
|
.flat-expand-btn { width: 1.75rem; height: 1.75rem; border-radius: 999px;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
border: 1px solid var(--border); background: var(--surface);
|
|
color: var(--muted); cursor: pointer; transition: transform .2s, background .15s; }
|
|
.flat-expand-btn:hover { background: var(--ghost); color: var(--text); }
|
|
.flat-expand-btn.open { transform: rotate(180deg); }
|
|
.flat-detail { background: #fafcfe; border-top: 1px solid var(--border); }
|
|
.flat-detail:empty { display: none; }
|
|
|
|
/* Temporary row highlight after arriving via a Telegram deep-link (?flat=…). */
|
|
.flat-highlight { animation: flat-highlight-pulse 3s ease-out; }
|
|
@keyframes flat-highlight-pulse {
|
|
0% { background-color: #fff4dd; }
|
|
100% { background-color: transparent; }
|
|
}
|
|
|
|
/* Normalised image gallery — every tile has the same aspect ratio */
|
|
.flat-gallery { display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
|
gap: 8px; }
|
|
.flat-gallery-tile { aspect-ratio: 4 / 3; overflow: hidden;
|
|
border-radius: 8px; border: 1px solid var(--border);
|
|
background: #f0f5fa; display: block;
|
|
padding: 0; cursor: zoom-in; }
|
|
.flat-gallery-tile img { width: 100%; height: 100%; object-fit: cover;
|
|
display: block; transition: transform .3s; }
|
|
.flat-gallery-tile:hover img { transform: scale(1.04); }
|
|
|
|
/* Image lightbox — full-viewport overlay with a centered, uniformly sized
|
|
image. Prev arrow is hidden on the first image; next arrow on the last. */
|
|
.lightbox { position: fixed; inset: 0; z-index: 1000;
|
|
background: rgba(8, 18, 32, .92);
|
|
align-items: center; justify-content: center;
|
|
animation: lightbox-fade .15s ease-out; }
|
|
.lightbox-image { max-width: 92vw; max-height: 88vh; object-fit: contain;
|
|
border-radius: 8px; box-shadow: 0 10px 40px rgba(0,0,0,.5);
|
|
background: #0c1726; position: relative; z-index: 1; }
|
|
.lightbox button { background: rgba(0, 0, 0, .55); color: #fff; border: 0;
|
|
border-radius: 9999px; cursor: pointer;
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
transition: background .15s, transform .05s; padding: 0;
|
|
z-index: 2; }
|
|
.lightbox button:hover { background: rgba(0, 0, 0, .8); }
|
|
.lightbox button:active { transform: scale(.96); }
|
|
.lightbox-close { position: absolute; top: 1.25rem; right: 1.25rem;
|
|
width: 2.5rem; height: 2.5rem; }
|
|
.lightbox-prev, .lightbox-next { position: absolute; top: 50%;
|
|
transform: translateY(-50%);
|
|
width: 3rem; height: 3rem; }
|
|
.lightbox-prev:active, .lightbox-next:active { transform: translateY(-50%) scale(.96); }
|
|
.lightbox-prev { left: 1.25rem; }
|
|
.lightbox-next { right: 1.25rem; }
|
|
.lightbox-prev[hidden], .lightbox-next[hidden] { display: none; }
|
|
.lightbox-counter { position: absolute; bottom: 1.25rem; left: 50%;
|
|
transform: translateX(-50%); color: rgba(255,255,255,.7);
|
|
font-size: .85rem; font-variant-numeric: tabular-nums;
|
|
letter-spacing: .02em; pointer-events: none; }
|
|
body.lightbox-open { overflow: hidden; }
|
|
@keyframes lightbox-fade { from { opacity: 0 } to { opacity: 1 } }
|
|
|
|
/* Map pin — divIcon default class has a white box; clear it so the SVG sits clean. */
|
|
.lazyflat-pin { background: transparent; border: 0; }
|
|
.lazyflat-pin svg { display: block; filter: drop-shadow(0 1px 2px rgba(0,0,0,.25)); }
|
|
|
|
/* Leaflet popup — match site visual */
|
|
.leaflet-popup-content-wrapper { border-radius: 12px; box-shadow: 0 6px 20px rgba(16,37,63,.15); }
|
|
.leaflet-popup-content { margin: 12px 14px; min-width: 220px; color: var(--text); }
|
|
.map-popup-title { font-weight: 600; font-size: 13px; display: inline-block; color: var(--primary); }
|
|
.map-popup-title:hover { text-decoration: underline; }
|
|
.map-popup-meta { color: var(--muted); font-size: 12px; margin-top: 2px; }
|
|
.map-popup-status { margin-top: 8px; }
|
|
.map-popup-actions { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
|
|
.map-popup-actions .btn { padding: 0.35rem 0.7rem; font-size: 12px; }
|
|
.map-popup-actions form { margin: 0; }
|
|
|
|
/* Brand avatar */
|
|
.brand-dot {
|
|
width: 2.5rem; height: 2.5rem; border-radius: 10px;
|
|
background: linear-gradient(135deg, #66b7f2 0%, #2f8ae0 60%, #fbd76b 100%);
|
|
box-shadow: 0 1px 4px rgba(47, 138, 224, 0.35);
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
overflow: hidden; flex-shrink: 0;
|
|
}
|
|
.brand-dot img { width: 88%; height: 88%; object-fit: contain; display: block; }
|
|
|
|
/* Anchors */
|
|
a { color: var(--primary); }
|
|
a:hover { text-decoration: underline; }
|
|
|
|
/* Tab nav */
|
|
.tab { padding: 0.7rem 0.2rem; color: var(--muted); border-bottom: 2px solid transparent;
|
|
margin-right: 1.5rem; font-weight: 500; }
|
|
.tab.active { color: var(--text); border-color: var(--primary); }
|
|
.tab:hover { color: var(--text); text-decoration: none; }
|
|
|
|
/* Mono / forensic JSON tree */
|
|
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; }
|
|
details > summary { cursor: pointer; user-select: none; }
|
|
details > summary::marker { color: var(--muted); }
|