1<!DOCTYPE html><html lang="en" data-astro-cid-sckkx6r4> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><!-- Mark that JS is available, as early as possible (before first paint). 2 Scroll-reveal initial states (opacity:0 / translateY) are scoped to 3 `.js` so that when JS is blocked/fails, content stays fully visible 4 instead of being permanently hidden. Must NOT be deferred. -->
4<script>document.documentElement.classList.add("js");</script>
4<link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="icon" href="/favicon.ico" sizes="16x16 32x32 48x48"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- The site is a fixed light design: declare that so browsers don't 5 auto-darken form controls/scrollbars, and tint mobile browser chrome 6 to match the white site header. --><meta name="color-scheme" content="light"><meta name="theme-color" content="#ffffff"><!-- Feed discovery: announce the RSS feed to readers and aggregators. --><link rel="alternate" type="application/rss+xml" title="Property Hub" href="/rss.xml"><!-- Consent Mode defaults must exist before either CookieYes or GTM. GTM 7 can then load immediately and send consent-safe cookieless pings while 8 advertising, analytics and behavioural vendors remain denied. -->
8<script> 9 (function () { 10 window.dataLayer = window.dataLayer || []; 11 window.gtag = window.gtag || function () { window.dataLayer.push(arguments); }; 12 13 window.gtag("consent", "default", { 14 ad_storage: "denied", 15 ad_user_data: "denied", 16 ad_personalization: "denied", 17 analytics_storage: "denied", 18 functionality_storage: "denied", 19 personalization_storage: "denied", 20 security_storage: "granted", 21 wait_for_update: 2000, 22 }); 23 window.gtag("set", "ads_data_redaction", true); 24 25 function cookieYesCategories() { 26 var match = document.cookie.match(/(?:^|;\s*)cookieyes-consent=([^;]*)/); 27 if (!match) return {}; 28 return decodeURIComponent(match[1]).split(",").reduce(function (values, item) { 29 var separator = item.indexOf(":"); 30 if (separator === -1) return values; 31 values[item.slice(0, separator)] = item.slice(separator + 1); 32 return values; 33 }, {}); 34 } 35 36 function isGranted(value) { 37 return /^(yes|true)$/i.test(value || ""); 38 } 39 40 function updateGoogleConsent() { 41 var categories = cookieYesCategories(); 42 var analytics = isGranted(categories.analytics); 43 var advertising = isGranted(categories.advertisement); 44 var functional = isGranted(categories.functional); 45 46 window.gtag("consent", "update", { 47 ad_storage: advertising ? "granted" : "denied", 48 ad_user_data: advertising ? "granted" : "denied", 49 ad_personalization: advertising ? "granted" : "denied", 50 analytics_storage: analytics ? "granted" : "denied", 51 functionality_storage: functional ? "granted" : "denied", 52 personalization_storage: functional ? "granted" : "denied", 53 }); 54 } 55 56 updateGoogleConsent(); 57 document.addEventListener("cookie_consent_update", updateGoogleConsent); 58 })(); 59 </script>
59<!-- CookieYes â deferred and non-blocking. -->
59<script id="cookieyes" type="text/javascript" src="https://cdn-cookieyes.com/client_data/b895e82d8e1c52eed0a7eb64/script.js" defer></script>
59<!-- Google Tag Manager â load immediately on the canonical production host. 60 Consent Mode above controls storage/vendor activation. The hostname 61 guard excludes localhost and every Netlify deploy-preview hostname. -->
61<script> 62 (function () { 63 if (!/^(www\.)?propertyhub\.net$/i.test(window.location.hostname)) return; 64 (function (w, d, s, l, i) { 65 w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" }); 66 var f = d.getElementsByTagName(s)[0]; 67 var j = d.createElement(s); 68 var dl = l != "dataLayer" ? "&l=" + l : ""; 69 j.async = true; 70 j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl; 71 f.parentNode.insertBefore(j, f); 72 })(window, document, "script", "dataLayer", "GTM-PQS7STW"); 73 })(); 74 </script>
74<!-- End Google Tag Manager --><!-- SEO --><title>About Property Hub | Where Serious Investors Are Built</title><meta name="description" content="Learn about Property Hub - education for people who want to invest themselves, and a done-with-you service for people who'd rather not."><link rel="canonical" href="https://propertyhub.net/about/"><!-- Open Graph --><meta property="og:title" content="About Property Hub | Where Serious Investors Are Built"><meta property="og:description" content="Learn about Property Hub - education for people who want to invest themselves, and a done-with-you service for people who'd rather not."><meta property="og:image" content="https://assets.propertyhub.net/homepage/hero-manchester-dusk-1400w.webp"><meta property="og:url" content="https://propertyhub.net/about/"><meta property="og:type" content="website"><meta property="og:site_name" content="Property Hub"><!-- Twitter --><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="About Property Hub | Where Serious Investors Are Built"><meta name="twitter:description" content="Learn about Property Hub - education for people who want to invest themselves, and a done-with-you service for people who'd rather not."><meta name="twitter:image" content="https://assets.propertyhub.net/homepage/hero-manchester-dusk-1400w.webp"><!-- Article-specific --><!-- JSON-LD -->
74<script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"Property Hub","url":"https://propertyhub.net","description":"Where serious investors are built. Education and done-with-you property investment services.","address":{"@type":"PostalAddress","streetAddress":"1st Floor B, 117-119 Portland Street","addressLocality":"Manchester","postalCode":"M1 6ED","addressCountry":"GB"}}</script>
74<!-- Fonts --><meta name="generator" content="Astro v6.3.7"><link rel="preconnect" href="https://assets.propertyhub.net"><link rel="preload" href="/fonts/roboto-latin-variable.woff2" as="font" type="font/woff2" crossorigin><!-- Hero/LCP image preload (per-page, optional) --><!-- Sitewide structured data (Organization + optional Article/BreadcrumbList). 75 Kept at the end of <head>, separate from the per-page JSON-LD above, 76 so multiple ld+json blocks coexist without duplication. --><link rel="stylesheet" href="/_astro/Layout.ebJlzi19.css"> 77<style>.logo-stack{display:grid;line-height:0}.logo-stack .logo-face{grid-area:1 / 1;transition:opacity .5s ease}.logo-stack .logo-standard{opacity:0}.logo-stack .logo-invest{opacity:1}.logo-stack.is-armed .logo-standard{opacity:1;transition:none}.logo-stack.is-armed .logo-invest{opacity:0;transition:none}.logo-stack.is-playing .logo-standard{opacity:0}.logo-stack.is-playing .logo-invest{opacity:1}@media(prefers-reduced-motion:reduce){.logo-stack .logo-face{transition:none}}.nav-serif,.nav-serif a,.nav-serif button{font-family:var(--font-sans);font-weight:500;letter-spacing:0}.nav-dropdown a{font-family:var(--font-sans);letter-spacing:0}.nav-dropdown-panel{opacity:0;visibility:hidden}.nav-dropdown-root:hover .nav-dropdown-panel,.nav-dropdown-root:focus-within .nav-dropdown-panel,.nav-dropdown-root.is-open .nav-dropdown-panel{opacity:1;visibility:visible}.nav-dropdown-root.is-closed .nav-dropdown-panel{opacity:0;visibility:hidden}.nav-dropdown-label{font-family:var(--font-sans);font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.18em;color:var(--color-text-tertiary, #8A929C)}.nav-cta{font-family:var(--font-sans);font-weight:500;letter-spacing:.01em}.btn.nav-cta{transition-duration:.15s}.menu-icon{position:relative;display:block;width:24px;height:24px}.menu-bar{position:absolute;left:3px;right:3px;height:2px;border-radius:1px;background:currentColor;transition:transform .25s cubic-bezier(.16,1,.3,1),opacity .15s ease}.menu-bar--top{top:6px}.menu-bar--mid{top:11px}.menu-bar--bot{top:16px}#mobile-menu-btn.is-open .menu-bar--top{transform:translateY(5px) rotate(45deg)}#mobile-menu-btn.is-open .menu-bar--mid{opacity:0;transform:scaleX(.4)}#mobile-menu-btn.is-open .menu-bar--bot{transform:translateY(-5px) rotate(-45deg)}@media(prefers-reduced-motion:reduce){.menu-bar{transition:none}} 78.footer-label[data-astro-cid-sz7xmlte]{font-family:var(--font-sans);font-weight:600;text-transform:uppercase;letter-spacing:.18em}.footer-link[data-astro-cid-sz7xmlte]{font-family:var(--font-sans);font-weight:400;letter-spacing:0;touch-action:manipulation}a[data-astro-cid-sz7xmlte].footer-link:active{color:#fff} 79.timeline-pulse[data-astro-cid-kh7btl4r]{animation:timeline-pulse 2.4s cubic-bezier(.16,1,.3,1) infinite}@keyframes timeline-pulse{0%,to{box-shadow:0 0 0 5px #ff51512e}50%{box-shadow:0 0 0 10px #ff51510f}}.timeline-track[data-astro-cid-kh7btl4r]::-webkit-scrollbar{display:none}.timeline-track[data-astro-cid-kh7btl4r]{scrollbar-width:none}.hero-about[data-astro-cid-kh7btl4r]:before{content:"";position:absolute;inset:0;background:radial-gradient(ellipse 80% 70% at 5% 20%,rgba(255,81,81,.04) 0%,transparent 60%),radial-gradient(ellipse 60% 80% at 90% 80%,rgba(201,169,110,.035) 0%,transparent 50%);pointer-events:none}.stat-card[data-astro-cid-kh7btl4r]:after{content:"";position:absolute;bottom:0;left:50%;transform:translate(-50%);width:32px;height:2px;background:var(--color-coral);border-radius:1px;opacity:0;transition:opacity .25s cubic-bezier(.16,1,.3,1)}.stat-card[data-astro-cid-kh7btl4r]:hover{border-color:var(--color-border);box-shadow:var(--shadow-card)}.stat-card[data-astro-cid-kh7btl4r]:hover:after{opacity:1}.reveal[data-astro-cid-kh7btl4r]{opacity:0;transform:translateY(20px);transition:opacity .4s cubic-bezier(.16,1,.3,1),transform .4s cubic-bezier(.16,1,.3,1)}.reveal[data-astro-cid-kh7btl4r].visible{opacity:1;transform:translateY(0)}.reveal-stagger[data-astro-cid-kh7btl4r]>[data-astro-cid-kh7btl4r]{opacity:0;transform:translateY(20px);transition:opacity .4s cubic-bezier(.16,1,.3,1),transform .4s cubic-bezier(.16,1,.3,1)}.reveal-stagger[data-astro-cid-kh7btl4r].visible>[data-astro-cid-kh7btl4r]:nth-child(1){transition-delay:0ms;opacity:1;transform:translateY(0)}.reveal-stagger[data-astro-cid-kh7btl4r].visible>[data-astro-cid-kh7btl4r]:nth-child(2){transition-delay:80ms;opacity:1;transform:translateY(0)}.reveal-stagger[data-astro-cid-kh7btl4r].visible>[data-astro-cid-kh7btl4r]:nth-child(3){transition-delay:.16s;opacity:1;transform:translateY(0)}.reveal-stagger[data-astro-cid-kh7btl4r].visible>[data-astro-cid-kh7btl4r]:nth-child(4){transition-delay:.24s;opacity:1;transform:translateY(0)} 80</style></head> <body class="font-sans text-text-primary antialiased bg-background " data-astro-cid-sckkx6r4> <!-- Keyboard users can bypass the header nav; visually hidden until focused. 81 Target: the page's main landmark (id "main-content" â pages and 82 sub-layouts all carry it). Styles in global.css (.skip-link). -->
82 <a href="#main-content" class="skip-link" data-astro-cid-sckkx6r4>Skip to content</a> <!-- Google Tag Manager (noscript) --> <noscript> <iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PQS7STW" height="0" width="0" style="display:none;visibility:hidden" data-astro-cid-sckkx6r4></iframe> </noscript> <!-- End Google Tag Manager (noscript) --> <!-- HEADER --><header class="fixed top-0 left-0 right-0 z-[99] bg-white/95 backdrop-blur-[10px] transition-shadow duration-250" id="site-header" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);"> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-between h-[88px]"> <a href="/" class="flex-shrink-0"> <img src="/property-hub-logo.svg" alt="Property Hub" class="h-[68px] w-auto"> </a> <!-- Desktop nav --> <nav class="hidden xl:flex items-center gap-6 nav-serif whitespace-nowrap"> <!-- Start Here (standalone) --> <a href="/learn/" class="text-[16px] hover:text-text-primary transition-colors duration-150 text-charcoal-soft font-normal">Start Here</a> <!-- Investing Guides (dropdown) --> <div class="relative group nav-dropdown-root"> <button id="nav-dd-guides-btn" aria-controls="nav-dd-guides" class="nav-dropdown-btn flex items-center gap-1.5 text-[16px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coral transition-colors duration-150 hover:text-text-primary text-charcoal-soft font-normal" aria-expanded="false" aria-haspopup="true"> 83Investing Guides 84<svg class="w-3 h-3 opacity-50 group-hover:opacity-100 transition-opacity duration-150" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7"></path></svg> </button> <div id="nav-dd-guides" class="nav-dropdown-panel absolute top-full left-0 pt-3 transition-[opacity,visibility] duration-250" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);"> <div class="nav-dropdown bg-white rounded-lg shadow-card border border-border-light py-2 min-w-[230px]"> <a href="/guides/getting-started/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Getting Started</a> <a href="/guides/buying-sourcing/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Buying & Sourcing</a> <a href="/guides/financing-tax/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Financing & Tax</a> <a href="/guides/strategy-portfolio/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Strategy & Portfolio</a> <a href="/guides/lettings-landlord/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Lettings & Being a Landlord</a> <a href="/guides/market-view/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Market View & Timing</a> </div> </div> </div> <!-- Build Your Portfolio (dropdown) --> <div class="relative group nav-dropdown-root"> <button id="nav-dd-portfolio-btn" aria-controls="nav-dd-portfolio" class="nav-dropdown-btn flex items-center gap-1.5 text-[16px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coral transition-colors duration-150 hover:text-text-primary text-charcoal-soft font-normal" aria-expanded="false" aria-haspopup="true"> 85Build Your Portfolio 86<svg class="w-3 h-3 opacity-50 group-hover:opacity-100 transition-opacity duration-150" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7"></path></svg> </button> <div id="nav-dd-portfolio" class="nav-dropdown-panel absolute top-full left-0 pt-3 transition-[opacity,visibility] duration-250" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);"> <div class="nav-dropdown bg-white rounded-lg shadow-card border border-border-light py-2 min-w-[230px]"> <a href="/invest/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Invest With Us</a> <a href="/invest/book-a-consultation/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Book a Consultation</a> <a href="/invest/case-studies/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Past Deals & Case Studies</a> <a href="/investor-stories/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Investor Stories</a> <a href="/invest/expats/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">For Expats</a> </div> </div> </div> <!-- Resources (dropdown) --> <div class="relative group nav-dropdown-root"> <button id="nav-dd-resources-btn" aria-controls="nav-dd-resources" class="nav-dropdown-btn flex items-center gap-1.5 text-[16px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coral transition-colors duration-150 hover:text-text-primary text-charcoal-soft font-normal" aria-expanded="false" aria-haspopup="true"> 87Resources 88<svg class="w-3 h-3 opacity-50 group-hover:opacity-100 transition-opacity duration-150" fill="none" stroke="currentColor" viewBox="0 0 24 24">
88<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7"></path></svg> </button> <div id="nav-dd-resources" class="nav-dropdown-panel absolute top-full left-0 pt-3 transition-[opacity,visibility] duration-250" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);"> <div class="nav-dropdown bg-white rounded-lg shadow-card border border-border-light py-2 min-w-[210px]"> <a href="/news/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Latest News</a> <a href="/pulse/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Newsletter</a> <a href="/free-tools/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Investor Toolkit</a> <a href="https://quiz.propertyhub.net/" target="_blank" rel="noopener noreferrer" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Investment Readiness Quiz</a> <a href="https://podcast.propertyhub.net/" target="_blank" rel="noopener noreferrer" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Podcast</a> <a href="https://www.youtube.com/propertyhubuk" target="_blank" rel="noopener noreferrer" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">YouTube</a> <a href="/books/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Books</a> <a href="/university/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Free Courses</a> <a href="/webinar/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Webinar</a> <a href="/ai/" class="block px-4 py-2 text-[13px] text-text-secondary hover:text-text-primary hover:bg-background transition-colors duration-150">Rob AI</a> </div> </div> </div> <!-- CTA --> <a href="/free-tools/" class="btn btn--primary btn--xs nav-cta" data-analytics-cta="true" data-cta-name="get_free_toolkit" data-cta-location="header" data-business-area="tools">Get the free toolkit</a> </nav> <div class="flex items-center gap-3"> <!-- Search button --> <button id="search-toggle" class="p-2 text-text-tertiary hover:text-text-primary transition-colors duration-150" aria-label="Search"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg> </button> <!-- Mobile menu button (hamburger morphs to cross when open) --> <button id="mobile-menu-btn" class="xl:hidden p-2 text-text-secondary" aria-label="Open menu" aria-expanded="false" aria-controls="mobile-menu"> <span class="menu-icon" aria-hidden="true"> <span class="menu-bar menu-bar--top"></span> <span class="menu-bar menu-bar--mid"></span> <span class="menu-bar menu-bar--bot"></span> </span> </button> </div> </div> <!-- Mobile menu --> <div id="mobile-menu" class="hidden xl:hidden bg-white border-t border-border-light px-4 pb-4 max-h-[80vh] overflow-y-auto"> <!-- Start Here (standalone) --> <a href="/learn/" class="nav-serif block py-3 text-[18px] font-normal text-text-primary border-b border-border-light">Start Here</a> <!-- Investing Guides --> <div class="border-b border-border-light"> <button class="mobile-dropdown-trigger nav-serif w-full flex items-center justify-between py-3 text-[18px] font-normal text-text-primary" aria-expanded="false"> 89Investing Guides 90<svg class="mobile-chevron w-4 h-4 text-text-tertiary transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg> </button> <div class="mobile-dropdown hidden pl-4 pb-3 space-y-1"> <a href="/guides/getting-started/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Getting Started</a> <a href="/guides/buying-sourcing/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Buying & Sourcing</a> <a href="/guides/financing-tax/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Financing & Tax</a>
90 <a href="/guides/strategy-portfolio/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Strategy & Portfolio</a> <a href="/guides/lettings-landlord/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Lettings & Being a Landlord</a> <a href="/guides/market-view/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Market View & Timing</a> </div> </div> <!-- Build Your Portfolio --> <div class="border-b border-border-light"> <button class="mobile-dropdown-trigger nav-serif w-full flex items-center justify-between py-3 text-[18px] font-normal text-text-primary" aria-expanded="false"> 91Build Your Portfolio 92<svg class="mobile-chevron w-4 h-4 text-text-tertiary transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg> </button> <div class="mobile-dropdown hidden pl-4 pb-3 space-y-1"> <a href="/invest/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Invest With Us</a> <a href="/invest/book-a-consultation/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Book a Consultation</a> <a href="/invest/case-studies/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Past Deals & Case Studies</a> <a href="/investor-stories/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Investor Stories</a> <a href="/invest/expats/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">For Expats</a> </div> </div> <!-- Resources --> <div class="border-b border-border-light"> <button class="mobile-dropdown-trigger nav-serif w-full flex items-center justify-between py-3 text-[18px] font-normal text-text-primary" aria-expanded="false"> 93Resources 94<svg class="mobile-chevron w-4 h-4 text-text-tertiary transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg> </button> <div class="mobile-dropdown hidden pl-4 pb-3 space-y-1"> <a href="/news/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Latest News</a> <a href="/pulse/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Newsletter</a> <a href="/free-tools/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Investor Toolkit</a> <a href="https://quiz.propertyhub.net/" target="_blank" rel="noopener noreferrer" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Investment Readiness Quiz</a> <a href="https://podcast.propertyhub.net/" target="_blank" rel="noopener noreferrer" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Podcast</a> <a href="https://www.youtube.com/propertyhubuk" target="_blank" rel="noopener noreferrer" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">YouTube</a> <a href="/books/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Books</a> <a href="/university/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Free Courses</a> <a href="/webinar/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Webinar</a> <a href="/ai/" class="block py-2 text-[13px] text-text-secondary hover:text-coral transition-colors duration-150">Rob AI</a> </div> </div> <div class="pt-3"> <a href="/free-tools/" class="btn btn--primary btn--xs nav-cta w-full justify-center py-3" data-analytics-cta="true" data-cta-name="get_free_toolkit" data-cta-location="mobile_menu" data-business-area="tools">Get the free toolkit</a> </div> <div class="mt-5 pt-5 border-t border-border-light"> <div class="grid grid-cols-3 gap-2 mb-5"> <a href="/about/" class="text-center py-2 text-[13px] font-medium text-text-secondary hover:text-coral transition-colors duration-150">About</a> <a href="/contact/" class="text-center py-2 text-[13px] font-medium text-text-secondary hover:text-coral transition-colors duration-150">Contact</a> <a href="/jobs/" class="text-center py-2 text-[13px] font-medium text-text-secondary hover:text-coral transition-colors duration-150">Jobs</a> </div> <div class="flex items-center justify-center gap-5"> <a href="https://www.facebook.com/propertyhubuk/" target="_blank" rel="noopener noreferrer" class="text-text-tertiary hover:text-text-primary transition-colors duration-150" aria-label="Facebook"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
94<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"></path></svg> </a> <a href="https://www.instagram.com/propertyhubuk/" target="_blank" rel="noopener noreferrer" class="text-text-tertiary hover:text-text-primary transition-colors duration-150" aria-label="Instagram"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z"></path></svg> </a> <a href="https://www.linkedin.com/company/thepropertyhub" target="_blank" rel="noopener noreferrer" class="text-text-tertiary hover:text-text-primary transition-colors duration-150" aria-label="LinkedIn"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"></path></svg> </a> <a href="https://www.youtube.com/propertyhubuk" target="_blank" rel="noopener noreferrer" class="text-text-tertiary hover:text-text-primary transition-colors duration-150" aria-label="YouTube"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"></path></svg> </a> </div> </div> </div> </header> <!-- Search overlay (outside header â header's backdrop-filter creates a containing block that traps fixed children) --> <div id="search-overlay" role="dialog" aria-modal="true" aria-label="Search Property Hub" class="hidden fixed inset-0 z-[100] bg-charcoal/50 backdrop-blur-sm overflow-y-auto"> <div class="max-w-2xl mx-auto mt-24 mb-12 px-4"> <div class="bg-white rounded-[12px] shadow-elevated overflow-hidden"> <div class="flex items-center gap-3 p-6 border-b border-border-light focus-within:border-coral transition-colors duration-150"> <svg class="w-5 h-5 text-text-tertiary flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
94<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg> <input id="search-input" type="text" aria-label="Search Property Hub" placeholder="Search Property Hub..." autocomplete="off" class="w-full text-[18px] font-light text-text-primary placeholder:text-text-tertiary outline-none"> <button id="search-close" class="p-1 text-text-tertiary hover:text-text-primary transition-colors duration-150" aria-label="Close search"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg> </button> </div> <div id="search-results" aria-live="polite" class="max-h-[60vh] overflow-y-auto"></div> </div> </div> </div>
94<script type="module" src="/_astro/Header.astro_astro_type_script_index_0_lang.PZKu0m98.js"></script>
94 <main id="main-content" class="pt-16 sm:pt-20" data-astro-cid-kh7btl4r> <!-- HERO SECTION --> <section class="pt-28 lg:pt-36 pb-16 lg:pb-24 bg-background-warm relative overflow-hidden surface-editorial" data-astro-cid-kh7btl4r> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 relative z-[1]" data-astro-cid-kh7btl4r> <div class="lg:grid lg:grid-cols-2 lg:gap-16 items-center" data-astro-cid-kh7btl4r> <!-- Left: hero video --> <div class="mb-10 lg:mb-0 reveal" data-reveal data-astro-cid-kh7btl4r> <div class="rounded-[16px] overflow-hidden shadow-card" data-astro-cid-kh7btl4r> <div style="position:relative; width:1px; min-width:100%; padding-bottom:56.25%;" data-astro-cid-kh7btl4r> <iframe allow="autoplay" class="spotlightr" allowtransparency="true" style="width:1px; min-width:100%; height:100%; position:absolute;" allowfullscreen="true" src="https://videos.cdn.spotlightr.com/watch/MjAwMTk4Mw==?fallback=true" frameborder="0" scrolling="no" name="videoPlayer" title="About Property Hub" data-astro-cid-kh7btl4r></iframe> </div> </div> </div> <!-- Right: headline + intro text --> <div class="reveal" data-reveal style="transition-delay: 0.15s;" data-astro-cid-kh7btl4r> <div class="w-16 h-px bg-coral mb-8" data-astro-cid-kh7btl4r></div> <h1 class="font-serif text-[36px] sm:text-[44px] lg:text-[52px] text-text-primary leading-[1.05] tracking-[-0.02em]" data-astro-cid-kh7btl4r> 95Building a property portfolio takes two things most people don't have: <span class="text-coral italic" data-astro-cid-kh7btl4r>knowledge, and time.</span> </h1> <p class="mt-6 sm:mt-8 text-[18px] text-text-secondary font-light leading-[1.7]" data-astro-cid-kh7btl4r> 96That's why we built two sides to Property Hub: education for people who want to do it themselves, and a done-with-you service for people who'd rather not. 97</p> </div> </div> </div> </section> <!-- WHAT WE BELIEVE --> <section class="py-24 lg:py-32 bg-surface relative overflow-hidden surface-editorial" data-astro-cid-kh7btl4r> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 relative z-[1]" data-astro-cid-kh7btl4r> <div class="lg:grid lg:grid-cols-[390px_1fr] lg:gap-8" data-astro-cid-kh7btl4r> <div class="reveal" data-reveal data-astro-cid-kh7btl4r> <p class="text-coral text-[12px] font-medium uppercase tracking-[0.12em] mb-3" data-astro-cid-kh7btl4r>Our philosophy</p> <h2 class="font-serif text-[32px] sm:text-[40px] lg:text-[52px] text-text-primary leading-[1.1] tracking-[-0.02em]" data-astro-cid-kh7btl4r> 98What we believe 99</h2> </div> <div class="mt-6 lg:mt-0 reveal" data-reveal style="transition-delay: 0.1s;" data-astro-cid-kh7btl4r> <div class="space-y-5" data-astro-cid-kh7btl4r> <p class="text-[18px] text-text-primary font-medium leading-[1.7]" data-astro-cid-kh7btl4r> 100True property wealth isn't built from rental income – it's built from owning quality assets long enough for compounding to do the work. 101</p> <p class="text-[18px] text-text-secondary font-light leading-[1.7]" data-astro-cid-kh7btl4r> 102This belief shapes everything we do. Our <a href="/books/" class="text-coral hover:underline transition-colors duration-150" data-astro-cid-kh7btl4r>books</a>, <a href="https://podcast.propertyhub.net/" target="_blank" rel="noopener noreferrer" class="text-coral hover:underline transition-colors duration-150" data-astro-cid-kh7btl4r>podcast</a> and <a href="/youtube/" class="text-coral hover:underline transition-colors duration-150" data-astro-cid-kh7btl4r>YouTube</a> channel exist to help people set clearer goals, choose the right strategy, and build a portfolio that performs over time. <a href="/invest/" class="text-coral hover:underline transition-colors duration-150" data-astro-cid-kh7btl4r>Our investment service</a> is designed for people who understand this but don't have time to execute it themselves. 103</p> <p class="text-[18px] text-text-secondary font-light leading-[1.7]" data-astro-cid-kh7btl4r> 104We're not for everyone. If you enjoy the hands-on side of property, you'll find our approach frustrating. If you're looking for a quick flip, we're the wrong partner. But if you want to build long-term financial security, independence and a legacy, you're in the right place. 105</p> </div> </div> </div> </div> </section> <!-- HOW WE WORK â dark section --> <section class="py-24 lg:py-32 bg-charcoal relative overflow-hidden" data-astro-cid-kh7btl4r> <!-- Radial glows --> <div class="absolute inset-0 pointer-events-none" style="background: radial-gradient(ellipse at 15% 80%, rgba(255, 81, 81, 0.06), transparent 50%), radial-gradient(ellipse at 85% 20%, rgba(201, 169, 110, 0.04), transparent 50%);" data-astro-cid-kh7btl4r></div> <!-- Grain --> <div class="absolute inset-0 pointer-events-none" style="background-image: var(--grain); background-repeat: repeat; background-size: 256px 256px; opacity: 0.04; mix-blend-mode: soft-light;" data-astro-cid-kh7btl4r></div> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 relative z-[1]" data-astro-cid-kh7btl4r> <div class="text-center mb-14 reveal" data-reveal data-astro-cid-kh7btl4r> <p class="text-coral text-[12px] font-medium uppercase tracking-[0.12em] mb-3" data-astro-cid-kh7btl4r>Our process</p> <h2 class="font-serif text-[32px] sm:text-[40px] lg:text-[52px] text-white leading-[1.1] tracking-[-0.02em]" data-astro-cid-kh7btl4r>
106How we work 107</h2> </div> <div class="grid grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8 reveal-stagger" data-reveal-stagger data-astro-cid-kh7btl4r> <div class="text-center" data-astro-cid-kh7btl4r> <h3 class="text-[20px] sm:text-[24px] font-medium text-white mb-2" data-astro-cid-kh7btl4r>Search the market</h3> <div class="w-8 h-[2px] bg-coral mx-auto mb-5" data-astro-cid-kh7btl4r></div> <p class="text-[16px] text-white/70 font-light leading-[1.7]" data-astro-cid-kh7btl4r>We use our exclusive relationships with developers – FTSE-listed housebuilders and major regional players – to secure properties before they reach the open market.</p> </div> <div class="text-center" data-astro-cid-kh7btl4r> <h3 class="text-[20px] sm:text-[24px] font-medium text-white mb-2" data-astro-cid-kh7btl4r>Negotiate the deal</h3> <div class="w-8 h-[2px] bg-coral mx-auto mb-5" data-astro-cid-kh7btl4r></div> <p class="text-[16px] text-white/70 font-light leading-[1.7]" data-astro-cid-kh7btl4r>Because we're buying at volume and can move quickly, we negotiate discounts that aren't available to individual buyers – securing an average 11% off the market value.</p> </div> <div class="text-center" data-astro-cid-kh7btl4r> <h3 class="text-[20px] sm:text-[24px] font-medium text-white mb-2" data-astro-cid-kh7btl4r>Present our research</h3> <div class="w-8 h-[2px] bg-coral mx-auto mb-5" data-astro-cid-kh7btl4r></div> <p class="text-[16px] text-white/70 font-light leading-[1.7]" data-astro-cid-kh7btl4r>When a development matches our criteria, we share it with clients: location, pricing, rental projections, the full picture. You do your own research and due diligence.</p> </div> <div class="text-center" data-astro-cid-kh7btl4r> <h3 class="text-[20px] sm:text-[24px] font-medium text-white mb-2" data-astro-cid-kh7btl4r>Own the process</h3> <div class="w-8 h-[2px] bg-coral mx-auto mb-5" data-astro-cid-kh7btl4r></div> <p class="text-[16px] text-white/70 font-light leading-[1.7]" data-astro-cid-kh7btl4r>If you decide to proceed, we coordinate the financing and legals and get it ready for tenants to move in.</p> </div> </div> <!-- Quote --> <div class="mt-16 pt-14 text-center border-t border-white/10 reveal" data-reveal data-astro-cid-kh7btl4r> <p class="max-w-4xl mx-auto text-[20px] sm:text-[28px] font-medium text-white leading-[1.2]" data-astro-cid-kh7btl4r> 108We do the work, but you're in control: you pay us nothing until we've found you something you love. 109</p> <div class="mt-8 flex justify-center" data-astro-cid-kh7btl4r> <div class="w-12 h-[2px] bg-coral" data-astro-cid-kh7btl4r></div> </div> </div> </div> </section> <!-- WHAT WE'VE BUILT â timeline --> <section class="py-24 lg:py-32 bg-background-warm relative overflow-hidden surface-editorial" data-astro-cid-kh7btl4r> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 relative z-[1]" data-astro-cid-kh7btl4r> <div class="max-w-[720px] mb-16 lg:mb-20 reveal" data-reveal data-astro-cid-kh7btl4r> <div class="w-16 h-px bg-coral mb-8" data-astro-cid-kh7btl4r></div> <p class="text-coral text-[12px] font-medium uppercase tracking-[0.12em] mb-3" data-astro-cid-kh7btl4r>Track record</p> <h2 class="font-serif text-[32px] sm:text-[44px] lg:text-[52px] text-text-primary leading-[1.05] tracking-[-0.02em] mb-6" data-astro-cid-kh7btl4r> 110What we've built 111</h2> <p class="text-[18px] text-text-primary font-medium leading-[1.7] mb-4" data-astro-cid-kh7btl4r> 112We've been teaching property investment for as long as we've been doing it. Most people who benefit from our expertise will never pay us anything – and that's fine. 113</p> <p class="text-[18px] text-text-secondary font-light leading-[1.7]" data-astro-cid-kh7btl4r> 114But it does mean that when someone works with us, they've usually spent months or years understanding our approach. They know whether we're right for them before the first conversation. 115</p> </div> <!-- Horizontal timeline --> <div class="relative reveal" data-reveal style="transition-delay: 0.15s;" data-astro-cid-kh7btl4r> <!-- Scroll container for mobile, static grid on desktop --> <div class="timeline-track overflow-x-auto lg:overflow-visible pb-6 lg:pb-0" data-astro-cid-kh7btl4r> <div class="timeline-inner relative min-w-[900px] lg:min-w-0 lg:grid lg:grid-cols-7 flex" data-astro-cid-kh7btl4r> <!-- Timeline axis --> <div class="absolute left-0 right-0 top-[62px] h-px bg-border-light" aria-hidden="true" data-astro-cid-kh7btl4r></div> <div class="absolute left-0 top-[62px] h-px bg-coral" aria-hidden="true" style="width: 100%; opacity: 0.25;" data-astro-cid-kh7btl4r></div> <!-- Milestone: 2013 â PH founded --> <div class="timeline-node relative flex-1 lg:col-span-1 px-4 lg:px-2 pt-0" data-astro-cid-kh7btl4r> <div class="text-[14px] font-serif text-coral mb-2" data-astro-cid-kh7btl4r>2013</div> <div class="h-[28px] flex items-center justify-start" data-astro-cid-kh7btl4r> <div class="w-3 h-3 rounded-full bg-coral shadow-[0_0_0_4px_rgba(255,81,81,0.15)]" data-astro-cid-kh7btl4r></div> </div> <p class="mt-4 text-[14px] font-medium text-text-primary leading-snug" data-astro-cid-kh7btl4r>Property Hub founded</p> <p class="mt-1 text-[12px] text-text-tertiary font-light leading-[1.5]" data-astro-cid-kh7btl4r>Rob Bence & Rob Dix start teaching what they've learned investing their own money.</p> </div> <!-- Milestone: 2013 â podcast --> <div class="timeline-node relative flex-1 lg:col-span-1 px-4 lg:px-2 pt-0" data-astro-cid-kh7btl4r> <div class="text-[14px] font-serif text-coral mb-2" data-astro-cid-kh7btl4r>2013</div> <div class="h-[28px] flex items-center justify-start" data-astro-cid-kh7btl4r> <div class="w-3 h-3 rounded-full bg-coral shadow-[0_0_0_4px_rgba(255,81,81,0.15)]" data-astro-cid-kh7btl4r></div> </div> <p class="mt-4 text-[14px] font-medium text-text-primary leading-snug" data-astro-cid-kh7btl4r>The Property Podcast launches</p> <p class="mt-1 text-[12px] text-text-tertiary font-light leading-[1.5]" data-astro-cid-kh7btl4r>Now the UK's #1 property podcast, 100k+ downloads a month.</p> </div> <!-- Milestone: 2014 â Invest --> <div class="timeline-node relative flex-1 lg:col-span-1 px-4 lg:px-2 pt-0" data-astro-cid-kh7btl4r> <div class="text-[14px] font-serif text-coral mb-2" data-astro-cid-kh7btl4r>2014</div> <div class="h-[28px] flex items-center justify-start" data-astro-cid-kh7btl4r> <div class="w-3 h-3 rounded-full bg-coral shadow-[0_0_0_4px_rgba(255,81,81,0.15)]" data-astro-cid-kh7btl4r></div> </div> <p class="mt-4 text-[14px] font-medium text-text-primary leading-snug" data-astro-cid-kh7btl4r>Property Hub Invest launches</p> <p class="mt-1 text-[12px] text-text-tertiary font-light leading-[1.5]" data-astro-cid-kh7btl4r>The done-with-you service begins sourcing for the first cohort of clients.</p> </div> <!-- Milestone: 2014 â first book --> <div class="timeline-node relative flex-1 lg:col-span-1 px-4 lg:px-2 pt-0" data-astro-cid-kh7btl4r> <div class="text-[14px] font-serif text-coral mb-2" data-astro-cid-kh7btl4r>2014</div> <div class="h-[28px] flex items-center justify-start" data-astro-cid-kh7btl4r> <div class="w-3 h-3 rounded-full bg-coral shadow-[0_0_0_4px_rgba(255,81,81,0.15)]" data-astro-cid-kh7btl4r></div> </div> <p class="mt-4 text-[14px] font-medium text-text-primary leading-snug" data-astro-cid-kh7btl4r>First book published</p> <p class="mt-1 text-[12px] text-text-tertiary font-light leading-[1.5]" data-astro-cid-kh7btl4r>Now 140,000+ copies of Rob's books sold worldwide.</p> </div> <!-- Milestone: 2018 --> <div class="timeline-node relative flex-1 lg:col-span-1 px-4 lg:px-2 pt-0" data-astro-cid-kh7btl4r> <div class="text-[14px] font-serif text-coral mb-2" data-astro-cid-kh7btl4r>2018</div> <div class="h-[28px] flex items-center justify-start" data-astro-cid-kh7btl4r> <div class="w-3 h-3 rounded-full bg-coral shadow-[0_0_0_4px_rgba(255,81,81,0.15)]" data-astro-cid-kh7btl4r></div> </div> <p class="mt-4 text-[14px] font-medium text-text-primary leading-snug" data-astro-cid-kh7btl4r>Property Pulse newsletter</p> <p class="mt-1 text-[12px] text-text-tertiary font-light leading-[1.5]" data-astro-cid-kh7btl4r>Now read weekly by 70,000+ UK property investors.</p> </div> <!-- Milestone: 2024 â Sunday Times --> <div class="timeline-node relative flex-1 lg:col-span-1 px-4 lg:px-2 pt-0" data-astro-cid-kh7btl4r> <div class="text-[14px] font-serif text-coral mb-2" data-astro-cid-kh7btl4r>2024</div> <div class="h-[28px] flex items-center justify-start" data-astro-cid-kh7btl4r> <div class="w-3 h-3 rounded-full bg-coral shadow-[0_0_0_4px_rgba(255,81,81,0.15)]" data-astro-cid-kh7btl4r></div> </div> <p class="mt-4 text-[14px] font-medium text-text-primary leading-snug" data-astro-cid-kh7btl4r>Sunday Times column</p> <p class="mt-1 text-[12px] text-text-tertiary font-light leading-[1.5]" data-astro-cid-kh7btl4r>Rob Dix becomes a weekly columnist for The Sunday Times.</p> </div> <!-- Milestone: today --> <div class="timeline-node relative flex-1 lg:col-span-1 px-4 lg:px-2 pt-0" data-astro-cid-kh7btl4r> <div class="text-[14px] font-serif text-coral mb-2" data-astro-cid-kh7btl4r>Today</div> <div class="h-[28px] flex items-center justify-start" data-astro-cid-kh7btl4r> <div class="w-3.5 h-3.5 rounded-full bg-coral shadow-[0_0_0_5px_rgba(255,81,81,0.18)] timeline-pulse" data-astro-cid-kh7btl4r></div> </div> <p class="mt-4 text-[14px] font-medium text-text-primary leading-snug" data-astro-cid-kh7btl4r>35+ team in Manchester</p> <p class="mt-1 text-[12px] text-text-tertiary font-light leading-[1.5]" data-astro-cid-kh7btl4r>Acquisitions, legal, research, client support – all under one roof.</p> </div> </div> </div> <!-- Mobile hint --> <p class="text-[12px] text-text-tertiary font-light text-center mt-4 lg:hidden" data-astro-cid-kh7btl4r>← Scroll to explore →</p> </div> </div> </section> <!-- TYPOGRAPHIC MOMENT --> <section class="bg-charcoal relative overflow-hidden" data-astro-cid-kh7btl4r> <div class="absolute inset-0 pointer-events-none" style="background: radial-gradient(ellipse 60% 80% at 20% 50%, rgba(255, 81, 81, 0.09) 0%, transparent 55%), radial-gradient(ellipse 50% 60% at 85% 50%, rgba(201, 169, 110, 0.05) 0%, transparent 50%);" data-astro-cid-kh7btl4r></div> <div class="absolute inset-0 pointer-events-none" style="background-image: var(--grain); background-repeat: repeat; background-size: 256px 256px; opacity: 0.04; mix-blend-mode: soft-light;" data-astro-cid-kh7btl4r></div> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 py-24 lg:py-36 relative z-[1]" data-astro-cid-kh7btl4r> <div class="reveal" data-reveal data-astro-cid-kh7btl4r> <p class="text-coral text-[12px] font-medium uppercase tracking-[0.12em] mb-8" data-astro-cid-kh7btl4r>Last year alone</p> <p class="font-serif text-white leading-[0.9] tracking-[-0.04em]" style="font-size: clamp(80px, 14vw, 200px);" data-astro-cid-kh7btl4r> 116£100m+ 117</p> <p class="text-[18px] sm:text-[22px] text-white/70 font-light mt-8 max-w-xl leading-[1.5]" data-astro-cid-kh7btl4r> 118of UK property acquired on behalf of our investors. 119</p> </div> </div> </section> <!-- WHO WE ARE --> <section class="py-24 lg:py-32 bg-surface relative overflow-hidden surface-editorial" data-astro-cid-kh7btl4r> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 relative z-[1]" data-astro-cid-kh7btl4r> <div class="max-w-3xl reveal" data-reveal data-astro-cid-kh7btl4r> <p class="text-coral text-[12px] font-medium uppercase tracking-[0.12em] mb-3" data-astro-cid-kh7btl4r>The team</p> <h2 class="font-serif text-[32px] sm:text-[40px] lg:text-[52px] text-text-primary leading-[1.1] tracking-[-0.02em]" data-astro-cid-kh7btl4r> 120Who we are 121</h2> <p class="mt-5 text-[18px] text-text-secondary font-light leading-[1.7]" data-astro-cid-kh7btl4r> 122We're a Manchester-based team of 35+ across acquisitions, legal coordination, research and client support. When you work with us, you're working with people who spend their days evaluating developments, negotiating with developers, and handling the complexity so you don't have to. 123</p> </div> <!-- Team carousel --> <div class="mt-14 relative" id="team-carousel" data-astro-cid-kh7btl4r> <div class="overflow-hidden" id="team-track-wrapper" data-astro-cid-kh7btl4r> <div class="flex gap-8 transition-transform duration-500 ease-out" id="team-track" style="will-change: transform;" data-astro-cid-kh7btl4r> <div class="flex-shrink-0 w-[300px] sm:w-[380px]" data-astro-cid-kh7btl4r> <div class="bg-surface rounded-[12px] overflow-hidden border border-border-light transition-[transform,box-shadow,border-color] duration-250 hover:shadow-card hover:-translate-y-1 hover:border-coral/20" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> <div class="aspect-[4/3] overflow-hidden bg-background" data-astro-cid-kh7btl4r> <img src="/images/team/rob-bence-headshot.png" alt="Rob Bence" class="w-full h-full object-cover object-[center_20%]" loading="lazy" data-astro-cid-kh7btl4r> </div> <div class="p-5 sm:p-6" data-astro-cid-kh7btl4r> <h3 class="text-lg font-medium text-text-primary" data-astro-cid-kh7btl4r>Rob Bence</h3>
123 <p class="text-sm text-coral font-medium mt-1" data-astro-cid-kh7btl4r>Co-founder</p> <p class="text-sm text-text-secondary font-light leading-relaxed mt-3" data-astro-cid-kh7btl4r>Built Property Hub into a business facilitating over £100m in annual property transactions.</p> </div> </div> </div><div class="flex-shrink-0 w-[300px] sm:w-[380px]" data-astro-cid-kh7btl4r> <div class="bg-surface rounded-[12px] overflow-hidden border border-border-light transition-[transform,box-shadow,border-color] duration-250 hover:shadow-card hover:-translate-y-1 hover:border-coral/20" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> <div class="aspect-[4/3] overflow-hidden bg-background" data-astro-cid-kh7btl4r> <img src="/images/team/rob-dix.jpg" alt="Rob Dix" class="w-full h-full object-cover object-[center_20%]" loading="lazy" data-astro-cid-kh7btl4r> </div> <div class="p-5 sm:p-6" data-astro-cid-kh7btl4r> <h3 class="text-lg font-medium text-text-primary" data-astro-cid-kh7btl4r>Rob Dix</h3> <p class="text-sm text-coral font-medium mt-1" data-astro-cid-kh7btl4r>Co-founder & Author</p> <p class="text-sm text-text-secondary font-light leading-relaxed mt-3" data-astro-cid-kh7btl4r>Author of seven best-selling books, co-founder, and an unashamed property geek.</p> </div> </div> </div><div class="flex-shrink-0 w-[300px] sm:w-[380px]" data-astro-cid-kh7btl4r> <div class="bg-surface rounded-[12px] overflow-hidden border border-border-light transition-[transform,box-shadow,border-color] duration-250 hover:shadow-card hover:-translate-y-1 hover:border-coral/20" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> <div class="aspect-[4/3] overflow-hidden bg-background" data-astro-cid-kh7btl4r> <img src="/images/team/ben-speaker.jpg" alt="Tracey Jones" class="w-full h-full object-cover object-[center_20%]" loading="lazy" data-astro-cid-kh7btl4r> </div> <div class="p-5 sm:p-6" data-astro-cid-kh7btl4r> <h3 class="text-lg font-medium text-text-primary" data-astro-cid-kh7btl4r>Tracey Jones</h3> <p class="text-sm text-coral font-medium mt-1" data-astro-cid-kh7btl4r>Managing Director</p> <p class="text-sm text-text-secondary font-light leading-relaxed mt-3" data-astro-cid-kh7btl4r>Leads our strategy, performance and delivery - balancing business growth with high-quality execution.</p> </div> </div> </div><div class="flex-shrink-0 w-[300px] sm:w-[380px]" data-astro-cid-kh7btl4r> <div class="bg-surface rounded-[12px] overflow-hidden border border-border-light transition-[transform,box-shadow,border-color] duration-250 hover:shadow-card hover:-translate-y-1 hover:border-coral/20" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> <div class="aspect-[4/3] overflow-hidden bg-background" data-astro-cid-kh7btl4r> <img src="/images/team/jenny-portrait.jpg" alt="Sam Smith" class="w-full h-full object-cover object-[center_20%]" loading="lazy" data-astro-cid-kh7btl4r> </div> <div class="p-5 sm:p-6" data-astro-cid-kh7btl4r> <h3 class="text-lg font-medium text-text-primary" data-astro-cid-kh7btl4r>Sam Smith</h3> <p class="text-sm text-coral font-medium mt-1" data-astro-cid-kh7btl4r>Director of Investments & Partnerships</p> <p class="text-sm text-text-secondary font-light leading-relaxed mt-3" data-astro-cid-kh7btl4r>Leads the sourcing and evaluation of new developments, shaping the investment opportunities we bring to market.</p> </div> </div> </div><div class="flex-shrink-0 w-[300px] sm:w-[380px]" data-astro-cid-kh7btl4r> <div class="bg-surface rounded-[12px] overflow-hidden border border-border-light transition-[transform,box-shadow,border-color] duration-250 hover:shadow-card hover:-translate-y-1 hover:border-coral/20" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> <div class="aspect-[4/3] overflow-hidden bg-background" data-astro-cid-kh7btl4r> <img src="/images/team/sophie-portrait.jpg" alt="Zoe Cairney" class="w-full h-full object-cover object-[center_20%]" loading="lazy" data-astro-cid-kh7btl4r> </div> <div class="p-5 sm:p-6" data-astro-cid-kh7btl4r> <h3 class="text-lg font-medium text-text-primary" data-astro-cid-kh7btl4r>
123Zoe Cairney</h3> <p class="text-sm text-coral font-medium mt-1" data-astro-cid-kh7btl4r>Sales Progression Manager</p> <p class="text-sm text-text-secondary font-light leading-relaxed mt-3" data-astro-cid-kh7btl4r>Responsible for our client experience: from reservation to completion, keeping purchases moving and on track.</p> </div> </div> </div> </div> </div> <!-- Carousel nav buttons --> <button id="team-prev" class="absolute left-0 top-[140px] sm:top-[180px] -translate-x-3 sm:-translate-x-6 w-12 h-12 sm:w-14 sm:h-14 rounded-full bg-coral flex items-center justify-center text-white hover:bg-coral-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coral active:scale-95 transition-[background-color,transform] duration-200 z-10" aria-label="Previous team member" data-astro-cid-kh7btl4r> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5" data-astro-cid-kh7btl4r> <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" data-astro-cid-kh7btl4r></path> </svg> </button> <button id="team-next" class="absolute right-0 top-[140px] sm:top-[180px] translate-x-3 sm:translate-x-6 w-12 h-12 sm:w-14 sm:h-14 rounded-full bg-coral flex items-center justify-center text-white hover:bg-coral-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coral active:scale-95 transition-[background-color,transform] duration-200 z-10" aria-label="Next team member" data-astro-cid-kh7btl4r> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5" data-astro-cid-kh7btl4r> <path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" data-astro-cid-kh7btl4r></path> </svg> </button> </div> </div> </section> <!-- WE'RE GROWING â dark section --> <section class="py-24 lg:py-32 bg-charcoal relative overflow-hidden" data-astro-cid-kh7btl4r> <!-- Radial glows --> <div class="absolute inset-0 pointer-events-none" style="background: radial-gradient(ellipse at 20% 50%, rgba(255, 81, 81, 0.06), transparent 50%), radial-gradient(ellipse at 80% 50%, rgba(201, 169, 110, 0.04), transparent 50%);" data-astro-cid-kh7btl4r></div> <!-- Grain --> <div class="absolute inset-0 pointer-events-none" style="background-image: var(--grain); background-repeat: repeat; background-size: 256px 256px; opacity: 0.04; mix-blend-mode: soft-light;" data-astro-cid-kh7btl4r></div> <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 text-center relative z-[1] reveal" data-reveal data-astro-cid-kh7btl4r> <h2 class="font-serif text-[32px] sm:text-[40px] text-white leading-[1.1] tracking-[-0.02em]" data-astro-cid-kh7btl4r> 124We're growing. 125</h2> <p class="mt-4 text-[18px] text-white/70 font-light leading-[1.7]" data-astro-cid-kh7btl4r> 126If you're interested in joining a winning team, check out our current vacancies below. 127</p> <a href="/jobs/" class="inline-block mt-8 px-8 py-[14px] bg-coral text-white font-medium text-[16px] rounded-[8px] shadow-coral-cta hover:bg-coral-hover hover:shadow-coral-hover hover:-translate-y-[1px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-coral transition-[transform,background-color,box-shadow] duration-250" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> 128View our current vacancies 129</a> </div> </section> <!-- WHAT'S NEXT --> <section class="py-24 lg:py-32 bg-background-warm relative overflow-hidden surface-editorial" data-astro-cid-kh7btl4r> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 relative z-[1]" data-astro-cid-kh7btl4r> <div class="text-center mb-12 reveal" data-reveal data-astro-cid-kh7btl4r> <p class="text-coral text-[12px] font-medium uppercase tracking-[0.12em] mb-3" data-astro-cid-kh7btl4r>Get started</p> <h2 class="font-serif text-[32px] sm:text-[40px] text-text-primary leading-[1.15] tracking-[-0.015em]" data-astro-cid-kh7btl4r> 130What's next? 131</h2> <p class="mt-4 text-[18px] text-text-secondary font-light leading-[1.7] max-w-2xl mx-auto" data-astro-cid-kh7btl4r> 132If you've read this far, you're probably in one of two camps: 133</p> </div> <div class="grid md:grid-cols-2 gap-8 reveal-stagger" data-reveal-stagger data-astro-cid-kh7btl4r> <!-- Learn CTA â light card --> <div class="bg-surface rounded-[12px] border border-border-light p-8 transition-[transform,box-shadow,border-color] duration-250 hover:shadow-card hover:-translate-y-1 hover:border-coral/20" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> <div class="text-center" data-astro-cid-kh7btl4r> <img src="/images/pages/property-pulse-laptop.png" alt="Property Pulse newsletter on laptop" class="w-full h-auto mb-4" loading="lazy" data-astro-cid-kh7btl4r> <div class="mt-2" data-astro-cid-kh7btl4r> <svg class="w-8 h-8 mx-auto text-coral" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-kh7btl4r><path d="M12 3L1 9l4 2.18v6L12 21l7-3.82v-6l2-1.09V17h2V9L12 3zm
1336.82 6L12 12.72 5.18 9 12 5.28 18.82 9zM17 15.99l-5 2.73-5-2.73v-3.72L12 15l5-2.73v3.72z" data-astro-cid-kh7btl4r></path></svg> </div> <p class="text-coral text-[12px] font-medium uppercase tracking-[0.12em] mt-3 mb-2" data-astro-cid-kh7btl4r>Free Resources</p> <h3 class="text-[24px] font-medium text-text-primary" data-astro-cid-kh7btl4r>You might want to keep learning</h3> <p class="mt-3 text-[16px] text-text-secondary font-light leading-[1.7]" data-astro-cid-kh7btl4r> 134In which case, our free weekly newsletter is the best place to start. Market commentary, expert insights, and lessons from arranging hundreds of transactions every year. 135</p> <div class="mt-8" data-astro-cid-kh7btl4r> <a href="/pulse/" class="inline-flex items-center px-6 py-3 bg-transparent text-text-primary font-medium text-[16px] rounded-[8px] border-[1.5px] border-border hover:border-text-primary hover:bg-background hover:-translate-y-[1px] transition-[transform,border-color,background-color] duration-250" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> 136Sign up for free 137</a> </div> </div> </div> <!-- Invest CTA â premium dark card --> <div class="bg-charcoal rounded-[16px] p-8 relative overflow-hidden transition-[transform,box-shadow] duration-250 hover:shadow-elevated hover:-translate-y-1" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> <!-- Radial glows --> <div class="absolute inset-0 pointer-events-none" style="background: radial-gradient(ellipse at 15% 80%, rgba(255, 81, 81, 0.06), transparent 50%), radial-gradient(ellipse at 85% 20%, rgba(201, 169, 110, 0.04), transparent 50%);" data-astro-cid-kh7btl4r></div> <div class="absolute inset-0 pointer-events-none" style="background-image: var(--grain); background-repeat: repeat; background-size: 256px 256px; opacity: 0.04; mix-blend-mode: soft-light;" data-astro-cid-kh7btl4r></div> <div class="relative z-[1] text-center" data-astro-cid-kh7btl4r> <img src="/images/pages/ph-invest-laptop.png" alt="Property Hub Invest on laptop" class="w-full h-auto mb-4" loading="lazy" data-astro-cid-kh7btl4r> <div class="mt-2" data-astro-cid-kh7btl4r> <svg class="w-8 h-8 mx-auto text-warm-gold" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-kh7btl4r><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" data-astro-cid-kh7btl4r></path></svg> </div> <p class="text-warm-gold text-[12px] font-medium uppercase tracking-[0.12em] mt-3 mb-2" data-astro-cid-kh7btl4r>Managed Service</p> <h3 class="text-[24px] font-medium text-white" data-astro-cid-kh7btl4r>You might be ready to talk about a portfolio</h3> <p class="mt-3 text-[16px] text-white/75 font-light leading-[1.7]" data-astro-cid-kh7btl4r> 138Book a free strategy call and we'll take the time to figure out together whether this approach makes sense for you and your goals. 139</p> <div class="mt-8" data-astro-cid-kh7btl4r> <a href="/invest/" class="inline-flex items-center px-6 py-3 bg-coral text-white font-medium text-[16px] rounded-[8px] shadow-coral-cta hover:bg-coral-hover hover:shadow-coral-hover hover:-translate-y-[1px] transition-[transform,background-color,box-shadow] duration-250" style="transition-timing-function: cubic-bezier(0.16, 1, 0.3, 1);" data-astro-cid-kh7btl4r> 140Book a call 141</a> </div> </div> </div> </div> </div> </section> </main> <footer class="bg-charcoal border-t border-white/10 py-16 lg:py-20 relative overflow-hidden" data-astro-cid-sz7xmlte> <!-- Top accent line --> <div class="absolute top-0 left-0 right-0 h-[2px]" style="background: linear-gradient(90deg, #FF5151 0%, transparent 100%);" data-astro-cid-sz7xmlte></div> <!-- Radial glows --> <div class="absolute inset-0 pointer-events-none" style="background: radial-gradient(ellipse at 15% 50%, rgba(255, 81, 81, 0.06), transparent 50%), radial-gradient(ellipse at 85% 20%, rgba(201, 169, 110, 0.04), transparent 50%);" data-astro-cid-sz7xmlte></div> <!-- Grain --> <div class="absolute inset-0 pointer-events-none" style="background-image: var(--grain); background-repeat: repeat; background-size: 256px 256px; opacity: 0.04; mix-blend-mode: soft-light;" data-astro-cid-sz7xmlte></div> <div class="max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8 relative z-[1]" data-astro-cid-sz7xmlte> <div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-10 lg:gap-12" data-astro-cid-sz7xmlte> <div data-astro-cid-sz7xmlte> <a href="/" class="inline-block" data-astro-cid-sz7xmlte> <img src="/property-hub-logo.svg" alt="Property Hub" class="h-[56px] w-auto" data-astro-cid-sz7xmlte> </a> <div class="flex gap-4 mt-7" data-astro-cid-sz7xmlte> <a href="https://www.facebook.com/propertyhubuk/" target="_blank" rel="noopener noreferrer" class="text-white/70 hover:text-white active:text-white active:scale-95 [touch-action:manipulation] transition-[transform,color] duration-150" aria-label="Facebook" data-astro-cid-sz7xmlte> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-sz7xmlte><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" data-astro-cid-sz7xmlte></path></svg> </a> <a href="https://www.instagram.com/propertyhubuk/" target="_blank" rel="noopener noreferrer" class="text-white/70 hover:text-white active:text-white active:scale-95 [touch-action:manipulation] transition-[transform,color] duration-150" aria-label="Instagram" data-astro-cid-sz7xmlte> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-sz7xmlte><path d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.
141047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z" data-astro-cid-sz7xmlte></path></svg> </a> <a href="https://www.linkedin.com/company/thepropertyhub" target="_blank" rel="noopener noreferrer" class="text-white/70 hover:text-white active:text-white active:scale-95 [touch-action:manipulation] transition-[transform,color] duration-150" aria-label="LinkedIn" data-astro-cid-sz7xmlte> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-sz7xmlte><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" data-astro-cid-sz7xmlte></path></svg> </a> <a href="https://www.youtube.com/propertyhubuk" target="_blank" rel="noopener noreferrer" class="text-white/70 hover:text-white active:text-white active:scale-95 [touch-action:manipulation] transition-[transform,color] duration-150" aria-label="YouTube" data-astro-cid-sz7xmlte> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-sz7xmlte><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" data-astro-cid-sz7xmlte></path></svg> </a> </div> </div> <div data-astro-cid-sz7xmlte> <p class="footer-label text-[11px] text-white/60 mb-5" data-astro-cid-sz7xmlte>Build Your Portfolio</p> <ul class="space-y-3" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte><a href="/invest/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Invest With Us</a></li> <li data-astro-cid-sz7xmlte><a href="/invest/book-a-consultation/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Book a Consultation</a></li> <li data-astro-cid-sz7xmlte><a href="/invest/case-studies/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Past Deals & Case Studies</a></li> </ul> </div> <div data-astro-cid-sz7xmlte> <p class="footer-label text-[11px] text-white/60 mb-5" data-astro-cid-sz7xmlte>Read & Learn</p> <ul class="space-y-3" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte><a href="/learn/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Start Here</a></li> <li data-astro-cid-sz7xmlte><a href="/guides/getting-started/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Investing Guides</a></li> <li data-astro-cid-sz7xmlte><a href="/news/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Latest News</a></li> <li data-astro-cid-sz7xmlte><a href="/free-tools/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Investor Toolkit</a></li> </ul> </div> <div data-astro-cid-sz7xmlte> <p class="footer-label text-[11px] text-white/60 mb-5" data-astro-cid-sz7xmlte>Company</p> <ul class="space-y-3" data-astro-cid-sz7xmlte> <li data-astro-cid-sz7xmlte><a href="/about/" class="footer-link text-[13px] hover:text-white transition-colors duration-150 text-coral" data-astro-cid-sz7xmlte>About</a></li> <li data-astro-cid-sz7xmlte><a href="/contact/" class="footer-link text-[13px] hover:text-white transition-colors duration-150 text-white/70" data-astro-cid-sz7xmlte>Contact</a></li> <li data-astro-cid-sz7xmlte><a href="/jobs/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Jobs</a></li> <li data-astro-cid-sz7xmlte><a href="/developers/" class="footer-link text-[13px] hover:text-white transition-colors duration-150 text-white/70" data-astro-cid-sz7xmlte>Developers</a></li> <li data-astro-cid-sz7xmlte><a href="/charities/" class="footer-link text-[13px] text-white/70 hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Charities</a></li> </ul> </div> </div> <!-- Legal strip --> <div class="mt-14 pt-8 border-t border-white/10 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between" data-astro-cid-sz7xmlte> <div class="space-y-1" data-astro-cid-sz7xmlte> <p class="footer-link text-white/60 text-[12px] leading-[1.5]" data-astro-cid-sz7xmlte>Property Hub © 2026 All rights reserved. Property Hub Ltd. Registered in England and Wales.</p> <p class="footer-link text-white/60 text-[12px] leading-[1.5]" data-astro-cid-sz7xmlte>Property Hub Invest Ltd (07495608). 1st Floor B, 117-119 Portland Street, Manchester, M1 6ED.</p> </div> <nav class="flex flex-wrap gap-x-6 gap-y-2 flex-shrink-0" data-astro-cid-sz7xmlte> <a href="/privacy-policy/" class="footer-link text-white/70 text-[13px] hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Privacy Policy</a> <a href="/terms-conditions/" class="footer-link text-white/70 text-[13px] hover:text-white transition-colors duration-150" data-astro-cid-sz7xmlte>Terms & Conditions</a> </nav> </div> </div> </footer>
141<script> 142 (function () { 143 const STORAGE_KEY = 'ph_attribution_v1'; 144 const UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content']; 145 // Ad-platform click IDs, plus our own short-link id (appended by the /go/* 146 // edge function). Captured + stored like UTMs (first-touch wins within the 147 // session) so they survive navigation before a form is submitted. 148 const CLICK_ID_KEYS = ['gclid', 'gbraid', 'wbraid', 'fbclid', 'msclkid', 'ph_link_id']; 149 150 function readCookie(name) { 151 const prefix = name + '='; 152 const part = document.cookie 153 .split(';') 154 .map((value) => value.trim()) 155 .find((value) => value.indexOf(prefix) === 0); 156 return part ? decodeURIComponent(part.slice(prefix.length)) : ''; 157 } 158 159 function hasAdvertisingConsent() { 160 const consent = readCookie('cookieyes-consent'); 161 return /(?:^|,)advertisement:(?:yes|true)(?:,|$)/i.test(consent); 162 } 163 164 function readStored() { 165 try { 166 const raw = sessionStorage.getItem(STORAGE_KEY); 167 return raw ? JSON.parse(raw) : null; 168 } catch (e) { 169 return null; 170 } 171 } 172 173 function writeStored(data) { 174 try { 175 sessionStorage.setItem(STORAGE_KEY, JSON.stringify(data)); 176 } catch (e) { 177 /* sessionStorage unavailable â fail silently */ 178 } 179 } 180 181 function captureFromUrl() { 182 const params = new URLSearchParams(window.location.search); 183 const stored = readStored() || {}; 184 185 let updated = false; 186 UTM_KEYS.concat(CLICK_ID_KEYS).forEach((key) => { 187 const val = params.get(key); 188 if (val && !stored[key]) { 189 stored[key] = val; 190 if (key === 'fbclid') stored.fbclid_captured_at = Date.now(); 191 updated = true; 192 } 193 }); 194 195 if (!stored.landing_page) { 196 stored.landing_page = window.location.pathname + window.location.search; 197 updated = true; 198 } 199 if (!stored.referrer) { 200 stored.referrer = document.referrer || ''; 201 updated = true; 202 } 203 204 if (updated) writeStored(stored); 205 return stored; 206 } 207 208 function generateSubmissionId() { 209 try { 210 if (window.crypto && typeof window.crypto.randomUUID === 'function') { 211 return window.crypto.randomUUID(); 212 } 213 } catch (e) { 214 /* fall through to manual generation */ 215 } 216 // RFC4122-ish fallback for older browsers. 217 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 218 var r = (Math.random() * 16) | 0; 219 var v = c === 'x' ? r : (r & 0x3) | 0x8; 220 return v.toString(16); 221 }); 222 } 223 224 function injectHidden(form, name, value) { 225 // Set the value on an EXISTING input if there is one, otherwise create it. 226 // The attribution fields are also declared as static empty hidden inputs in 227 // LeadForm so that Netlify registers them in the form's build-time schema â 228 // Netlify only records fields it saw in the static HTML, and silently drops 229 // POSTed fields it didn't (this is why utm_* / referrer / submitted_url were 230 // missing from submissions). So here we must UPDATE the existing input's 231 // value rather than bail, then fall back to creating one for any form that 232 // doesn't declare it statically. 233 const val = value == null ? '' : value; 234 const existing = form.querySelector('input[name="' + name + '"]'); 235 if (existing) { 236 existing.value = val; 237 return; 238 } 239 const input = document.createElement('input'); 240 input.type = 'hidden'; 241 input.name = name; 242 input.value = val; 243 form.appendChild(input); 244 } 245 246 function attachToForms(attribution) { 247 document.querySelectorAll('form[data-ph-form]').forEach((form) => { 248 form.addEventListener( 249 'submit', 250 function () { 251 const fresh = readStored() || attribution; 252 UTM_KEYS.forEach((key) => injectHidden(form, key, fresh[key] || '')); 253 CLICK_ID_KEYS.forEach((key) => injectHidden(form, key, fresh[key] || '')); 254 const advertisingConsent = hasAdvertisingConsent(); 255 const fbp = advertisingConsent ? readCookie('_fbp') : ''; 256 const cookieFbc = advertisingConsent ? readCookie('_fbc') : ''; 257 const derivedFbc = 258 advertisingConsent && fresh.fbclid 259 ? 'fb.1.' + String(fresh.fbclid_captured_at || Date.now()) + '.' + fresh.fbclid 260 : ''; 261 injectHidden(form, 'fbp', fbp); 262 injectHidden(form, 'fbc', cookieFbc || derivedFbc); 263 injectHidden(form, 'advertising_consent', advertisingConsent ? 'true' : 'false'); 264 injectHidden(form, 'landing_page', fresh.landing_page || ''); 265 injectHidden(form, 'referrer', fresh.referrer || ''); 266 injectHidden(form, 'submitted_url', window.location.href); 267 injectHidden(form, 'submission_id', generateSubmissionId()); 268 }, 269 { capture: true } 270 ); 271 }); 272 } 273 274 const attribution = captureFromUrl(); 275 276 if (document.readyState === 'loading') { 277 document.addEventListener('DOMContentLoaded', function () { 278 attachToForms(attribution); 279 }); 280 } else { 281 attachToForms(attribution); 282 } 283 })(); 284</script>
284
284<script> 285 (function () { 286 var PARDOT_HANDLER_URL = 'https://go.propertyhub.net/l/641323/2026-02-16/h8hb71'; 287 288 function postToPardot(form) { 289 try { 290 var emailInput = form.querySelector('input[type="email"], input[name="email"]'); 291 if (!emailInput || !emailInput.value) return; 292 293 var body = new URLSearchParams(); 294 body.append('email', emailInput.value); 295 296 var firstNameInput = form.querySelector('input[name="first_name"]'); 297 if (firstNameInput && firstNameInput.value) { 298 body.append('first_name', firstNameInput.value); 299 } 300 var lastNameInput = form.querySelector('input[name="last_name"]'); 301 if (lastNameInput && lastNameInput.value) { 302 body.append('last_name', lastNameInput.value); 303 } 304 305 // Fire-and-forget. mode:'no-cors' avoids CORS preflight; credentials:'include' 306 // ensures the Pardot tracking cookie travels with the request so Pardot can 307 // stitch the anonymous visitor to this prospect's email. 308 fetch(PARDOT_HANDLER_URL, { 309 method: 'POST', 310 body: body, 311 mode: 'no-cors', 312 credentials: 'include', 313 }); 314 } catch (e) { 315 /* never block the real form submission */ 316 } 317 } 318 319 // Some forms are not investor lead-gen (e.g. the developer/B2B enquiry form) 320 // and must NOT push contacts into the investor Pardot/Salesforce. Opt out 321 // with data-no-pardot on the form. 322 document.querySelectorAll('form[data-ph-form]:not([data-no-pardot])').forEach(function (form) { 323 form.addEventListener( 324 'submit', 325 function () { 326 postToPardot(form); 327 }, 328 { capture: true } 329 ); 330 }); 331 })(); 332</script>
332
332<script type="module" src="/_astro/PhoneCountryInput.astro_astro_type_script_index_0_lang.CZn1wpMa.js"></script>
332
332<script> 333 (function () { 334 function appendToUrl(rawUrl, params) { 335 try { 336 const url = new URL(rawUrl, window.location.origin); 337 params.forEach(([key, value]) => { 338 if (value && !url.searchParams.has(key)) { 339 url.searchParams.set(key, value); 340 } 341 }); 342 const isAbsolute = /^https?:\/\//i.test(rawUrl); 343 return isAbsolute ? url.toString() : url.pathname + url.search + url.hash; 344 } catch (e) { 345 return rawUrl; 346 } 347 } 348 349 function buildRedirectUrl(form, formData) { 350 // The browser-visible success destination is deliberately separate from 351 // the form action: Netlify requires form actions to remain root-relative, 352 // while Invest submissions redirect to an external Calendly URL. 353 const action = form.dataset.successUrl || form.getAttribute('action') || '/'; 354 const params = []; 355 // Never put submitted form fields in a redirect URL. URLs are copied 356 // into browser history, request logs and analytics page locations. Only 357 // the approved campaign fields are safe to carry to the destination. 358 ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].forEach((key) => { 359 const val = formData.get(key); 360 if (val) params.push([key, String(val)]); 361 }); 362 return appendToUrl(action, params); 363 } 364 365 function showThankYou(form) { 366 const selector = form.dataset.successTarget; 367 const target = selector 368 ? document.querySelector(selector) 369 : (form.parentElement && form.parentElement.querySelector('[data-thank-you]')) || null; 370 form.hidden = true; 371 if (target) { 372 target.hidden = false; 373 target.scrollIntoView({ behavior: 'smooth', block: 'center' }); 374 } 375 } 376 377 const TRACKED_OUTCOMES = new Set([ 378 'generate_lead', 379 'developer_lead', 380 'subscriber_signup', 381 'webinar_registration', 382 ]); 383 384 function safeValue(formData, key) { 385 const value = formData.get(key); 386 return typeof value === 'string' ? value : ''; 387 } 388 389 function formLocation(form) { 390 if (form.dataset.formLocation) return form.dataset.formLocation; 391 const section = form.closest('section[id]'); 392 return section ? section.id : 'inline'; 393 } 394 395 function trackingPayload(form, formData, eventName) { 396 const advertisingConsent = safeValue(formData, 'advertising_consent') === 'true'; 397 return { 398 event: eventName, 399 analytics_event: safeValue(formData, 'analytics_event'), 400 submission_id: safeValue(formData, 'submission_id'), 401 event_id: safeValue(formData, 'submission_id'), 402 form_name: form.getAttribute('name') || '', 403 form_type: safeValue(formData, 'form_type'), 404 form_location: formLocation(form), 405 form_label: safeValue(formData, 'form_label'), 406 signup_type: safeValue(formData, 'signup_type'), 407 asset_id: safeValue(formData, 'asset_id'), 408 asset_name: safeValue(formData, 'asset_name'), 409 asset_type: safeValue(formData, 'asset_type'), 410 webinar_id: 411 safeValue(formData, 'analytics_event') === 'webinar_registration' 412 ? safeValue(formData, 'asset_id') 413 : '', 414 provider: safeValue(formData, 'provider'), 415 advertising_consent: advertisingConsent, 416 // Meta browser/server identifiers are only present after advertising 417 // consent. They are deliberately kept out of the data layer otherwise. 418 fbp: advertisingConsent ? safeValue(formData, 'fbp') : '', 419 fbc: advertisingConsent ? safeValue(formData, 'fbc') : '', 420 source_page: safeValue(formData, 'source_page') || window.location.pathname, 421 }; 422 } 423 424 function pushOutcome(form, formData, eventName, onComplete) { 425 const analyticsEvent = safeValue(formData, 'analytics_event'); 426 if (!TRACKED_OUTCOMES.has(analyticsEvent)) { 427 onComplete(); 428 return; 429 } 430 431 window.dataLayer = window.dataLayer || []; 432 let completed = false; 433 const finish = function () { 434 if (completed) return; 435 completed = true; 436 window.clearTimeout(fallback); 437 onComplete(); 438 }; 439 const fallback = window.setTimeout(finish, 1200); 440 window.dataLayer.push({ 441 ...trackingPayload(form, formData, eventName), 442 eventCallback: finish, 443 eventTimeout: 1000, 444 }); 445 } 446 447 // Inline submission error, announced to assistive tech via role="alert". 448 // Created lazily per form, re-used on repeat failures, cleared on retry. 449 function clearFormError(form) { 450 const el = form.querySelector('[data-form-error]'); 451 if (el) el.hidden = true; 452 } 453 454 function showFormError(form) { 455 let el = form.querySelector('[data-form-error]'); 456 if (!el) { 457 el = document.createElement('div'); 458 el.setAttribute('data-form-error', ''); 459 el.setAttribute('role', 'alert'); 460 el.style.cssText = 461 'margin-top:12px;padding:12px 16px;border-radius:8px;font-size:14px;' + 462 'background:rgba(255,81,81,0.10);border:1px solid rgba(255,81,81,0.45);color:inherit;'; 463 const submitBtn = form.querySelector('button[type="submit"]'); 464 if (submitBtn && submitBtn.parentElement === form) { 465 submitBtn.insertAdjacentElement('afterend', el); 466 } else { 467 form.appendChild(el); 468 } 469 } 470 el.textContent = 471 "Sorry, something went wrong sending your details. Check your connection and try again â nothing has been submitted.";
472 el.hidden = false; 473 } 474 475 document.querySelectorAll('form[data-ph-form]').forEach((form) => { 476 form.addEventListener('submit', async (event) => { 477 event.preventDefault(); 478 clearFormError(form); 479 const submitBtn = form.querySelector('button[type="submit"]'); 480 if (submitBtn) submitBtn.disabled = true; 481 482 // Netlify uses a field named `title` for the submission summary shown in 483 // its dashboard. Populate it from the submitted email here, before 484 // FormData snapshots the form. This field is sent only to Netlify; the 485 // analytics payload below is explicitly allow-listed and excludes it. 486 const emailInput = form.querySelector('input[type="email"], input[name="email"]'); 487 const titleInput = form.querySelector('input[name="title"]'); 488 if (emailInput instanceof HTMLInputElement && titleInput instanceof HTMLInputElement) { 489 titleInput.value = emailInput.value.trim(); 490 } 491 492 const formData = new FormData(form); 493 const body = new URLSearchParams(); 494 formData.forEach((value, key) => { 495 body.append(key, typeof value === 'string' ? value : ''); 496 }); 497 498 // Netlify routes an AJAX-submitted form by a `form-name` field in the 499 // POST body (the form's `name` attribute alone isn't enough once we 500 // intercept and fetch() ourselves). Without it Netlify returns 404. 501 const netlifyFormName = form.getAttribute('name'); 502 if (netlifyFormName) body.set('form-name', netlifyFormName); 503 504 // Normalise EVERY checkbox to a single true/false (applies to all forms: 505 // newsletter consent, sunday-times publish_consent, survey unsubscribe 506 // boxes). HTML omits an unticked box entirely, so set an explicit value 507 // from the checkbox state so downstream (Salesforce booleans, Zaps) gets 508 // a clean value. Do NOT pair a checkbox with a hidden default of the 509 // same name: a native (no-JS) submit then sends both ("false,true") and 510 // Salesforce rejects the enquiry. Replaces the old "on"/absent. 511 form.querySelectorAll('input[type="checkbox"][name]').forEach((cb) => { 512 body.set(cb.name, cb.checked ? 'true' : 'false'); 513 }); 514 515 try { 516 const res = await fetch('/', { 517 method: 'POST', 518 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 519 body: body.toString(), 520 }); 521 if (!res.ok) throw new Error('HTTP ' + res.status); 522 523 pushOutcome(form, formData, 'ph_form_success', function () { 524 const isInline = form.hasAttribute('data-inline-success'); 525 if (isInline) { 526 showThankYou(form); 527 } else { 528 window.location.href = buildRedirectUrl(form, formData); 529 } 530 }); 531 } catch (err) { 532 console.error('Form submission failed:', err); 533 const analyticsEvent = safeValue(formData, 'analytics_event'); 534 if (TRACKED_OUTCOMES.has(analyticsEvent)) { 535 window.dataLayer = window.dataLayer || []; 536 window.dataLayer.push({ 537 ...trackingPayload(form, formData, 'ph_form_error'), 538 error_type: err instanceof Error && /^HTTP /.test(err.message) ? 'http_error' : 'network_error', 539 http_status: 540 err instanceof Error && /^HTTP \d+$/.test(err.message) 541 ? err.message.slice(5) 542 : '', 543 }); 544 } 545 if (submitBtn) submitBtn.disabled = false; 546 showFormError(form); 547 } 548 }); 549 }); 550 551 document.addEventListener('click', function (event) { 552 const target = event.target; 553 const link = target instanceof Element ? target.closest('a[data-analytics-cta]') : null; 554 if (!link) return; 555 window.dataLayer = window.dataLayer || []; 556 window.dataLayer.push({ 557 event: 'ph_cta_click', 558 cta_name: link.dataset.ctaName || '', 559 cta_location: link.dataset.ctaLocation || 'unknown', 560 business_area: link.dataset.businessArea || 'general', 561 destination_url: link.getAttribute('href') || '', 562 }); 563 }); 564 })(); 565</script>
565
565<script> 566 (function () { 567 function attachEmailToQuizLinks() { 568 const params = new URLSearchParams(window.location.search); 569 const email = params.get('email') || params.get('Email'); 570 if (!email) return; 571 572 const links = document.querySelectorAll('a[href*="quiz.propertyhub.net"]:not([data-email-relayed])'); 573 links.forEach(function (link) { 574 try { 575 const url = new URL(link.href); 576 url.searchParams.set('email', email); 577 link.href = url.toString(); 578 link.dataset.emailRelayed = '1'; 579 } catch (e) { 580 /* malformed href â skip */ 581 } 582 }); 583 } 584 585 if (document.readyState === 'loading') { 586 document.addEventListener('DOMContentLoaded', attachEmailToQuizLinks); 587 } else { 588 attachEmailToQuizLinks(); 589 } 590 591 const observer = new MutationObserver(attachEmailToQuizLinks); 592 if (document.body) { 593 observer.observe(document.body, { childList: true, subtree: true }); 594 } else { 595 document.addEventListener('DOMContentLoaded', function () { 596 observer.observe(document.body, { childList: true, subtree: true }); 597 }); 598 } 599 })(); 600</script>
600 <!-- n8n chat widget â themed to match Property Hub. 601 Maps the widget's CSS variables to the site's brand tokens. Because 602 these reference var(--color-coral) etc. and the widget mounts inside 603 <body>, invest pages (.theme-invest) automatically render it in purple. -->
603<script type="module"> 604 // Kill switch for the n8n chat widget. Set to false to disable loading 605 // the bot site-wide (e.g. while its n8n workflow is being fixed before 606 // go-live); flip back to true to restore it â no other change needed. 607 // The whole loader below is left intact so re-enabling is a one-line flip. 608 const CHAT_ENABLED = false; 609 610 // The chat bundle is large and secondary to the page's main task. Load it 611 // only after the visitor interacts, rather than competing with LCP and 612 // parsing 1.9MB of JavaScript during an untouched initial page load. 613 let chatLoadPromise; 614 615 async function loadPropertyHubChat() { 616 if (chatLoadPromise) return chatLoadPromise; 617 618 chatLoadPromise = (async () => { 619 const [{ createChat }] = await Promise.all([ 620 import(/* @vite-ignore */ "https://cdn.jsdelivr.net/npm/@n8n/chat/dist/chat.bundle.es.js"), 621 loadChatStyles(), 622 ]); 623 624 createChat({ 625 webhookUrl: 626 "https://primary-production-86ea3.up.railway.app/webhook/d718b778-6558-4da9-96dc-cfcf5086e5a5/chat", 627 initialMessages: [ 628 "Hello! I'm here to answer your questions about PropertyHub. How can I help?", 629 ], 630 }); 631 632 const chatRoot = await waitForChatRoot(); 633 patchChatA11y(chatRoot); 634 observeChatA11y(chatRoot); 635 document.dispatchEvent(new CustomEvent("propertyhub:chat-ready")); 636 })().catch((error) => { 637 chatLoadPromise = undefined; 638 throw error; 639 }); 640 641 return chatLoadPromise; 642 } 643 644 function loadChatStyles() { 645 if (document.getElementById("propertyhub-chat-styles")) { 646 return Promise.resolve(); 647 } 648 649 return new Promise((resolve, reject) => { 650 const link = document.createElement("link"); 651 link.id = "propertyhub-chat-styles"; 652 link.rel = "stylesheet"; 653 link.href = "https://cdn.jsdelivr.net/npm/@n8n/chat/dist/style.css"; 654 link.onload = () => resolve(); 655 link.onerror = () => reject(new Error("Chat styles failed to load")); 656 document.head.appendChild(link); 657 }); 658 } 659 660 function waitForChatRoot() { 661 const existing = document.querySelector("#n8n-chat, .n8n-chat"); 662 if (existing) return Promise.resolve(existing); 663 664 return new Promise((resolve, reject) => { 665 const timeout = window.setTimeout(() => { 666 observer.disconnect(); 667 reject(new Error("Chat widget did not mount")); 668 }, 5000); 669 const observer = new MutationObserver(() => { 670 const root = document.querySelector("#n8n-chat, .n8n-chat"); 671 if (!root) return; 672 window.clearTimeout(timeout); 673 observer.disconnect(); 674 resolve(root); 675 }); 676 observer.observe(document.body, { childList: true, subtree: true }); 677 }); 678 } 679 680 // Accessibility patches for the n8n widget's own markup, which we can't 681 // configure. Two problems it ships with: 682 // 1. Its "Hi there! ð" greeting is an <h1>, so every page ends up with a 683 // second page-level heading (present even while the chat is closed). 684 // We can't swap the tag in place, so we demote it with ARIA: role 685 // "heading" at level 2 wins over the implicit <h1> level for 686 // assistive tech, leaving the page's real <h1> unique. 687 // 2. Its launcher is a bare <div>/SVG with no role or label, so keyboard 688 // users can't reach or activate it. We give it a button role, a name, 689 // and Enter/Space handling. 690 // The widget mounts asynchronously and re-renders on open/close, so we 691 // re-apply on every mutation rather than once. 692 function patchChatA11y(root) { 693 root.querySelectorAll("h1").forEach(function (h) { 694 h.setAttribute("role", "heading"); 695 h.setAttribute("aria-level", "2"); 696 }); 697 698 var toggle = root.querySelector(".chat-window-toggle, [class*='toggle']"); 699 if (toggle && toggle.tagName !== "BUTTON" && !toggle.dataset.a11yPatched) { 700 toggle.dataset.a11yPatched = "true"; 701 toggle.setAttribute("role", "button"); 702 toggle.setAttribute("tabindex", "0"); 703 toggle.setAttribute("aria-label", "Open chat"); 704 toggle.addEventListener("keydown", function (e) { 705 if (e.key === "Enter" || e.key === " ") { 706 e.preventDefault(); 707 toggle.click(); 708 } 709 }); 710 } 711 } 712 713 function observeChatA11y(root) { 714 new MutationObserver(() => patchChatA11y(root)).observe(root, { 715 childList: true, 716 subtree: true, 717 }); 718 } 719 720 window.loadPropertyHubChat = loadPropertyHubChat; 721 722 // Only wire up the interaction listeners that trigger chat loading when 723 // the kill switch is on. With CHAT_ENABLED = false the widget never loads 724 // and no bubble appears; everything above stays ready to run again. 725 if (CHAT_ENABLED) { 726 const intentEvents = ["pointerdown", "keydown", "scroll"]; 727 const handleFirstIntent = () => {
728 intentEvents.forEach((eventName) => 729 window.removeEventListener(eventName, handleFirstIntent), 730 ); 731 loadPropertyHubChat().catch(() => { 732 // Chat is progressive enhancement; navigation and forms must keep 733 // working if the third-party CDN or webhook is unavailable. 734 }); 735 }; 736 intentEvents.forEach((eventName) => 737 window.addEventListener(eventName, handleFirstIntent, { 738 once: true, 739 passive: true, 740 }), 741 ); 742 } 743 </script>
743 <!-- Chat-widget suppression (issue #36). 744 The n8n chat bubble is secondary to conversion, so we hide it in two 745 situations: 746 1. While any element flagged `[data-suppress-chat]` is present AND 747 actually shown â e.g. the mobile sticky CTA bar, which slides in 748 from the bottom corner and would otherwise overlap the bubble. 749 2. While any lead form is (even partially) in the viewport â the 750 bubble is a distraction at the moment we want a form fill. 751 Suppression toggles the `chat-suppressed` class on <html>; the CSS in 752 the style block above does the actual hiding. 753 754 This script is deliberately self-contained and does NOT depend on the 755 chat widget having loaded: if the CDN module is blocked the class 756 still toggles harmlessly, and nothing throws. It also works no matter 757 the merge order of the sticky-CTA-bar PR â it discovers suppressors 758 from the DOM rather than referencing the bar directly. -->
758<script> 759 (function () { 760 var html = document.documentElement; 761 762 // --- form suppressors --------------------------------------------- 763 // Every real lead form on the site renders a <form> (LeadForm.astro 764 // and a handful of inline page forms). We observe all of them except 765 // ones that are explicitly opted out or never rendered. 766 var formsIntersecting = new Set(); 767 768 // --- generic [data-suppress-chat] suppressors --------------------- 769 // The mobile CTA bar (and any future element) flags itself with 770 // `data-suppress-chat`. The bar slides in/out, so presence alone isn't 771 // enough: we only suppress while such an element is actually shown. 772 // "Shown" = on screen (IntersectionObserver) AND not visually hidden 773 // (display/visibility/opacity 0, or data-suppress-chat="false"/"off"). 774 // We watch both intersection and attribute/class changes so the bar 775 // toggling its visible state re-evaluates suppression. 776 var flagIntersecting = new Set(); 777 778 function flagIsActive(el) { 779 if (!flagIntersecting.has(el)) return false; 780 var val = (el.getAttribute("data-suppress-chat") || "").toLowerCase(); 781 if (val === "false" || val === "off" || val === "0") return false; 782 var cs = window.getComputedStyle(el); 783 if ( 784 cs.display === "none" || 785 cs.visibility === "hidden" || 786 parseFloat(cs.opacity) === 0 787 ) { 788 return false; 789 } 790 return true; 791 } 792 793 function update() { 794 var suppress = formsIntersecting.size > 0; 795 if (!suppress) { 796 // Only walk the flag set if no form already triggered suppression. 797 var flags = document.querySelectorAll("[data-suppress-chat]"); 798 for (var i = 0; i < flags.length; i++) { 799 if (flagIsActive(flags[i])) { 800 suppress = true; 801 break; 802 } 803 } 804 } 805 html.classList.toggle("chat-suppressed", suppress); 806 } 807 808 // IntersectionObserver shared by forms; threshold 0 = "even partially". 809 var io; 810 try { 811 io = new IntersectionObserver( 812 function (entries) { 813 entries.forEach(function (entry) { 814 var set = 815 entry.target.tagName === "FORM" 816 ? formsIntersecting 817 : flagIntersecting; 818 if (entry.isIntersecting) set.add(entry.target); 819 else set.delete(entry.target); 820 }); 821 update(); 822 }, 823 { threshold: 0 } 824 ); 825 } catch (e) { 826 // No IntersectionObserver (very old browser) â bail out quietly; 827 // the chat simply never gets suppressed, which is a safe default. 828 return; 829 } 830 831 function isHidden(el) { 832 // Skip forms that aren't actually visible (e.g. the honeypot row or 833 // a form inside a closed accordion) â they shouldn't suppress chat. 834 return !el.offsetParent && el.offsetWidth === 0 && el.offsetHeight === 0; 835 } 836 837 var watchedForms = new WeakSet(); 838 var watchedFlags = new WeakSet(); 839 840 function observeForms() { 841 document.querySelectorAll("form").forEach(function (form) { 842 if (watchedForms.has(form)) return; 843 if (form.hasAttribute("data-no-suppress-chat")) return; 844 if (isHidden(form)) return; 845 watchedForms.add(form); 846 io.observe(form); 847 }); 848 } 849 850 function observeFlags() { 851 document 852 .querySelectorAll("[data-suppress-chat]") 853 .forEach(function (el) { 854 if (watchedFlags.has(el)) return; 855 watchedFlags.add(el); 856 io.observe(el); 857 }); 858 } 859 860 function scan() { 861 observeForms(); 862 observeFlags(); 863 update(); 864 } 865 866 scan(); 867 868 // The CTA bar mounts/toggles after load and Astro view transitions can 869 // swap page content; a MutationObserver keeps our observers current and 870 // re-evaluates when a flagged element changes its class/attributes 871 // (e.g. the bar adding/removing `is-visible`). 872 try { 873 var mo = new MutationObserver(function (mutations) { 874 var needsRescan = false;
875 var needsUpdate = false; 876 mutations.forEach(function (m) { 877 if (m.type === "childList") needsRescan = true; 878 else if (m.type === "attributes") { 879 // A flagged element changed visibility-affecting attributes. 880 needsUpdate = true; 881 } 882 }); 883 if (needsRescan) scan(); 884 else if (needsUpdate) update(); 885 }); 886 mo.observe(document.body, { 887 childList: true, 888 subtree: true, 889 attributes: true, 890 attributeFilter: ["class", "style", "data-suppress-chat", "hidden"], 891 }); 892 } catch (e) { 893 /* MutationObserver unavailable â initial scan still applies. */ 894 } 895 896 document.addEventListener("astro:page-load", scan); 897 })(); 898 </script>
898 </body> </html>
898<script type="module">const s=document.getElementById("team-track"),r=document.getElementById("team-prev"),c=document.getElementById("team-next");if(s&&r&&c){let a=function(){const e=s.parentElement;if(!e)return 0;const i=Math.floor((e.offsetWidth+l)/d());return Math.max(0,f-i)},n=function(){const e=d();s.style.transform=`translateX(-${t*e}px)`;const i=a();r.style.opacity=t===0?"0.4":"1",c.style.opacity=t>=i?"0.4":"1"},t=0;const p=()=>window.innerWidth<640?300:380,l=32,d=()=>p()+l,f=s.children.length;r.addEventListener("click",()=>{t>0&&(t--,n())}),c.addEventListener("click",()=>{const e=a();t<e&&(t++,n())});let m=setInterval(()=>{const e=a();t<e?t++:t=0,n()},4e3);const o=s.parentElement;o&&(o.addEventListener("mouseenter",()=>clearInterval(m)),o.addEventListener("mouseleave",()=>{m=setInterval(()=>{const e=a();t<e?t++:t=0,n()},4e3)})),n(),window.addEventListener("resize",()=>{const e=a();t>e&&(t=e),n()})}</script>
898 <!-- Scroll reveal animations -->
898<script type="module">const s={threshold:.1,rootMargin:"0px 0px -40px 0px"},t=new IntersectionObserver(e=>{e.forEach(r=>{r.isIntersecting&&(r.target.classList.add("visible"),t.unobserve(r.target))})},s);document.querySelectorAll("[data-reveal]").forEach(e=>{t.observe(e)});const a=new IntersectionObserver(e=>{e.forEach(r=>{r.isIntersecting&&(r.target.classList.add("visible"),a.unobserve(r.target))})},s);document.querySelectorAll("[data-reveal-stagger]").forEach(e=>{a.observe(e)});</script>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.