// ─── K&N Elite — Shared components (light theme unified) ─── const { useState, useEffect, useRef, useMemo, useCallback } = React; // Unsplash luxury real estate photos — stable IDs const PHOTOS = { hero: "https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=2000&q=80&auto=format&fit=crop", apt1: "https://images.unsplash.com/photo-1600607687939-ce8a6c25118c?w=1200&q=80&auto=format&fit=crop", apt2: "https://images.unsplash.com/photo-1560518883-ce09059eeffa?w=1200&q=80&auto=format&fit=crop", apt3: "https://images.unsplash.com/photo-1600566753190-17f0baa2a6c3?w=1200&q=80&auto=format&fit=crop", apt4: "https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?w=1200&q=80&auto=format&fit=crop", apt5: "https://images.unsplash.com/photo-1600607687644-c7171b42498f?w=1200&q=80&auto=format&fit=crop", apt6: "https://images.unsplash.com/photo-1613977257363-707ba9348227?w=1200&q=80&auto=format&fit=crop", interior1: "https://images.unsplash.com/photo-1600210492486-724fe5c67fb0?w=1200&q=80&auto=format&fit=crop", interior2: "https://images.unsplash.com/photo-1600566753051-6057e2f04f83?w=1200&q=80&auto=format&fit=crop", interior3: "https://images.unsplash.com/photo-1616594039964-ae9021a400a0?w=1200&q=80&auto=format&fit=crop", interior4: "https://images.unsplash.com/photo-1600585154526-990dced4db0d?w=1200&q=80&auto=format&fit=crop", }; window.PHOTOS = PHOTOS; // ─── Logo mark (real PNG — gold key in circle) ─── function BrandMark({ size = 40 }) { return ( K&N Elite ); } // Full logo as image (for hero use where needed) function BrandFull({ height = 64, variant = "dark" }) { // dark = original (white text + gold key, for dark bg) // light = inverted text (dark text + gold key, for light bg) const filter = variant === "light" ? "invert(0.85) hue-rotate(0deg) brightness(0.75) saturate(1.2)" : "none"; return ( K&N Elite Real Estate Agency ); } function Brand({ onClick, floating = false, compact = false }) { const { t } = useI18n(); return (
K&N ELITE
{!compact && {t("brand_sub")}}
); } // ─── Language switcher ─── function LangSwitch() { const { lang, setLang } = useI18n(); return (
{["es", "en", "ru"].map((l) => ( ))}
); } // ─── Topbar ─── function Topbar({ onNav, current, floating = false }) { const { t } = useI18n(); return (
onNav("home")} />
); } // ─── Footer ─── function Footer() { const { t } = useI18n(); return ( ); } // ─── Toast ─── function useToast() { const [msg, setMsg] = useState(null); const show = useCallback((m) => { setMsg(m); setTimeout(() => setMsg(null), 2600); }, []); const node = msg ?
{msg}
: null; return { showToast: show, toastNode: node }; } // ─── CountUp hook (animated number) ─── function useCountUp(target, duration = 1800, fmt = (v) => Math.round(v).toLocaleString("es-ES").replace(/,/g, " ")) { const [value, setValue] = useState(0); const startRef = useRef(null); const targetRef = useRef(target); useEffect(() => { targetRef.current = target; let raf; startRef.current = performance.now(); const startVal = 0; const tick = (now) => { const p = Math.min(1, (now - startRef.current) / duration); const eased = 1 - Math.pow(1 - p, 4); setValue(startVal + (targetRef.current - startVal) * eased); if (p < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [target, duration]); return fmt(value); } // ─── Progress bar (under topbar) ─── function ProgressBar({ step, total = 3 }) { const pct = total === 0 ? 0 : ((step + 1) / total) * 100; return (
); } // ─── Big step header (HUGE number + meta) ─── function StepHeader({ step, total = 3, labels }) { const num = String(step + 1).padStart(2, "0"); return (
{num}
Step {num} / {String(total).padStart(2, "0")}

{labels[step]}

); } // ─── Horizontal stepper (compact) ─── function StepperH({ step, labels }) { return (
{labels.map((lab, i) => (
0{i + 1}
{lab}
))}
); } // ─── Checkbox ─── function Checkbox({ checked, onChange, children, required = false }) { return ( ); } // ─── Segmented toggle ─── function SegmentedToggle({ options, value, onChange }) { return (
{options.map((o) => ( ))}
); } // ─── Chip multi-select ─── function ChipMulti({ options, values, onToggle }) { return (
{options.map((o) => { const active = values.includes(o.value); return ( ); })}
); } function fmt(n) { return Math.round(n).toLocaleString("es-ES").replace(/,/g, " "); } function Ornament() { return (
); } Object.assign(window, { BrandMark, BrandFull, Brand, LangSwitch, Topbar, Footer, useToast, useCountUp, ProgressBar, StepHeader, StepperH, Checkbox, SegmentedToggle, ChipMulti, Ornament, fmt, });