Back to Property Insights
My retirement investment after a lifetime in buy-to-let
Industry News Pinned

My retirement investment after a lifetime in buy-to-let

Property118 · · 26 min read

Property118 My retirement investment after a lifetime in buy-to-let If you sold a rental property tomorrow, what would you do with the money? After selling several of mine, I still wanted a worthwhile income, but I was ready for fewer responsibilities. I wanted this money working for me without another minefield of licensing, safety certificates, deposit rules and looming landlord registration requirements, and without the potential for substantial fines or rent repayment orders if I got things wrong. To cut a long story short, I eventually invested in an equity release lender offering a 30-month corporate bond with a fixed annual coupon of 10%, payable quarterly. Those were the terms of my investment; terms available to others may differ. Years as a landlord had already taught me to assess risk. Rent arrears, unexpected repairs, taxation, legislation, and ever-changing mortgage rates and lending criteria were all familiar considerations. However, it was my background in commercial finance that helped me investigate a different way of earning income from the property sector. That’s why I chose to invest into a business providing specialist mortgages to older homeowners. Before investing, I examined its lending, funding arrangements and how it expected to repay my capital . Having experienced the 2008 financial crisis, I needed more than an attractive interest rate to feel comfortable. For me, the appeal was an agreed payment schedule, a business I understood and fewer day-to-day responsibilities. I only committed money I could leave invested for the full term, as there is no readily available market for exiting or trading the bond early. I also knew I was relying on the company to pay the interest and return my money. If it couldn’t, I could lose some or all of what I’d invested, and the Financial Services Compensation Scheme (FSCS) wouldn’t cover that loss or protect me. I was comfortable with that level of risk; I accept others might not be. There is no ‘one-size-fits-all’. The bottom line for me was this; after spending so many years building my property wealth, I wanted more time to enjoy what I had worked for. Putting some of that capital to work in a business I understood, with an agreed quarterly payment schedule that was outperforming my returns from rental property, suited the next stage of my life. To find out more, complete the form below to request a private introduction to the intermediary who arranged my investment. Your answers help them carry out initial eligibility checks and understand your enquiry. You do not need to have decided to invest. It is simply an opportunity to ask questions and obtain current information, without committing yourself. If you would like to be considered for a private introduction, please complete the sections below. Your answers help us understand whether this opportunity is likely to be appropriate for you before any investment-specific information is shared. Step 1 of 4 About you Full name * Email address * Telephone number * Country of residence * Country of tax residence * Next Your proposed investment Approximately how much are you considering investing? * Where would the capital come from? * Net proceeds from selling rental property Personal savings Proceeds from other investments Funds held within a company Other Is the capital currently available? * Yes Partly Not yet When are you likely to be ready? * Now Within three months Within six months More than six months from now I am researching at this stage Why does this type of investment interest you? * Please briefly explain what you are trying to achieve, such as replacing rental income, investing property sale proceeds, reducing the work associated with being a landlord, generating retirement income or diversifying your existing investments. Would you expect to need access to this capital during a 30-month term? * No Possibly Yes I am unsure Previous Next Initial high-net-worth eligibility check Which of these applied during your previous financial year? * My annual income was at least £100,000, excluding one-off pension withdrawals. My qualifying net assets were at least £250,000, excluding my main residence, pension assets and qualifying insurance rights. Neither test applies to me. Approximate annual income * Approximate qualifying net assets * Previous Next Your request I understand that this is a fixed-term, high-risk investment and that I could lose some or all of the money invested. I understand that Property118 does not provide regulated investment advice and has not assessed whether the investment is suitable for me. I confirm that the financial information provided above is accurate to the best of my knowledge. I understand that Property118 may receive a commercial introduction fee if I subsequently invest. I have read and agree to the Property118 privacy notice. Electronic signature * Type your full name to sign. Previous Request a private introduction (function(){ var uid = "crm-form-f0002f38"; var form = document.getElementById(uid + '-form'); var wrap = document.getElementById(uid); var msg = wrap.querySelector('.crm-message'); var totalPages = 4; var curPage = 0; // ── Name casing ────────────────────────────────────────────────────── // Tidy a name box as the visitor leaves it, so they are not staring at // "JOHN SMITH" in their own form. Deliberately cosmetic: the API runs // the same normalisation on submit and is the authority on what gets // stored, so a disagreement here is harmless. Kept in step with // packages/shared/src/names.ts. var NAME_PARTICLES = ' van von de del della der den di da dal du la le el bin ibn al dos das do ter ten '; var NAME_MACS = ' macdonald macintyre macleod macarthur macgregor macneil macpherson macrae mackinnon macqueen '; function nameUp(s){ return s.replace(/[a-z]/i, function(c){ return c.toUpperCase(); }); } function isParticle(w){ return NAME_PARTICLES.indexOf(' ' + w.toLowerCase() + ' ') >= 0; } function nameRecase(atom){ if (!/[a-z]/i.test(atom)) return atom; var dot = atom.charAt(atom.length - 1) === '.' ? '.' : ''; var core = dot ? atom.slice(0, -1) : atom; var lower = core.toLowerCase(); if (/^(?:II|III|IV|VI|VII|VIII|IX|XI|XII)$/.test(core.toUpperCase())) return core.toUpperCase() + dot; if (lower === 'jr' || lower === 'sr') return nameUp(lower) + dot; if (core.length === 1) return core.toUpperCase() + dot; var mc = /^mc([a-z]{2,})$/.exec(lower); if (mc) return 'Mc' + nameUp(mc[1]) + dot; if (NAME_MACS.indexOf(' ' + lower + ' ') >= 0) return 'Mac' + nameUp(lower.slice(3)) + dot; return nameUp(lower) + dot; } function nameWellFormed(atom){ // "Mccoll" has its leading capital but still wants McColl. Safe only // because "Mc" is unambiguous — "Mac" deliberately has no such rule. if (/^Mc[a-z]{2,}$/.test(atom)) return false; return /^(?:[A-Z][a-z]*|[A-Z][a-z]+[A-Z][A-Za-z]*|O[A-Z][a-z]+|[A-Z]{1,3}|[IVX]+)$/.test(atom); } function tidyName(value){ var v = (value || '').replace(/\s+/g, ' ').replace(/^ | $/g, ''); if (!v) return value; if (/[@\d,]|&[a-z]+;|&#|https?:|www\./i.test(v)) return value; // not a name var words = v.split(' '); var deliberate = words.every(function(w){ // A lone particle is not a particle — it is someone's name (Di, Al). if (words.length > 1 && isParticle(w)) return true; return w.split(/[-'\u2019.]/).filter(function(seg){ return /[a-z]/i.test(seg); }) .every(function(seg){ return nameWellFormed(seg); }); }); if (deliberate) return v; return words.map(function(w, i){ if (i > 0 && isParticle(w)) return w.toLowerCase(); return w.split(/([-'\u2019.])/).map(function(seg){ return /^[-'\u2019.]$/.test(seg) ? seg : nameRecase(seg); }).join(''); }).join(' '); } // ── Thousand separators ────────────────────────────────────────────── // Opt-in per field (data-thousands). Mirrors formatThousands() and the // caret helpers in the CRM's packages/shared/src/numbers.ts. The CRM // strips the separators again on submit, so storage is unaffected. function groupThousands(value){ var raw = String(value == null ? '' : value).replace(/,/g, ''); if (!raw) return ''; // More than one point is not a number to group: "5.000.000" became "5.000000". if (raw.indexOf('.') !== raw.lastIndexOf('.')) return raw; var neg = raw.charAt(0) === '-'; var body = neg ? raw.slice(1) : raw; var dot = body.indexOf('.'); var digits = function(x){ return x.replace(/[^0-9]/g, ''); }; var whole = digits(dot === -1 ? body : body.slice(0, dot)); var frac = dot === -1 ? null : digits(body.slice(dot + 1)); if (!whole && frac === null) return neg ? '-' : ''; var grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); return (neg ? '-' : '') + grouped + (frac === null ? '' : '.' + frac); } // Reposition by digit count, not character index: commas appear and // vanish to the left of the caret, and counting characters would throw // it to the end of the field on every keystroke. function caretAfterGrouping(formatted, digitsBefore){ if (digitsBefore s.lastIndexOf(',') ? '.' : ','; else if (dots + commas === 1) { var mark = dots ? '.' : ','; var bits = s.split(mark); point = bits[1].length === 3 && bits[0].length 2) return null; var digits = function(t){ return t.replace(/[.,]/g, ''); }; var n = Number((digits(parts[0]) || '0') + '.' + (digits(parts[1] || '') || '0')) * scale; if (!isFinite(n)) return null; n = Math.round(n * 100) / 100; return neg ? -n : n; } function crmWholeOf(n) { return n % 1 !== 0 && Math.abs(n) "1,600,000". Unreadable stays as typed. function crmTidyMoney(value) { var n = crmReadMoney(value); if (n === null) return value; var whole = crmWholeOf(n); return whole % 1 === 0 ? groupThousands(String(whole)) : String(whole); } function crmMoneyReading(value) { var text = String(value == null ? '' : value).trim(); if (!text) return ''; var n = crmReadMoney(text); if (n === null) return 'Enter an amount in pounds, e.g. 1,600,000'; var whole = crmWholeOf(n); var pounds = whole % 1 === 0 ? whole.toLocaleString('en-GB') : whole.toLocaleString('en-GB', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); var millions = Math.abs(whole) >= 1e6 ? ' (£' + Number((whole / 1e6).toFixed(2)).toLocaleString('en-GB') + ' million)' : ''; return 'Reads as £' + pounds + millions; } var crmWarnings = []; // What a money box reads as, and any sense check, shown under it. function crmMoneyNotes() { form.querySelectorAll('input[data-money="1"]').forEach(function(el){ var note = el.parentNode.querySelector('.crm-money-reading'); if (note) note.textContent = crmMoneyReading(el.value); }); crmWarnings.forEach(function(wf){ var el = form.querySelector('[name="' + wf.id + '"]'); var note = el ? el.parentNode.querySelector('.crm-money-warning') : null; if (!note) return; var msg = ''; var n = crmNumberAt(wf.id), b = wf.ofId ? crmNumberAt(wf.ofId) : null, ofW = wf.ofId ? crmWrapper(wf.ofId) : null; if (wf.below !== null && n !== null && isFinite(n) && n 0 && ofW && ofW.style.display !== 'none') { var pct = n / b * 100, what = '“' + wf.ofLabel + '”'; if (wf.max !== null && pct > wf.max) msg = 'Please check: this is ' + (wf.max === 100 ? 'more than ' : 'over ' + wf.max + '% of ') + what + '.'; else if (wf.min !== null && pct parseFloat(cmp); case 'lessthan': return parseFloat(val) [ ][ ]', so the prefix arm above // collects EVERY rendered row. Demanding all of them be filled means one blank // extra row - added by mistake, or rendered by settings.minRows - blocks Next and // Submit with a generic message on the wrapper. Only the first row is required. var firstRow = form.querySelector('[data-field-id="' + fld.id + '"] .crm-repeater-row'); if (firstRow) { reqEls = Array.prototype.filter.call(reqEls, function (el) { return firstRow.contains(el); }); } var toTest = reqEls.length ? reqEls : [els[0]]; return Array.prototype.every.call(toTest, function (el) { return (el.value || '').trim() !== ''; }); } var crmMinimums = [{"id":"4a3e202f-0865-4770-972d-cd0943ced15c","label":"Approximately how much are you considering investing?","min":1000,"max":null,"allowZero":true,"pct":null,"ofId":null,"ofLabel":null,"money":true},{"id":"d273ffd6-7082-49d6-bf24-92160a151ae9","label":"Approximate annual income","min":1000,"max":null,"allowZero":true,"pct":null,"ofId":null,"ofLabel":null,"money":true},{"id":"2427d562-0198-4721-8ba2-8f106ce7a9a3","label":"Approximate qualifying net assets","min":1000,"max":null,"allowZero":true,"pct":null,"ofId":null,"ofLabel":null,"money":true}]; // Mirrors the CRM's numberMinimumError, numberMaximumError and numberShareError (packages/shared/src/numbers.ts). function crmNumberAt(id) { var el = form.querySelector('[name="' + id + '"]'); if (el && el.getAttribute('data-money') === '1') { var m = crmReadMoney(el.value); return m === null ? null : crmWholeOf(m); } var text = el ? String(el.value || '').replace(/,/g, '').trim() : ''; return text === '' ? null : Number(text); } function crmMinimumMessage(mf) { var mel = form.querySelector('[name="' + mf.id + '"]'); if (mf.money && mel && String(mel.value || '').trim() !== '' && crmReadMoney(mel.value) === null) { return mf.label + ' must be an amount in pounds, e.g. 1,600,000.'; } var n = crmNumberAt(mf.id); if (n === null || !isFinite(n)) return null; if (mf.min !== null && n mf.max) { return mf.label + ' must be at most ' + mf.max.toLocaleString('en-GB') + '.'; } if (mf.pct !== null) { var ofW = crmWrapper(mf.ofId); var b = crmNumberAt(mf.ofId); if (ofW && ofW.style.display !== 'none' && b !== null && isFinite(b) && b > 0) { var least = Math.ceil(b * mf.pct / 100); if (n = 0 ? (sel.options[sel.selectedIndex].text || '').trim() : ''; var vals = []; w.querySelectorAll('input[type=text], input[type=email], input[type=tel], input[type=url], input[type=number], input[type=date], textarea').forEach(function(i){ if (i.value) vals.push(i.value); }); return vals.join(' '); } function buildSummary() { var list = form.querySelector('.crm-summary-list'); if (!list) return; list.innerHTML = ''; form.querySelectorAll('.crm-page:not(.crm-summary-page) .crm-field[data-field-id]').forEach(function(w){ // Skip anything conditional logic has hidden, and anything with no // input of its own (html blocks, section headings). if (w.style.display === 'none') return; if (!w.querySelector('input, select, textarea')) return; var label = summaryLabel(w); if (!label) return; var row = document.createElement('div'); row.className = 'crm-summary-row'; var head = document.createElement('div'); head.className = 'crm-summary-head'; var txt = document.createElement('div'); txt.className = 'crm-summary-value'; var val = summaryText(w); txt.innerHTML = ' '; txt.querySelector('.crm-summary-label').textContent = label; var ans = txt.querySelector('.crm-summary-answer'); ans.textContent = val || 'Not answered'; if (!val) ans.className += ' crm-summary-empty'; var edit = document.createElement('button'); edit.type = 'button'; edit.className = 'crm-summary-edit'; edit.textContent = 'Edit'; head.appendChild(txt); head.appendChild(edit); row.appendChild(head); list.appendChild(row); edit.addEventListener('click', function(){ var home = w.parentNode, after = w.nextSibling; // Snapshot for Cancel, before anything is touched. var snap = []; w.querySelectorAll('input, select, textarea').forEach(function(i){ snap.push({ el: i, value: i.value, checked: i.checked }); }); head.style.display = 'none'; var box = document.createElement('div'); box.className = 'crm-summary-edit-box'; row.appendChild(box); box.appendChild(w); var actions = document.createElement('div'); actions.className = 'crm-summary-actions'; var ok = document.createElement('button'); ok.type = 'button'; ok.className = 'crm-summary-ok'; ok.textContent = 'OK'; var cancel = document.createElement('button'); cancel.type = 'button'; cancel.className = 'crm-summary-cancel'; cancel.textContent = 'Cancel'; actions.appendChild(ok); actions.appendChild(cancel); box.appendChild(actions); function restoreField() { if (after) home.insertBefore(w, after); else home.appendChild(w); box.parentNode.removeChild(box); head.style.display = ''; } ok.addEventListener('click', function(){ restoreField(); buildSummary(); }); cancel.addEventListener('click', function(){ snap.forEach(function(sv){ sv.el.value = sv.value; sv.el.checked = sv.checked; }); restoreField(); }); }); }); } form.querySelectorAll('.crm-next-btn').forEach(function(btn){ btn.addEventListener('click', function(){ var page = parseInt(btn.dataset.page); // Validate the current page's required fields (config-based, so // checkbox groups are caught too) before advancing. var badW = crmFirstInvalid(page); if (badW) { crmReportInvalid(badW); return; } showPage(page + 1); progNext(page + 1); }); }); form.querySelectorAll('.crm-prev-btn').forEach(function(btn){ btn.addEventListener('click', function(){ showPage(parseInt(btn.dataset.page) - 1); }); }); // ── Submit ──────────────────────────────────────────────────────────── var submitBtn = form.querySelector('button[type=submit]'); var btnText = submitBtn ? submitBtn.textContent : 'Submit'; var crmApiUrl = "https:\/\/crm-api.property118.com"; function collectFormData() { var data = {}; for (var j = 0; j [ ][ ]". // Group those flat keys into an array of row objects under the repeater // id. Plain fields, checkbox "[]" arrays and single-bracket composites // (name[first], address[city]) don't match the double-bracket pattern, so // ordinary submissions are unchanged. var _repRe = /^(.+?)\[(\d+)\]\[(.+)\]$/; var _repIds = {}; Object.keys( data ).forEach( function ( key ) { var m = key.match( _repRe ); if ( ! m ) { return; } var rid = m[1], row = parseInt( m[2], 10 ), sub = m[3]; _repIds[ rid ] = true; if ( ! Array.isArray( data[ rid ] ) ) { data[ rid ] = []; } if ( ! data[ rid ][ row ] || typeof data[ rid ][ row ] !== 'object' ) { data[ rid ][ row ] = {}; } data[ rid ][ row ][ sub ] = data[ key ]; delete data[ key ]; } ); Object.keys( _repIds ).forEach( function ( rid ) { if ( Array.isArray( data[ rid ] ) ) { data[ rid ] = data[ rid ].filter( function ( r ) { return r && typeof r === 'object'; } ); } } ); // GF auto-substituted {user_agent} / {referer} on hidden fields // at render time. We do the equivalent right before submit so // fields whose default value carries these placeholders // resolve to the browser's actual values rather than being // stored as literal "{user_agent}" / "{referer}" strings. // The last ARTICLE the visitor read (set client-side on post views by // P118_Article_Views). Used to attribute the enquiry to the article // even after navigating away or with a stripped/absent referer. var lastPost = ''; try { var lpm = document.cookie.match(/(?:^|;\s*)p118_last_post=([^;]+)/); if (lpm) lastPost = decodeURIComponent(lpm[1]); } catch (e) {} var subs = { '{user_agent}': navigator.userAgent || '', // Prefer the last article read; fall back to the (lossy) HTTP referer. '{referer}': lastPost || document.referrer || '', '{last_post}': lastPost || '', '{embed_url}': window.location.href || '', }; for (var name in data) { if (!data.hasOwnProperty(name)) continue; var v = data[name]; if (typeof v !== 'string') continue; for (var tag in subs) { if (v.indexOf(tag) !== -1) v = v.split(tag).join(subs[tag]); } data[name] = v; } // Agent/BDM attribution — read LIVE so it works even on a fully cached // page (the browser always sees the real URL + cookie). URL ?ataid=/?cid= // first, then the 30-day agent_id/cid cookies set by atat-tracking.php. var _qp = new URLSearchParams(window.location.search); var _ataid = _qp.get('ataid') || (document.cookie.match(/(?:^|;\s*)agent_id=([^;]+)/) || [])[1] || ''; var _cid = _qp.get('cid') || (document.cookie.match(/(?:^|;\s*)cid=([^;]+)/) || [])[1] || ''; if (_ataid) data.agent_id = decodeURIComponent(_ataid); if (_cid) data.bdm_id = decodeURIComponent(_cid); // Which page the form was actually on. Read live for the same reason // as the attribution above: on a cached page the server has no idea // which URL it is being served as, but the browser always does. data._sourceUrl = window.location.href; // …and what sent them to it. Read live for the same reason: a cached // page cannot know either, but the browser does. Blank when they // typed the address, used a bookmark, or came from an email client — // which is the honest answer, not a gap to be filled in server-side. data._referrerUrl = document.referrer || ''; // This browser's progress through a multi-page form is now sent. if (typeof progVisit !== 'undefined' && progVisit) data._visitId = progVisit; return data; } function uploadFiles(data) { var fileInputs = form.querySelectorAll('input[type=file][data-crm-file-field]'); var uploads = []; fileInputs.forEach(function(el) { if (!el.files || !el.files[0]) return; var fd = new FormData(); fd.append('file', el.files[0]); var fieldName = el.name; uploads.push( fetch(crmApiUrl + '/public/forms/' + "8faf069c-83f2-40f6-9218-9c8949fb14f8" + '/upload', { method: 'POST', body: fd }) .then(function(r) { if (!r.ok) throw new Error('File upload failed (' + r.status + ')'); return r.json(); }) .then(function(res) { if (res.path) data[fieldName] = res.path; else throw new Error(res.error || 'File upload failed'); }) ); }); return Promise.all(uploads).then(function() { return data; }); } var notSentMsg = 'Sorry, your answers did not reach us. Please check your connection and press Submit again.'; // The WordPress relay answered with something that isn't its JSON - a // Cloudflare challenge or a WordPress error page - so it never reached the // CRM, and r.json() on it was Safari's "The string did not match the // expected pattern". Send the answers straight to the CRM instead (an // overseas client lost a paid booking form this way, 30 Oct 2026). The // page goes in the body: a browser can't put a non-ASCII title in a // header. WordPress's own after-submit steps (member, newsletter) are // skipped for this one submission. function submitDirect(data) { if (!crmApiUrl) throw new Error(notSentMsg); var direct = Object.assign({}, data, { _embedUrl: "", _embedPostId: "0", _embedPostTitle: "" }); return fetch(crmApiUrl + '/public/forms/' + "8faf069c-83f2-40f6-9218-9c8949fb14f8" + '/submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(direct) }) .then(function(r){ return r.text(); }, function(){ throw new Error(notSentMsg); }) .then(function(t){ try { return JSON.parse(t); } catch (e) { throw new Error(notSentMsg); } }); } function submitFormData(data) { var body = new FormData(); body.append('action', 'p118_crm_submit'); body.append('form_id', "8faf069c-83f2-40f6-9218-9c8949fb14f8"); body.append('data', JSON.stringify(data)); // Embed-page context for GF-style merge tags ({embed_url}, // {embed_post:post_title}, {embed_post:ID}). Captured PHP-side // at render time, then echoed to JS so the submit fetch can // forward to V2 as request headers. body.append('embed_url', ""); body.append('embed_post_id', "0"); body.append('embed_post_title', ""); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: body, credentials: 'same-origin' }) .then(function(r){ return r.text(); }, function(){ throw new Error(notSentMsg); }) .then(function(t){ try { return JSON.parse(t); } catch (e) { return submitDirect(data); } }) .then(function(res){ var p = res.data || res; if (p && p.success) { if (typeof progDone === 'function') progDone(); if (p.confirmationType === 'form' && p.nextFormId) { return swapInNextForm(p.nextFormId, p.prefill || {}); } if (p.confirmationType === 'redirect' && p.confirmationRedirectUrl) { window.location.href = p.confirmationRedirectUrl; } else { form.style.display = 'none'; msg.className = 'crm-message success'; // Sent: the progress line says so, not "Step 6 of 6". var doneText = wrap.querySelector('.crm-progress-text'); if (doneText) doneText.textContent = 'Completed'; var doneFill = wrap.querySelector('.crm-progress-fill'); if (doneFill) doneFill.style.width = '100%'; msg.innerHTML = p.confirmationMessage || 'Thank you for your submission.'; // Carry the calculator's own results across. A calculator form // renders its figures into [data-iht-results] as the visitor // types; hiding the form hid those too, so the completion // screen went blank and the visitor lost what they had just // worked out. Nothing happens on forms without that element. var resultsEl = form.querySelector('[data-iht-results]'); if (resultsEl && resultsEl.innerHTML.trim()) { var carried = document.createElement('div'); carried.className = 'crm-message-results'; carried.innerHTML = resultsEl.innerHTML; msg.appendChild(carried); } // Download link for a generated report, present only when the // API filed the PDF before responding. Built through the DOM // rather than concatenated into innerHTML so the URL cannot // inject markup. if (p.reportDownloadUrl) { var dlWrap = document.createElement('p'); dlWrap.className = 'crm-report-download'; var dl = document.createElement('a'); dl.className = 'crm-report-button'; // Building through the DOM stops markup injection but not a // javascript: URL, which would run in this origin the moment // the submitter clicks the button. dl.href = /^https?:\/\//i.test(String(p.reportDownloadUrl)) ? p.reportDownloadUrl : '#'; dl.target = '_blank'; dl.rel = 'noopener noreferrer'; // The form's generator names its own button (e.g. a guide, not a report). dl.textContent = (typeof p.reportDownloadLabel === 'string' && p.reportDownloadLabel) ? p.reportDownloadLabel : 'Download your report (PDF)'; dlWrap.appendChild(dl); msg.appendChild(dlWrap); } msg.style.display = 'block'; if (msg.scrollIntoView) { msg.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } } else { throw new Error((p && p.error) || 'Submission failed.'); } }); } // Replace this whole form widget with another form, rendered server-side // with the carried-over values seeded in. Inline injected via // innerHTML won't run, so we re-create each script node to execute it // (this is what wires up the new form's submit / conditional logic). function swapInNextForm(nextFormId, prefill) { var rbody = new FormData(); rbody.append('action', 'p118_crm_render_form'); rbody.append('form_id', nextFormId); rbody.append('prefill', JSON.stringify(prefill || {})); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: rbody, credentials: 'same-origin' }) .then(function(r){ return r.json(); }) .then(function(res2){ var pd = res2.data || res2; if (!pd || !pd.html) { throw new Error((pd && pd.error) || 'Could not load the next form.'); } var frag = document.createElement('div'); frag.innerHTML = pd.html; var parent = wrap.parentNode; var nodes = []; while (frag.firstChild) { var node = frag.firstChild; parent.insertBefore(node, wrap); nodes.push(node); } parent.removeChild(wrap); function reexec(old) { var s = document.createElement('script'); for (var a = 0; a = 0; } function progSave() { var vals = {}; for (var i = 0; i = 0; // A money answer saved before they left its box ("5.000.000") comes back tidied, // so the form's own sums read it as meant rather than as 5. else el.value = el.getAttribute('data-money') === '1' ? crmTidyMoney(v) : v; } // Let conditional logic, calculations and the form's own custom JS catch up. for (i = 0; i 0 && form.querySelector('[data-page="' + pg + '"]')) showPage(pg); var note = document.createElement('p'); note.className = 'crm-resume-note'; note.style.cssText = 'font-size:13px;opacity:.75;margin:0 0 12px;'; note.textContent = 'Welcome back \u2014 your answers so far have been kept.'; form.parentNode.insertBefore(note, form); return true; } function progStart() { progRestore(); form.addEventListener('change', progSave); progPing('/progress/open', { pages: totalPages }); } // After every script on the page has run, so the form's custom JS is // listening before the restored answers are replayed to it. if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', progStart); else setTimeout(progStart, 0); })(); /* ── Property118 branded form ─────────────────────────────────────────────── */ .p118-crm-form{ --blue:#0b5fa5;--blue-dark:#073f70;--blue-soft:#eaf4fc;--ink:#17212b;--muted:#5c6875; --line:#d9e1e8;--panel:#f7f9fb;--red:#a82d2d;--pad:32px; max-width:920px;margin:24px auto;font-family:Arial,Helvetica,sans-serif;color:var(--ink);line-height:1.55; padding:var(--pad);border:1px solid var(--line);border-radius:16px;background:#fff; box-shadow:0 16px 45px rgba(13,44,72,.10);overflow:hidden; } .p118-crm-form *{box-sizing:border-box} /* fields — single column always, never two-up */ .p118-crm-form .crm-field,.p118-crm-form .crm-half{margin-bottom:16px} .p118-crm-form .crm-half{display:block;width:100%;margin-right:0} .p118-crm-form label{display:block;font-weight:700;color:var(--ink);margin-bottom:7px} .p118-crm-form .crm-required{color:var(--red);margin-left:2px} .p118-crm-form .crm-desc,.p118-crm-form .crm-field-description{display:block;margin:-3px 0 8px;color:var(--muted);font-size:13px;font-weight:400} .p118-crm-form input[type="number"],.p118-crm-form input[type="text"],.p118-crm-form input[type="email"], .p118-crm-form input[type="tel"],.p118-crm-form input[type="url"],.p118-crm-form input[type="date"], .p118-crm-form select,.p118-crm-form textarea{ width:100%;min-height:48px;border:1px solid #b9c5cf;border-radius:10px;padding:11px 13px; background:#fff;font-size:16px;color:var(--ink);font-family:inherit; } .p118-crm-form textarea{min-height:120px;resize:vertical} .p118-crm-form input:focus,.p118-crm-form select:focus,.p118-crm-form textarea:focus{outline:0;border-color:var(--blue);box-shadow:0 0 0 3px rgba(11,95,165,.15)} .p118-crm-form input[aria-invalid="true"],.p118-crm-form select[aria-invalid="true"]{border-color:var(--red);box-shadow:0 0 0 3px rgba(168,45,45,.12)} /* currency fields */ .p118-crm-form .crm-amount-wrap{display:flex;align-items:center;gap:.5rem} .p118-crm-form .crm-amount-currency{font-size:1.15rem;font-weight:700;color:var(--ink)} .p118-crm-form .crm-amount-wrap input{flex:1} /* section headings = the step titles */ .p118-crm-form .crm-section,.p118-crm-form h2,.p118-crm-form h3{color:var(--blue-dark);font-size:clamp(22px,3vw,30px);line-height:1.2;margin:8px 0 6px;padding-top:14px} .p118-crm-form .crm-section hr{display:none} .p118-crm-form .crm-section+.crm-desc,.p118-crm-form .crm-section-description{max-width:720px;color:var(--muted);margin-bottom:18px} /* radio / checkbox options as selectable tiles */ .p118-crm-form .crm-choices{display:grid;gap:9px} .p118-crm-form .crm-choices label{display:flex;align-items:flex-start;gap:10px;min-height:48px;border:1px solid #c7d1da;border-radius:10px;background:#fff;padding:12px 13px;margin:0;font-weight:400;cursor:pointer} .p118-crm-form .crm-choices label:has(input:checked){border-color:var(--blue);background:var(--blue-soft);box-shadow:inset 0 0 0 1px var(--blue)} .p118-crm-form .crm-choices input{width:18px;height:18px;min-height:0;margin:2px 0 0;flex:0 0 auto;accent-color:var(--blue)} /* consent checkboxes */ .p118-crm-form .crm-consent-label{display:flex;gap:10px;align-items:flex-start;font-weight:400;line-height:1.5} .p118-crm-form .crm-consent-label input{width:19px;height:19px;min-height:0;margin-top:2px;flex:0 0 auto;accent-color:var(--blue)} /* buttons + nav */ .p118-crm-form .crm-nav,.p118-crm-form .crm-actions,.p118-crm-form .crm-page-nav{display:flex;justify-content:space-between;gap:12px;margin-top:26px} .p118-crm-form .crm-submit{margin-top:26px} .p118-crm-form button{appearance:none;min-height:48px;border:0;border-radius:10px;padding:12px 20px;font-weight:700;font-size:16px;cursor:pointer;font-family:inherit} .p118-crm-form button[type="submit"],.p118-crm-form .crm-next-btn,.p118-crm-form [data-next]{background:var(--blue);color:#fff;box-shadow:0 8px 20px rgba(11,95,165,.2)} .p118-crm-form button[type="submit"]:hover,.p118-crm-form .crm-next-btn:hover,.p118-crm-form [data-next]:hover{background:var(--blue-dark)} .p118-crm-form .crm-prev-btn,.p118-crm-form [data-back]{background:#fff;border:1px solid #bec9d2;color:var(--blue-dark)} .p118-crm-form button:disabled{opacity:.5;cursor:not-allowed} .p118-crm-form .crm-page-error{color:var(--red);font-weight:700;margin-top:12px} /* file input */ .p118-crm-form .crm-file-label{display:flex;align-items:center;gap:.75rem;cursor:pointer;width:100%;padding:12px 13px;background:#fff;border:2px dashed #c7d1da;border-radius:10px} .p118-crm-form .crm-file-label:hover{border-color:var(--blue)} .p118-crm-form .crm-file-btn{flex-shrink:0;background:var(--blue);color:#fff;border-radius:8px;padding:.35rem .8rem;font-size:.85rem;font-weight:700;white-space:nowrap} .p118-crm-form .crm-file-name{font-size:.9rem;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap} /* confirmation / error message */ .p118-crm-form .crm-message{padding:16px 18px;border-radius:12px;margin-top:16px;font-size:15px} .p118-crm-form .crm-message.success{background:var(--blue-soft);border:1px solid #bbd6eb;color:var(--blue-dark)} .p118-crm-form .crm-message.error{background:#fdecec;border:1px solid #f0c2c2;color:var(--red)} /* the native progress bar is replaced by the segmented rail below */ .p118-crm-form .crm-progress,.p118-crm-form .crm-progress-meta{display:none} /* branded header + step rail (both injected by the preset JS) */ .p118-header{margin:calc(var(--pad) * -1) calc(var(--pad) * -1) 0;padding:30px var(--pad) 26px;background:linear-gradient(135deg,var(--blue-dark),var(--blue));color:#fff} .p118-header .p118-eyebrow{margin:0 0 7px;font-size:13px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;opacity:.88} .p118-header h1{margin:0;max-width:700px;font-size:clamp(24px,4.2vw,40px);line-height:1.12;letter-spacing:-.02em;color:#fff} .p118-header .p118-header-copy{max-width:740px;margin:14px 0 0;color:rgba(255,255,255,.92);font-size:16px} .p118-steps{margin:0 calc(var(--pad) * -1) 22px;padding:16px var(--pad);border-bottom:1px solid var(--line);background:#fff} .p118-steps-bar{height:9px;border-radius:999px;background:#e5ebf0;overflow:hidden} .p118-steps-fill{height:100%;background:var(--blue);border-radius:inherit;transition:width .25s ease} .p118-steps-labels{display:grid;gap:6px;margin-top:8px;font-size:11px;text-align:center;color:#73808d} .p118-step-label.is-current{color:var(--blue-dark);font-weight:700} .p118-step-label.is-done{color:var(--blue)} @media(max-width:720px){ .p118-crm-form{--pad:20px;border-radius:12px} .p118-steps-labels{display:none} } var P118_FORM={"title":"Request a private introduction","description":"If you would like to be considered for a private introduction, please complete the sections below. Your answers help us understand whether this opportunity is likely to be appropriate for you before any investment-specific information is shared."}; ; (function () { var wrap = document.querySelector('.p118-crm-form'); if (!wrap || wrap.querySelector('.p118-header') || wrap.querySelector('.p118-steps')) return; // Title/description come from the P118_FORM prelude the resolver emits. The // CRM's preview renderer draws no .crm-form-title element at all, and the WP // shortcode only draws one when the embed passes title="true" — so scraping // the DOM for them left the header blank on most forms. var meta = (typeof P118_FORM !== 'undefined' && P118_FORM) || {}; var pages = [].slice.call(wrap.querySelectorAll('.crm-page')); var labels = pages.map(function (p, i) { var h = p.querySelector('.crm-section h2, .crm-section h3, .crm-section'); var t = h ? (h.textContent || '').trim() : ''; return t || 'Step ' + (i + 1); }); var titleEl = wrap.querySelector('.crm-form-title'); var descEl = wrap.querySelector('.crm-form-description'); var title = (meta.title || (titleEl && titleEl.textContent) || '').trim(); var copy = (meta.description || (descEl && descEl.textContent) || '').trim(); if (title) { var header = document.createElement('header'); header.className = 'p118-header'; var h1 = document.createElement('h1'); h1.textContent = title; var eyebrow = document.createElement('p'); eyebrow.className = 'p118-eyebrow'; eyebrow.textContent = 'Property118'; header.appendChild(eyebrow); header.appendChild(h1); if (copy) { var p = document.createElement('p'); p.className = 'p118-header-copy'; p.textContent = copy; header.appendChild(p); } if (titleEl) titleEl.style.display = 'none'; if (descEl) descEl.style.display = 'none'; wrap.insertBefore(header, wrap.firstChild); } if (pages.length Commercial disclosure: I have personally invested in the type of loan note described above. Property118 may receive an introductory commission if you subsequently invest. Property118 does not provide regulated investment advice. The post My retirement investment after a lifetime in buy-to-let appeared first on Property118 .

Originally published by

Property118

Read full article