<!-- Lake Como Florist — Investment Estimator.
Paste into a Squarespace Code Block (Business plan or above).
All prices live in the CONFIG and CATALOG blocks in the script. -->
<style>
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500&family=Jost:wght@300;400;500&display=swap');
.lcf-est{
--bg:#F6F3EE; --surface:#FFFFFF; --surface-2:#FBF9F6;
--ink:#2E2621; --ink-soft:#6B5F57; --ink-faint:#9C9088;
--line:#E4DDD3; --line-soft:#EFE9E1;
--accent:#5C7391; --accent-deep:#3E5570; --accent-tint:#EAEEF3;
background:var(--bg); color:var(--ink);
font-family:'Jost',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
font-weight:300; font-size:15px; line-height:1.55;
-webkit-font-smoothing:antialiased;
}
@media (prefers-color-scheme: dark){
:root:not([data-theme="light"]) .lcf-est{
--bg:#191512; --surface:#221D19; --surface-2:#1F1A17;
--ink:#F0E9E0; --ink-soft:#AA9E92; --ink-faint:#7C7168;
--line:#352D27; --line-soft:#2B241F;
--accent:#8CA5C1; --accent-deep:#A8BDD4; --accent-tint:#232C36;
}
}
:root[data-theme="dark"] .lcf-est{
--bg:#191512; --surface:#221D19; --surface-2:#1F1A17;
--ink:#F0E9E0; --ink-soft:#AA9E92; --ink-faint:#7C7168;
--line:#352D27; --line-soft:#2B241F;
--accent:#8CA5C1; --accent-deep:#A8BDD4; --accent-tint:#232C36;
}
.lcf-est *{box-sizing:border-box}
.lcf-est .wrap{max-width:1120px; margin:0 auto; padding:56px 24px 96px}
.lcf-est .mast{border-bottom:1px solid var(--line); padding-bottom:36px; margin-bottom:44px}
.lcf-est .eyebrow{font-size:11px; letter-spacing:.22em; text-transform:uppercase; color:var(--accent); margin:0 0 18px}
.lcf-est h1{font-family:'Cormorant Garamond',Georgia,serif; font-weight:300; font-size:clamp(34px,5.2vw,52px); line-height:1.08; letter-spacing:-.01em; margin:0 0 18px; max-width:16ch; color:var(--ink)}
.lcf-est .lede{color:var(--ink-soft); max-width:56ch; margin:0; font-size:16px}
.lcf-est .cols{display:grid; grid-template-columns:1fr 340px; gap:56px; align-items:start}
@media (max-width:900px){ .lcf-est .cols{grid-template-columns:1fr; gap:0} }
.lcf-est .group{margin-bottom:40px}
.lcf-est .group-head{display:flex; align-items:baseline; gap:14px; padding-bottom:12px; margin-bottom:4px; border-bottom:1px solid var(--line)}
.lcf-est .group-title{font-family:'Cormorant Garamond',Georgia,serif; font-size:24px; font-weight:400; letter-spacing:.01em; margin:0; color:var(--ink)}
.lcf-est .group-count{font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-faint); margin-left:auto}
.lcf-est .row{display:grid; grid-template-columns:1fr auto auto; gap:22px; align-items:center; padding:16px 0; border-bottom:1px solid var(--line-soft)}
.lcf-est .row.is-on{background:linear-gradient(90deg,var(--accent-tint),transparent 60%)}
.lcf-est .row-main{min-width:0}
.lcf-est .row-name{font-size:15px; color:var(--ink)}
.lcf-est .row-note{font-size:12.5px; color:var(--ink-faint); margin-top:3px; line-height:1.45}
.lcf-est .row-price{font-family:'Cormorant Garamond',Georgia,serif; font-size:17px; color:var(--ink-soft); white-space:nowrap; letter-spacing:.01em}
.lcf-est .row-from{font-size:10px; letter-spacing:.14em; text-transform:uppercase; color:var(--ink-faint); display:block; text-align:right}
.lcf-est .step{display:flex; align-items:center; gap:2px}
.lcf-est .step button{width:30px; height:30px; border:1px solid var(--line); background:var(--surface); color:var(--ink-soft); font-family:inherit; font-size:15px; line-height:1; cursor:pointer; border-radius:2px; transition:all .15s; padding:0}
.lcf-est .step button:hover:not(:disabled){border-color:var(--accent); color:var(--accent)}
.lcf-est .step button:disabled{opacity:.3; cursor:default}
.lcf-est .step output{min-width:34px; text-align:center; font-size:15px; font-variant-numeric:tabular-nums; color:var(--ink)}
.lcf-est .step output.zero{color:var(--ink-faint)}
@media (max-width:560px){.lcf-est .row{grid-template-columns:1fr auto; gap:10px 16px}.lcf-est .row-price{grid-column:1; font-size:15px}.lcf-est .step{grid-column:2; grid-row:2}}
.lcf-est .summary{position:sticky; top:32px; background:var(--surface); border:1px solid var(--line); border-radius:3px; padding:28px 26px}
@media (max-width:900px){ .lcf-est .summary{position:static; margin:8px 0 0} }
.lcf-est .sum-title{font-size:11px; letter-spacing:.22em; text-transform:uppercase; color:var(--ink-faint); margin:0 0 22px}
.lcf-est .line{display:flex; justify-content:space-between; gap:14px; padding:9px 0; font-size:13.5px; color:var(--ink-soft)}
.lcf-est .line b{font-weight:400; color:var(--ink); font-variant-numeric:tabular-nums; white-space:nowrap}
.lcf-est .rule{height:1px; background:var(--line); margin:16px 0}
.lcf-est .total-label{font-size:11px; letter-spacing:.2em; text-transform:uppercase; color:var(--accent); margin:0 0 8px}
.lcf-est .total{font-family:'Cormorant Garamond',Georgia,serif; font-weight:300; font-size:clamp(26px,3.4vw,33px); line-height:1.15; color:var(--ink); font-variant-numeric:tabular-nums}
.lcf-est .total.empty{color:var(--ink-faint); font-size:22px}
.lcf-est .field{margin-top:12px}
.lcf-est .field label{display:block; font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-faint); margin-bottom:7px}
.lcf-est select,.lcf-est input[type=email]{width:100%; padding:10px 12px; font-family:inherit; font-size:14px; font-weight:300; color:var(--ink); background:var(--surface-2); border:1px solid var(--line); border-radius:2px; margin:0}
.lcf-est select:focus,.lcf-est input:focus{outline:none; border-color:var(--accent)}
.lcf-est .btn{display:block; width:100%; margin-top:14px; padding:13px; font-family:inherit; font-size:11px; font-weight:400; letter-spacing:.2em; text-transform:uppercase; color:var(--bg); background:var(--ink); border:1px solid var(--ink); border-radius:2px; cursor:pointer; transition:all .2s; text-align:center; text-decoration:none}
.lcf-est .btn:hover{background:var(--accent-deep); border-color:var(--accent-deep); color:var(--bg)}
.lcf-est .btn[aria-disabled="true"]{opacity:.35; pointer-events:none}
.lcf-est .btn-quiet{background:transparent; color:var(--ink-soft); border-color:var(--line)}
.lcf-est .btn-quiet:hover{background:transparent; color:var(--accent); border-color:var(--accent)}
.lcf-est .notice{margin-top:18px; padding:14px 16px; border-left:2px solid var(--accent); background:var(--accent-tint); font-size:13px; line-height:1.5; color:var(--ink-soft)}
.lcf-est .notice strong{font-weight:400; color:var(--ink)}
.lcf-est .fine{margin-top:20px; font-size:11.5px; line-height:1.55; color:var(--ink-faint)}
.lcf-est .sent{margin-top:12px; font-size:12.5px; color:var(--accent); text-align:center}
.lcf-est [hidden]{display:none !important}
</style>
<div class="lcf-est">
<div class="wrap">
<header class="mast">
<p class="eyebrow">Investment</p>
<h1>What a wedding with us costs</h1>
<p class="lede">Build the pieces you have in mind and watch the range take shape. Every number here is real — it is where our work starts, not a quote.</p>
</header>
<div class="cols">
<main id="lcfCatalog"></main>
<aside class="summary">
<p class="sum-title">Your estimate</p>
<div class="line"><span>Flowers & design</span><b id="lcfSub">—</b></div>
<div class="line"><span id="lcfLabourLabel">Labour, logistics & setup</span><b id="lcfLabour">—</b></div>
<div class="field">
<label for="lcfTravel">Location</label>
<select id="lcfTravel">
<option value="como">Lake Como — no travel fee</option>
<option value="italy">Elsewhere in Italy</option>
<option value="abroad">Outside Italy</option>
</select>
</div>
<div class="rule"></div>
<p class="total-label">Estimated range</p>
<div class="total empty" id="lcfTotal">Add a few pieces</div>
<div id="lcfNotice"></div>
<div class="field" style="margin-top:22px">
<label for="lcfEmail">Send this estimate to</label>
<input type="email" id="lcfEmail" placeholder="your@email.com" autocomplete="email">
</div>
<a class="btn" id="lcfSend" href="#" aria-disabled="true">Email me this estimate</a>
<button class="btn btn-quiet" id="lcfReset" type="button">Start over</button>
<p class="sent" id="lcfSent" hidden></p>
<p class="fine">
This is an honest starting range, not a proposal. Final pricing is built around your flowers,
palette, venue and season, and is confirmed after a consultation.
Pieces marked <em>from</em> are estimated at their starting price.
</p>
</aside>
</div>
</div>
</div>
<script>
(function(){
var CONFIG = {
currency: '€',
labourMinPct: 20,
labourMaxPct: 25,
minimumProject: 12000,
showMinimumNotice: true,
minimumNotice: 'Our full-service weddings start from <strong>€12,000</strong>. '
+ 'For a smaller celebration, write to us anyway — we will gladly point you to someone who is the right fit.',
addCreativeFee: false,
creativeFee: 5000,
contactEmail: 'hello@lakecomoflorist.com',
travel: {
como: { label: 'Lake Como', note: '' },
italy: { label: 'Elsewhere in Italy', note: 'Travel and accommodation are quoted separately.' },
abroad: { label: 'Outside Italy', note: 'Travel, shipping and accommodation are quoted separately.' }
}
};
var CATALOG = [
{ group: 'Bouquets', items: [
{ name: 'Formal bridal bouquet', note: 'Mixed seasonal flowers', min: 250, max: 250 },
{ name: 'Unstructured garden style bridal bouquet', note: 'Mixed seasonal flowers', min: 290, max: 290 },
{ name: 'Trailing bridal bouquet', note: 'Mixed seasonal flowers', min: 450, max: 450 },
{ name: 'Throw-away posy', note: 'Bridal bouquet double', min: 160, max: 160 },
{ name: 'Formal bridesmaid bouquet', note: 'Mixed seasonal flowers', min: 120, max: 120 },
{ name: 'Unstructured bridesmaid bouquet', note: 'Mixed seasonal flowers', min: 160, max: 160 }
]},
{ group: 'Gentlemen', items: [
{ name: 'Boutonnière', note: '', min: 20, max: 20 },
{ name: 'Floral pocket square', note: '', min: 75, max: 75 }
]},
{ group: 'Flower girls & boys', items: [
{ name: 'Posy', note: 'Mixed seasonal flowers', min: 50, max: 50 },
{ name: 'Rose petal basket', note: '', min: 35, max: 35 },
{ name: 'Flower crown', note: '', min: 120, max: 120 }
]},
{ group: 'Ceremony', items: [
{ name: 'Chair flowers', note: 'Depending on style', min: 80, max: 120 },
{ name: 'Ceremony arch', note: 'Depending on size, style and fullness', min: 3900, max: 8900 },
{ name: 'Ceremony vase arrangements', note: 'Per piece, depending on size and fullness', min: 520, max: 970 },
{ name: 'Aisle row arrangements', note: 'Floor compositions, depending on style and dimension',min: 420, max: 620 },
{ name: 'Jewish chuppah', note: 'Structure and pillar flower decoration', min: 4800, max: 9800 },
{ name: 'Indian mandap', note: 'Structure and pillar flower decoration', min: 4800, max: 9800 }
]},
{ group: 'Reception', items: [
{ name: 'Modern vase arrangements', note: 'Small from 340, medium from 440, large from 520', min: 340, max: 580 },
{ name: 'Formal tall centerpieces', note: 'Medium from 550, large from 750', min: 550, max: 850 },
{ name: 'Bridal table decor', note: 'Depending on style and quantity of flowers', min: 1600, max: 3200 },
{ name: 'Cake flowers', note: 'Depending on cake size and design', min: 250, max: 750 },
{ name: 'Hanging installations', note: 'Depending on style, space and labour', min: 5000, max: 5000, from: true }
]}
];
function money(n){ return CONFIG.currency + Math.round(n).toLocaleString('en-US'); }
var qty = {};
var $ = function(id){ return document.getElementById(id); };
var el = {
catalog: $('lcfCatalog'), sub: $('lcfSub'), labour: $('lcfLabour'),
labourLabel: $('lcfLabourLabel'), total: $('lcfTotal'), notice: $('lcfNotice'),
travel: $('lcfTravel'), email: $('lcfEmail'), send: $('lcfSend'),
reset: $('lcfReset'), sent: $('lcfSent')
};
if (!el.catalog) return;
el.labourLabel.textContent =
'Labour, logistics & setup (' + CONFIG.labourMinPct + '–' + CONFIG.labourMaxPct + '%)';
var rows = [];
function render(){
CATALOG.forEach(function(group, gi){
var sec = document.createElement('section');
sec.className = 'group';
var head = document.createElement('div');
head.className = 'group-head';
var h2 = document.createElement('h2');
h2.className = 'group-title'; h2.textContent = group.group;
var cnt = document.createElement('span');
cnt.className = 'group-count'; cnt.textContent = group.items.length + ' items';
head.appendChild(h2); head.appendChild(cnt);
sec.appendChild(head);
group.items.forEach(function(item, ii){
var id = gi + '-' + ii;
qty[id] = 0;
var row = document.createElement('div');
row.className = 'row';
var main = document.createElement('div');
main.className = 'row-main';
var nm = document.createElement('div');
nm.className = 'row-name'; nm.textContent = item.name;
main.appendChild(nm);
if (item.note){
var nt = document.createElement('div');
nt.className = 'row-note'; nt.textContent = item.note;
main.appendChild(nt);
}
var price = document.createElement('div');
price.className = 'row-price';
price.textContent = item.min === item.max
? money(item.min)
: money(item.min) + ' – ' + money(item.max);
if (item.from){
var tag = document.createElement('span');
tag.className = 'row-from'; tag.textContent = 'from';
price.appendChild(tag);
}
var step = document.createElement('div');
step.className = 'step';
var minus = document.createElement('button');
minus.type = 'button'; minus.textContent = '−';
minus.setAttribute('aria-label', 'Remove one ' + item.name);
minus.disabled = true;
var out = document.createElement('output');
out.className = 'zero'; out.textContent = '0';
var plus = document.createElement('button');
plus.type = 'button'; plus.textContent = '+';
plus.setAttribute('aria-label', 'Add one ' + item.name);
function sync(){
out.textContent = qty[id];
if (qty[id] === 0){ out.classList.add('zero'); } else { out.classList.remove('zero'); }
minus.disabled = qty[id] === 0;
if (qty[id] > 0){ row.classList.add('is-on'); } else { row.classList.remove('is-on'); }
recalc();
}
minus.addEventListener('click', function(){ if (qty[id] > 0) qty[id]--; sync(); });
plus.addEventListener('click', function(){ qty[id]++; sync(); });
rows.push(sync);
step.appendChild(minus); step.appendChild(out); step.appendChild(plus);
row.appendChild(main); row.appendChild(price); row.appendChild(step);
sec.appendChild(row);
});
el.catalog.appendChild(sec);
});
}
function totals(){
var lo = 0, hi = 0, picked = [];
CATALOG.forEach(function(group, gi){
group.items.forEach(function(item, ii){
var n = qty[gi + '-' + ii];
if (!n) return;
lo += item.min * n;
hi += item.max * n;
picked.push(n + ' × ' + item.name);
});
});
if (CONFIG.addCreativeFee && picked.length){ lo += CONFIG.creativeFee; hi += CONFIG.creativeFee; }
var labLo = lo * CONFIG.labourMinPct / 100;
var labHi = hi * CONFIG.labourMaxPct / 100;
return { lo:lo, hi:hi, labLo:labLo, labHi:labHi, totLo:lo+labLo, totHi:hi+labHi, picked:picked };
}
function range(a, b){
return Math.round(a) === Math.round(b) ? money(a) : money(a) + ' – ' + money(b);
}
function recalc(){
var t = totals();
var has = t.picked.length > 0;
el.sub.textContent = has ? range(t.lo, t.hi) : '—';
el.labour.textContent = has ? range(t.labLo, t.labHi) : '—';
if (has){ el.total.classList.remove('empty'); } else { el.total.classList.add('empty'); }
el.total.textContent = has ? range(t.totLo, t.totHi) : 'Add a few pieces';
var notes = [];
if (has && CONFIG.showMinimumNotice && t.totHi < CONFIG.minimumProject) notes.push(CONFIG.minimumNotice);
var tr = CONFIG.travel[el.travel.value];
if (tr && tr.note) notes.push(tr.note);
el.notice.innerHTML = notes.map(function(n){ return '<div class="notice">' + n + '</div>'; }).join('');
el.send.setAttribute('aria-disabled', has ? 'false' : 'true');
el.send.href = has ? mailtoLink(t) : '#';
}
function mailtoLink(t){
var lines = ['Hello Lake Como Florist,', '', 'I put together an estimate on your website:', '']
.concat(t.picked.map(function(p){ return ' • ' + p; }))
.concat(['',
'Location: ' + CONFIG.travel[el.travel.value].label,
'Flowers & design: ' + range(t.lo, t.hi),
'Labour, logistics & setup: ' + range(t.labLo, t.labHi),
'Estimated range: ' + range(t.totLo, t.totHi), '',
'My email: ' + (el.email.value || '(please add)'), '',
'I would like to talk about my wedding.']);
return 'mailto:' + CONFIG.contactEmail
+ '?subject=' + encodeURIComponent('Website estimate — ' + range(t.totLo, t.totHi))
+ '&body=' + encodeURIComponent(lines.join('\n'));
}
el.travel.addEventListener('change', recalc);
el.email.addEventListener('input', recalc);
el.send.addEventListener('click', function(){
if (el.send.getAttribute('aria-disabled') === 'true') return;
el.sent.hidden = false;
el.sent.textContent = 'Opening your mail app…';
});
el.reset.addEventListener('click', function(){
Object.keys(qty).forEach(function(k){ qty[k] = 0; });
rows.forEach(function(fn){ fn(); });
el.email.value = '';
el.sent.hidden = true;
});
render();
recalc();
})();
</script>