Compare commits
8 Commits
a0032d17fa
...
feature/ro
| Author | SHA1 | Date | |
|---|---|---|---|
| 04ef642775 | |||
| 50fdbb1b1d | |||
| 080be485fe | |||
| acb1818e5d | |||
| f0733a106c | |||
| c88ee544d6 | |||
| d70b614485 | |||
| 3e113cadd8 |
10
.env.example
10
.env.example
@@ -8,3 +8,13 @@ AI_API_KEY=your_nvidia_api_key_here
|
||||
AI_MODEL=qwen/qwen3.5-397b-a17b
|
||||
# Set to 'true' to enable detailed AI prompt/response logging
|
||||
AI_DEBUG=false
|
||||
|
||||
# Form abuse protection
|
||||
# Cloudflare Turnstile (free): https://dash.cloudflare.com/?to=/:account/turnstile
|
||||
# Leave blank to run without a visible CAPTCHA — the honeypot, signed form token
|
||||
# and per-IP rate limits stay active either way.
|
||||
TURNSTILE_SITE_KEY=
|
||||
TURNSTILE_SECRET_KEY=
|
||||
# Optional: stable secret for signing form tokens. If unset, a random one is
|
||||
# generated per process (tokens simply stop validating across restarts).
|
||||
FORM_TOKEN_SECRET=
|
||||
103
app.js
103
app.js
@@ -34,10 +34,76 @@
|
||||
|
||||
if (!overlay) return;
|
||||
|
||||
function open() { overlay.classList.add('open'); document.body.style.overflow = 'hidden'; }
|
||||
// ── Abuse protection ───────────────────────────────────
|
||||
// A signed, single-use token is fetched when the form is opened; the server
|
||||
// uses it to prove the form was really loaded and that a human took at least a
|
||||
// few seconds to fill it in. When Turnstile keys are configured server-side, a
|
||||
// CAPTCHA widget is rendered too.
|
||||
const captchaSlot = document.getElementById('calcCaptcha');
|
||||
let formToken = null;
|
||||
let captchaWidget = null;
|
||||
let siteKeyPromise = null;
|
||||
|
||||
async function fetchFormToken() {
|
||||
try {
|
||||
const res = await fetch('/api/form-token', { cache: 'no-store' });
|
||||
formToken = (await res.json()).token || null;
|
||||
} catch (_) { formToken = null; }
|
||||
}
|
||||
|
||||
function loadTurnstileScript() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.turnstile) return resolve();
|
||||
const s = document.createElement('script');
|
||||
s.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
|
||||
s.async = true;
|
||||
s.onload = resolve;
|
||||
s.onerror = reject;
|
||||
document.head.appendChild(s);
|
||||
});
|
||||
}
|
||||
|
||||
async function initCaptcha() {
|
||||
if (!captchaSlot || captchaWidget !== null) return;
|
||||
siteKeyPromise = siteKeyPromise || fetch('/api/form-config', { cache: 'no-store' })
|
||||
.then(r => r.json())
|
||||
.then(c => c.turnstileSiteKey)
|
||||
.catch(() => null);
|
||||
|
||||
const siteKey = await siteKeyPromise;
|
||||
if (!siteKey) return; // CAPTCHA not configured — other layers still apply
|
||||
|
||||
try {
|
||||
await loadTurnstileScript();
|
||||
captchaWidget = window.turnstile.render(captchaSlot, {
|
||||
sitekey: siteKey,
|
||||
theme: 'light',
|
||||
action: 'roi_calculator',
|
||||
});
|
||||
} catch (_) { /* widget unavailable — server decides whether to allow */ }
|
||||
}
|
||||
|
||||
function captchaResponse() {
|
||||
if (captchaWidget === null || !window.turnstile) return '';
|
||||
return window.turnstile.getResponse(captchaWidget) || '';
|
||||
}
|
||||
|
||||
function resetCaptcha() {
|
||||
if (captchaWidget !== null && window.turnstile) window.turnstile.reset(captchaWidget);
|
||||
}
|
||||
|
||||
function open() {
|
||||
overlay.classList.add('open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
fetchFormToken(); // starts the minimum-fill-time clock
|
||||
initCaptcha();
|
||||
}
|
||||
function close() { overlay.classList.remove('open'); document.body.style.overflow = ''; }
|
||||
|
||||
openBtn?.addEventListener('click', open);
|
||||
// Footer CTA also opens the modal (v2.js handles its analytics) — it needs the
|
||||
// same form token and CAPTCHA set-up.
|
||||
document.getElementById('openCalc2')?.addEventListener('click', open);
|
||||
closeBtn?.addEventListener('click', close);
|
||||
overlay.addEventListener('click', e => { if (e.target === overlay) close(); });
|
||||
document.addEventListener('keydown', e => { if (e.key === 'Escape') close(); });
|
||||
@@ -55,6 +121,12 @@
|
||||
const calcBtnText = submitBtn?.querySelector('.calc-btn-text');
|
||||
const calcBtnLoading = submitBtn?.querySelector('.calc-btn-loading');
|
||||
|
||||
function showCalcError(msg) {
|
||||
if (!calcErr) return;
|
||||
calcErr.textContent = msg;
|
||||
calcErr.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function setCalcLoading(on) {
|
||||
if (!submitBtn) return;
|
||||
submitBtn.disabled = on;
|
||||
@@ -73,12 +145,19 @@
|
||||
const calcOptIn = document.getElementById('calcOptIn')?.checked ?? true;
|
||||
|
||||
if (!homesites || !annualIncome) {
|
||||
calcErr.classList.remove('hidden');
|
||||
showCalcError('Please fill in homesites and annual dues income to continue.');
|
||||
return;
|
||||
}
|
||||
calcErr.classList.add('hidden');
|
||||
setCalcLoading(true);
|
||||
|
||||
// ── Abuse checks: server verifies the token, honeypot and CAPTCHA ──
|
||||
const guardBody = {
|
||||
formToken,
|
||||
captchaToken: captchaResponse(),
|
||||
hp_company_url: document.getElementById('hpCompanyUrl')?.value || '',
|
||||
};
|
||||
|
||||
// ── Conservative investment assumptions ──
|
||||
// Operating cash: depending on payment frequency, portion investable in high-yield savings
|
||||
const opMultiplier = { monthly: 0.10, quarterly: 0.20, annually: 0.35 }[paymentFreq] || 0.10;
|
||||
@@ -131,17 +210,35 @@
|
||||
|
||||
// ── AI recommendation — call server to generate & save to DB (not displayed) ──
|
||||
try {
|
||||
await fetch('/api/calculate', {
|
||||
const res = await fetch('/api/calculate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
...guardBody,
|
||||
homesites, propertyType, annualIncome, paymentFreq, reserveFunds, interest2025,
|
||||
email: calcEmail, optIn: calcOptIn,
|
||||
totalPotential, opInterest, resInterest,
|
||||
}),
|
||||
});
|
||||
|
||||
// A blocked submission stops here — the estimate is not shown and nothing
|
||||
// is stored. AI/service errors (502/503) fall through to the local result.
|
||||
if (!res.ok) {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
if (data.blocked) {
|
||||
setCalcLoading(false);
|
||||
showCalcError(data.error || 'We could not verify this submission. Please try again.');
|
||||
resetCaptcha();
|
||||
await fetchFormToken(); // tokens are single-use; issue a fresh one
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (_) { /* best-effort — DB save failed silently */ }
|
||||
|
||||
// Token is spent on a successful submission; get another for a recalculation.
|
||||
fetchFormToken();
|
||||
resetCaptcha();
|
||||
|
||||
// ── Animate the main number ──
|
||||
animateValue(document.getElementById('resultAmount'), 0, totalPotential);
|
||||
|
||||
|
||||
315
articles/hoa-board-meeting-financial-questions.html
Normal file
315
articles/hoa-board-meeting-financial-questions.html
Normal file
@@ -0,0 +1,315 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>5 Questions Every HOA Board Should Ask at Every Meeting | HOA LedgerIQ Insights</title>
|
||||
<meta name="description" content="Most HOA board meetings focus on what already happened. These five financial questions shift your board from reactive to proactive—before problems become crises." />
|
||||
<meta name="keywords" content="HOA board meeting, HOA financial review, HOA board questions, HOA treasurer tips, HOA budget management, community association board, HOA meeting agenda, HOA financial health" />
|
||||
<link rel="canonical" href="https://www.hoaledgeriq.com/articles/hoa-board-meeting-financial-questions" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="../styles.css" />
|
||||
<meta property="og:title" content="5 Questions Every HOA Board Should Ask at Every Meeting" />
|
||||
<meta property="og:description" content="The difference between a productive board meeting and a frustrating one often comes down to five financial questions nobody thinks to ask—until a crisis forces the issue." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://www.hoaledgeriq.com/articles/hoa-board-meeting-financial-questions" />
|
||||
<meta property="article:published_time" content="2026-07-01" />
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-RTWNVXPMRF"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-RTWNVXPMRF');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav">
|
||||
<div class="nav-inner">
|
||||
<a href="../index.html" class="nav-logo">
|
||||
<img src="../logo_house_transparent.svg" alt="HOA LedgerIQ" class="logo-img" />
|
||||
</a>
|
||||
<ul class="nav-links">
|
||||
<li><a href="../index.html">Home</a></li>
|
||||
<li><a href="../index.html#features">Features</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="index.html" class="nav-active">Insights</a></li>
|
||||
</ul>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" class="btn btn-primary nav-btn" target="_blank" rel="noopener">Start Free Trial</a>
|
||||
<a href="https://app.hoaledgeriq.com" class="btn btn-outline nav-btn nav-login" target="_blank" rel="noopener">Login</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Article Header -->
|
||||
<header class="article-header">
|
||||
<div class="container">
|
||||
<nav class="article-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<a href="index.html">Insights</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<span>HOA Board Meeting Financial Questions</span>
|
||||
</nav>
|
||||
<span class="article-tag">Board Management</span>
|
||||
<h1 class="article-title">5 Questions Every HOA Board Should Ask at Every Meeting</h1>
|
||||
<p class="article-subtitle">The difference between a productive board meeting and a frustrating one often comes down to five financial questions nobody thinks to ask—until a crisis forces the issue.</p>
|
||||
<div class="article-meta">
|
||||
<span>HOA LedgerIQ Team</span>
|
||||
<span class="meta-separator">•</span>
|
||||
<span>July 1, 2026</span>
|
||||
<span class="meta-separator">•</span>
|
||||
<span>8 min read</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Article Body -->
|
||||
<section class="article-body-section">
|
||||
<div class="container">
|
||||
<div class="article-prose">
|
||||
|
||||
<p class="lead">The meeting had been going for forty minutes and the board was deep into a debate about whether to replace the pool furniture this summer or push it to fall. Meanwhile, the treasurer's report had taken four minutes: she'd shown a bank balance, said everything looked "about where we expect it to be," and moved on.</p>
|
||||
|
||||
<p>Nobody asked a follow-up question. Nobody asked whether there was enough cash to cover the pool furniture if they approved it today. Nobody asked how the community's reserve contributions were tracking against the annual plan, or whether any large expenses were sitting in vendor inboxes waiting to be invoiced. The board wasn't being careless—they just didn't know what to ask.</p>
|
||||
|
||||
<p>That's the root problem in most HOA board meetings. The financial review happens, but it's a recitation of what already occurred rather than a forward-looking conversation about where the community stands and where it's heading. Five questions, asked consistently at every meeting, can completely transform that dynamic. They don't require financial expertise. They require only the discipline to stop and ask them every single time.</p>
|
||||
|
||||
<h2>Question 1: What Does Our Cash Flow Look Like Through the End of the Quarter?</h2>
|
||||
|
||||
<p>The most important financial question a board can ask isn't "what's in the bank?" It's "what will be in the bank in 60 to 90 days, given everything we know is coming in and going out?"</p>
|
||||
|
||||
<p>The distinction sounds subtle but it's enormous. A current bank balance tells you the result of decisions made weeks or months ago. A forward-looking cash flow projection tells you whether you have room to make decisions right now—or whether you need to slow down and conserve.</p>
|
||||
|
||||
<p>Consider a community with a $95,000 operating balance in October. On the surface, that looks healthy. But if $30,000 in annual insurance premiums are due in November, $22,000 in landscaping invoices are expected before year-end, and the next assessment cycle doesn't close until January, the real question isn't "do we have $95,000?"—it's "will we have $43,000 at the low point of Q4, and is that enough buffer?" Those are very different conversations.</p>
|
||||
|
||||
<blockquote>
|
||||
"Every month I showed the board the bank balance. Then one November we couldn't pay our property manager on time and everyone acted shocked. The balance had never been higher in October. I finally understood that the balance isn't the answer—it's barely even the question." — HOA Treasurer, Mesa, AZ
|
||||
</blockquote>
|
||||
|
||||
<p>Asking for a 90-day cash flow projection at every meeting takes the board out of the rearview mirror and puts them in the windshield. Over time, it becomes the most natural question in the room—and the one that prevents the most problems.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What to ask:</strong> "What's our projected balance at the low point of the next 90 days, and what assumptions does that projection depend on?" If your treasurer can't answer this in under two minutes, it's a sign your financial tools need an upgrade.
|
||||
</div>
|
||||
|
||||
<h2>Question 2: Are We on Track With Reserve Contributions?</h2>
|
||||
|
||||
<p>Reserve contributions are the HOA equivalent of a mortgage payment. Miss a few and the math catches up with you in ways that are far more painful than the short-term relief was worth. Yet many boards allow reserve contributions to slip—delayed by one month, reduced during a tight quarter, or simply forgotten in the noise of operating decisions—without ever explicitly discussing the trade-off they're making.</p>
|
||||
|
||||
<p>The question "are we on track with reserve contributions?" forces that conversation into the open. It's not accusatory—sometimes boards make a deliberate, defensible decision to defer a contribution in a particular month. The problem is when it happens silently and cumulatively, and nobody tallies the gap until the reserve study comes back showing a significant funding shortfall.</p>
|
||||
|
||||
<p>A well-run board tracks the year-to-date reserve contribution as a percentage of the annual plan and discusses it explicitly. If January through June should have contributed $54,000 and the actual is $54,000, the answer is a quick "yes, we're on track" and you move on. If the actual is $44,000, you now have a $10,000 underfunding conversation that's much better to have in June than in December—or worse, in year four when the roof is failing and the fund is short.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What to ask:</strong> "Year-to-date, what have we contributed to reserves versus what the plan called for? If there's a gap, what's the path to close it before year-end?"
|
||||
</div>
|
||||
|
||||
<h2>Question 3: What Large Expenses Are Expected in the Next 60 Days That Haven't Been Approved Yet?</h2>
|
||||
|
||||
<p>Every community has a pipeline of anticipated spending that hasn't formally reached the board yet. A contractor submitted a proposal for gutter cleaning that the property manager is reviewing. The annual pest control contract is up for renewal. A vendor is finishing a painting job and the final invoice—larger than the deposit—is coming.</p>
|
||||
|
||||
<p>None of these are surprises to the people managing them. But in a typical board meeting, none of them get mentioned until there's an invoice in hand and a vote needed. The result is a board that's perpetually in reactive mode: approving expenses they didn't know were coming, writing checks without a clear sense of what they're committed to spending next month.</p>
|
||||
|
||||
<p>A simple standing agenda item—"anticipated expenses in the next 60 days"—pulls this invisible pipeline into the room. The property manager or treasurer does a quick scan: anything in the queue worth flagging? It takes two minutes and changes everything. Now the board knows, before approving anything else, what's already headed toward them.</p>
|
||||
|
||||
<blockquote>
|
||||
"We started doing a '60-day expense preview' at every meeting three years ago. We've never had to scramble for money since. It's not that we have more money—we just know where it's going before it arrives." — HOA Board President, Charlotte, NC
|
||||
</blockquote>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What to ask:</strong> "Before we approve anything today—what significant expenses are expected in the next 60 days that haven't come to the board yet?" Include both planned items and anything in negotiation or approval pipeline.
|
||||
</div>
|
||||
|
||||
<h2>Question 4: How Do We Stand Year-to-Date Against Budget?</h2>
|
||||
|
||||
<p>Budgets are not just forecasts—they're accountability tools. When the board approves an annual budget, they're making a commitment to the community about how money will be spent. Reviewing budget-versus-actual performance at every meeting keeps that commitment visible and catches drift early.</p>
|
||||
|
||||
<p>"Year-to-date against budget" doesn't need to be an exhaustive line-item review at every meeting. A summary by major category—operating expenses, administration, maintenance and repairs, reserve contributions—takes five minutes and tells the board everything they need to know about whether they're tracking to plan.</p>
|
||||
|
||||
<p>The categories worth watching most closely are usually maintenance and repairs (where unplanned work can blow a line item quickly) and administration (where professional service fees sometimes exceed estimates). A budget variance of 10 percent or more in any major category is worth a brief conversation: is this a one-time item, a systematic underestimate, or a sign of something to watch?</p>
|
||||
|
||||
<p>What you're looking for over time is the pattern, not just the snapshot. A community that routinely underspends in the spring and overspends in the fall might need to adjust budget timing, not the total. You can only see that pattern if you're reviewing actuals consistently against the plan.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What to ask:</strong> "By major category, how are we tracking year-to-date against the approved budget? Are any categories more than 10 percent over or under, and do we understand why?"
|
||||
</div>
|
||||
|
||||
<h2>Question 5: Is There Anything We're Not Talking About That We Should Be?</h2>
|
||||
|
||||
<p>This question sounds soft, but it's actually the most powerful one on the list—and the hardest to get right. Every board meeting has a formal agenda, and that agenda creates a powerful filtering effect: things that aren't on the agenda don't get discussed. Information that doesn't fit neatly into a line item, a vote, or an update gets held back—sometimes indefinitely.</p>
|
||||
|
||||
<p>The property manager has noticed that a unit owner is two months behind on assessments and a third month is about to start. The treasurer saw something odd in the bank statements but it seemed minor and she didn't want to derail the meeting. A vendor sent an email suggesting that the pool pump replacement might need to happen sooner than the reserve study projected.</p>
|
||||
|
||||
<p>None of these things are crises yet. All of them are better addressed now than later. A standing question—"is there anything we're not discussing that we should be?"—creates explicit permission to surface the soft signals before they become hard problems.</p>
|
||||
|
||||
<p>The best boards use this question to cultivate a culture where nobody sits on uncomfortable information. When the treasurer knows she'll be asked every month, she comes prepared to surface the odd thing in the bank statement rather than hoping it resolves itself. When the property manager knows there's space to raise soft concerns, he doesn't wait for a formal report.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What to ask:</strong> "Before we close out the financial review—is there anything you've seen, heard, or are tracking that isn't on today's agenda but that the board should know about?" Direct the question to both the treasurer and the property manager.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SCREENSHOT CAROUSEL -->
|
||||
<section class="article-showcase">
|
||||
<div class="container">
|
||||
<div class="article-showcase-header">
|
||||
<div class="section-label">See How Modern HOA Financial Management Works</div>
|
||||
<h2>HOA LedgerIQ gives your board the answers to these questions before anyone has to ask</h2>
|
||||
</div>
|
||||
<div class="screenshot-carousel" id="screenshotCarousel">
|
||||
<div class="carousel-frame">
|
||||
<div class="carousel-slides">
|
||||
<div class="carousel-slide active">
|
||||
<img src="../img/screenshot-dashboard.png" alt="HOA LedgerIQ Dashboard — Fund health scores, operating and reserve balances" />
|
||||
<div class="slide-caption">Real-time financial dashboard with fund health scores and instant balance visibility</div>
|
||||
</div>
|
||||
<div class="carousel-slide">
|
||||
<img src="../img/screenshot-cashflow.png" alt="HOA LedgerIQ Cash Flow — Projected balances with forward forecasting chart" />
|
||||
<div class="slide-caption">Automated 90-day cash flow projections — so the first question answers itself</div>
|
||||
</div>
|
||||
<div class="carousel-slide">
|
||||
<img src="../img/screenshot-capital.png" alt="HOA LedgerIQ Capital Planning — Multi-year project timeline and budget view" />
|
||||
<div class="slide-caption">Reserve tracking and capital planning tools built for board-level conversations</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-btn carousel-prev" aria-label="Previous screenshot">←</button>
|
||||
<div class="carousel-dots">
|
||||
<span class="carousel-dot active" data-index="0"></span>
|
||||
<span class="carousel-dot" data-index="1"></span>
|
||||
<span class="carousel-dot" data-index="2"></span>
|
||||
</div>
|
||||
<button class="carousel-btn carousel-next" aria-label="Next screenshot">→</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- More Article Content -->
|
||||
<section class="article-body-section">
|
||||
<div class="container">
|
||||
<div class="article-prose">
|
||||
|
||||
<h2>What This Looks Like in Practice</h2>
|
||||
|
||||
<p>The Elmwood Park HOA is a 110-unit community in suburban Ohio with a volunteer board of five and a part-time property manager. Two years ago, their monthly meetings ran long, decisions felt reactive, and the treasurer's report was the part of the agenda everyone mentally checked out during.</p>
|
||||
|
||||
<p>The board president had attended a community association conference and came home with a simple idea: restructure the financial review around five standing questions. She proposed adding them to the agenda template and asked the treasurer and property manager to come to every meeting prepared to answer each one.</p>
|
||||
|
||||
<p>The first couple of meetings were awkward. The property manager hadn't been tracking a 60-day expense pipeline and had to build the habit. The treasurer needed to pull together a 90-day projection format she hadn't used before. But by the third meeting, it was working—and by the sixth, the board couldn't imagine going back.</p>
|
||||
|
||||
<p>In October of that year, the 60-day expense preview surfaced something that would have caught them off guard: the parking lot sealing contractor was wrapping up and the final invoice—$11,000 more than the deposit—was expected in three weeks. The board knew it was coming. They confirmed the cash was there. They didn't scramble.</p>
|
||||
|
||||
<p>In February, the "anything we're not discussing?" question surfaced a soft concern the property manager had been sitting on: one homeowner hadn't responded to three assessment notices and might be heading toward a lien. The board directed him to escalate, and the issue was resolved before it became a delinquency that affected cash flow.</p>
|
||||
|
||||
<blockquote>
|
||||
"We didn't change our budget, we didn't change our assessments, and we didn't hire anyone new. We just started asking better questions. The meetings are shorter now, and we leave feeling like we're actually in control." — Elmwood Park HOA Board President
|
||||
</blockquote>
|
||||
|
||||
<h2>Making the Questions Stick</h2>
|
||||
|
||||
<p>The hardest part isn't identifying the right questions—it's building the habit of asking them every single month, even when meetings are running long, even when everything seems fine, even when the treasurer's report takes four minutes and nobody's worried.</p>
|
||||
|
||||
<p>The communities that get this right treat the five questions like a safety checklist: you don't skip it because the flight looks routine. You run it precisely because things feel fine—because that's exactly when problems are forming quietly under the surface.</p>
|
||||
|
||||
<p>Put the questions in your standard agenda template so they appear automatically. Brief your treasurer and property manager once on what each question is looking for so they can come prepared. And the first time a standing question catches something that would otherwise have slipped through, remind the room that this is why you ask every time.</p>
|
||||
|
||||
<p>Boards that run consistent financial reviews don't just make better decisions—they build credibility with homeowners. When assessments rise, when a project goes over budget, or when a difficult vote is required, a board with a track record of asking the right questions earns the trust that makes those conversations manageable. A board that only reacts to crises is always starting from zero.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>The bottom line:</strong> Great HOA financial governance isn't about expertise—it's about habits. Five questions, asked every month, consistently and honestly, will do more to protect your community's finances than any spreadsheet, policy, or new committee. Start at the next meeting.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section class="article-cta">
|
||||
<div class="container">
|
||||
<h2>Ready to Walk Into Every Board Meeting with Answers?</h2>
|
||||
<p>HOA LedgerIQ gives your board a live financial dashboard—cash flow projections, reserve tracking, and budget-versus-actual all in one place, automatically updated before every meeting.</p>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" class="btn btn-primary btn-large" target="_blank" rel="noopener">Start Your Free 14-Day Trial</a>
|
||||
<p class="cta-note">No credit card required · 14-day free trial · No contracts</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Article Navigation -->
|
||||
<nav class="article-nav">
|
||||
<div class="container">
|
||||
<div class="article-nav-grid">
|
||||
<a href="hoa-cash-flow-management-mistakes.html" class="article-nav-prev">
|
||||
<span class="nav-label">Previous Article</span>
|
||||
<span class="nav-title">What HOA Boards Get Wrong About Cash Flow Management</span>
|
||||
</a>
|
||||
<a href="hoa-financial-transparency.html" class="article-nav-next">
|
||||
<span class="nav-label">More Reading</span>
|
||||
<span class="nav-title">HOA Financial Transparency: What Homeowners Deserve to Know</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer">
|
||||
<div class="container footer-inner">
|
||||
<div class="footer-logo">
|
||||
<img src="../logo_house.svg" alt="HOA LedgerIQ" class="logo-img logo-img--footer" />
|
||||
<p>AI-powered HOA finance management.</p>
|
||||
</div>
|
||||
<div class="footer-links">
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Product</div>
|
||||
<a href="../index.html#features">Features</a>
|
||||
<a href="../index.html#pricing">Pricing</a>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" target="_blank" rel="noopener">Start Free Trial</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Pages</div>
|
||||
<a href="../investment-management.html">Investment Management</a>
|
||||
<a href="../reserve-study-software.html">Reserve Studies</a>
|
||||
<a href="index.html">Insights</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Legal</div>
|
||||
<a href="../privacy.html">Privacy Policy</a>
|
||||
<a href="../terms.html">Terms of Service</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<div class="container">
|
||||
<span>© 2026 HOA LedgerIQ. All rights reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="../app.js"></script>
|
||||
|
||||
<!-- Support Chat Widget -->
|
||||
<script>
|
||||
(function(d,t) {
|
||||
var BASE_URL="https://chat.hoaledgeriq.com";
|
||||
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=BASE_URL+"/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g,s);
|
||||
g.onload=function(){
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: '1QMW1fycL5xHvd6XMfg4Dbb4',
|
||||
baseUrl: BASE_URL
|
||||
})
|
||||
}
|
||||
})(document,"script");
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
317
articles/hoa-cash-flow-management-mistakes.html
Normal file
317
articles/hoa-cash-flow-management-mistakes.html
Normal file
@@ -0,0 +1,317 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>What HOA Boards Get Wrong About Cash Flow Management | HOA LedgerIQ Insights</title>
|
||||
<meta name="description" content="Most HOA boards confuse a healthy bank balance with healthy cash flow. Learn the four cash flow mistakes that quietly drain communities—and how to fix them." />
|
||||
<meta name="keywords" content="HOA cash flow management, HOA financial planning, HOA budgeting mistakes, community association cash flow, HOA reserve funds, HOA operating budget, HOA treasurer tips" />
|
||||
<link rel="canonical" href="https://www.hoaledgeriq.com/articles/hoa-cash-flow-management-mistakes" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="../styles.css" />
|
||||
<meta property="og:title" content="What HOA Boards Get Wrong About Cash Flow Management" />
|
||||
<meta property="og:description" content="A healthy bank balance doesn't mean healthy cash flow. Here are the four mistakes HOA boards make—and how to catch them before they become crises." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://www.hoaledgeriq.com/articles/hoa-cash-flow-management-mistakes" />
|
||||
<meta property="article:published_time" content="2026-06-15" />
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-RTWNVXPMRF"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-RTWNVXPMRF');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav">
|
||||
<div class="nav-inner">
|
||||
<a href="../index.html" class="nav-logo">
|
||||
<img src="../logo_house_transparent.svg" alt="HOA LedgerIQ" class="logo-img" />
|
||||
</a>
|
||||
<ul class="nav-links">
|
||||
<li><a href="../index.html">Home</a></li>
|
||||
<li><a href="../index.html#features">Features</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="index.html" class="nav-active">Insights</a></li>
|
||||
</ul>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" class="btn btn-primary nav-btn" target="_blank" rel="noopener">Start Free Trial</a>
|
||||
<a href="https://app.hoaledgeriq.com" class="btn btn-outline nav-btn nav-login" target="_blank" rel="noopener">Login</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Article Header -->
|
||||
<header class="article-header">
|
||||
<div class="container">
|
||||
<nav class="article-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<a href="index.html">Insights</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<span>HOA Cash Flow Management</span>
|
||||
</nav>
|
||||
<span class="article-tag">Financial Planning</span>
|
||||
<h1 class="article-title">What HOA Boards Get Wrong About Cash Flow Management</h1>
|
||||
<p class="article-subtitle">A healthy bank balance doesn't mean healthy cash flow. Here are the four mistakes HOA boards make—and how to catch them before they become crises.</p>
|
||||
<div class="article-meta">
|
||||
<span>HOA LedgerIQ Team</span>
|
||||
<span class="meta-separator">•</span>
|
||||
<span>June 15, 2026</span>
|
||||
<span class="meta-separator">•</span>
|
||||
<span>8 min read</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Article Body -->
|
||||
<section class="article-body-section">
|
||||
<div class="container">
|
||||
<div class="article-prose">
|
||||
|
||||
<p class="lead">At the October board meeting, everything looked fine. The treasurer pulled up the bank portal, confirmed the operating account had $112,000, and reported that the community was "in great shape financially." Nobody asked any follow-up questions. Nobody needed to.</p>
|
||||
|
||||
<p>By December, the Maplewood Crossing HOA couldn't pay their landscaping contractor on time. Their $112,000 balance had obscured something the spreadsheet never showed: three large annual insurance premiums, a roof repair deposit, and Q4 assessment refunds were all due within the same six-week window. They had the money—they just didn't have it at the right time.</p>
|
||||
|
||||
<p>This is the most common and most misunderstood financial problem in HOA management. It isn't about saving enough or spending too much. It's about cash flow: the timing of money coming in and going out. Most HOA boards never see the problem coming—because they're looking at the wrong number.</p>
|
||||
|
||||
<h2>The Balance Trap: Why Your Bank Account Is Lying to You</h2>
|
||||
|
||||
<p>Ask any HOA treasurer how the community is doing financially, and the first thing they'll reach for is the current account balance. It's human nature—the number is right there, easy to read, intuitively satisfying. If it's high, things are good. If it's low, things are worrying.</p>
|
||||
|
||||
<p>The problem is that a balance is a snapshot taken at one instant in time. It tells you where you've been, not where you're going. It says nothing about what's owed in the next 30 days, whether a large payment is already in transit, or whether assessment income is about to slow down because a homeowner entered a payment plan.</p>
|
||||
|
||||
<blockquote>
|
||||
"We had more money in the bank in October than we'd had in years. Three months later we were asking our property manager if we could delay their invoice." — HOA Board President, Scottsdale, AZ
|
||||
</blockquote>
|
||||
|
||||
<p>The balance trap ensnares even experienced boards because the consequences are delayed. A cash flow problem in October might not surface until January. By then, the board has long since moved on from the October meeting, and nobody connects the dots.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>The core confusion:</strong> Balance measures what you have. Cash flow measures what you'll have—and when. Managing an HOA on balance alone is like driving by looking in the rearview mirror.
|
||||
</div>
|
||||
|
||||
<h2>Mistake #1: Treating All Cash as Available Cash</h2>
|
||||
|
||||
<p>Many HOAs maintain one or two bank accounts and view the combined balance as money that's available to spend. In practice, a meaningful portion of that balance is already committed: it's been budgeted for specific line items, it represents prepaid assessments that belong to future quarters, or it's informally earmarked for a project the board discussed three meetings ago.</p>
|
||||
|
||||
<p>When treasurers don't track committed funds separately from truly available cash, they make decisions based on a fictional number. A board approves a $15,000 parking lot patch because the account shows $90,000. What they didn't account for: $20,000 in landscaping invoices not yet received, a $25,000 roofing contractor deposit due in 45 days, and $18,000 in reserve contributions that need to be swept this month.</p>
|
||||
|
||||
<p>The math looks fine until it doesn't. And it tends to stop looking fine right around the time a vendor calls asking where their check is.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>Better practice:</strong> Maintain a simple committed-funds tracker alongside your account balance. Before approving any unplanned expense, check available cash against known upcoming obligations for the next 60–90 days.
|
||||
</div>
|
||||
|
||||
<h2>Mistake #2: Ignoring Seasonal Cash Flow Patterns</h2>
|
||||
|
||||
<p>HOA cash flow is rarely steady. Assessments often come in quarterly or semi-annually, creating predictable valleys between collection periods. Maintenance expenses tend to cluster: landscaping contracts ramp up in spring, HVAC servicing happens in the fall, and year-end often brings insurance renewals, audit fees, and property management contract payments all at once.</p>
|
||||
|
||||
<p>Most HOA boards know, in a general sense, that some months are tighter than others. What they rarely do is map it out explicitly. That's where the trouble starts.</p>
|
||||
|
||||
<p>Consider a typical 150-home community with quarterly assessments. In the month after assessments are due, the operating account looks robust. Eight weeks later, before the next assessment cycle, it looks thin. A board reviewing the financials in that thin window might panic unnecessarily. A board reviewing during the flush window might approve discretionary spending that creates a problem they won't see until next quarter.</p>
|
||||
|
||||
<blockquote>
|
||||
"We learned the hard way that October feels rich and February feels poor—and neither number tells you much about our actual financial health." — HOA Treasurer, Denver, CO
|
||||
</blockquote>
|
||||
|
||||
<p>Mapping your seasonal pattern requires only a few hours of historical data analysis, but the insight it produces is worth far more. Once you know your cash flow rhythm, you can time major payments, schedule reserve contributions, and have an honest conversation at every board meeting about where you are in the cycle.</p>
|
||||
|
||||
<h2>Mistake #3: Confusing Operating Cash Flow With Reserve Health</h2>
|
||||
|
||||
<p>Operating cash flow and reserve fund health are two separate things that affect each other but should never be confused with each other. Healthy operating cash flow means the community can pay its day-to-day bills without stress. A healthy reserve fund means the community can pay for major capital repairs without levying a special assessment.</p>
|
||||
|
||||
<p>The mistake boards make is treating them as interchangeable. Some communities routinely borrow from reserves to cover operating shortfalls, intending to pay it back later—and then don't. Others stop funding reserves at the required percentage because "the operating account looks fine," not realizing they're trading future stability for present comfort.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>A rule worth memorizing:</strong> Reserve contributions are not optional budget line items. They're the mortgage payment on your community's future. Miss them, and you don't notice the damage for years—right up until the roof fails and the reserve fund comes up $80,000 short.
|
||||
</div>
|
||||
|
||||
<p>The healthiest HOA boards treat reserve contributions as fixed obligations, exactly like an insurance premium or property management fee. Operating cash flow planning happens around that number, not at the expense of it. It requires more discipline in the short term, but it's the difference between a community that handles capital repairs smoothly and one that dreads every aging roof and crumbling driveway.</p>
|
||||
|
||||
<h2>Mistake #4: No Forward-Looking Cash Flow Forecast</h2>
|
||||
|
||||
<p>The most consequential cash flow mistake is also the simplest to describe: most HOA boards have no forward-looking projection at all. They review what happened last month, confirm the current balance, and adjourn. There's no model showing what the account will look like in 30, 60, or 90 days given known income and expenses.</p>
|
||||
|
||||
<p>This isn't laziness—it's a tool problem. Building a rolling cash flow forecast in a spreadsheet is genuinely tedious. You need to pull in assessment schedules, map out expected invoices, account for seasonal patterns, and update everything every month. Most volunteer treasurers don't have the time, even if they have the skill.</p>
|
||||
|
||||
<p>The result is a board that's perpetually surprised. Tight months feel like emergencies. Flush months feel like windfalls. Neither feeling is accurate—both reflect a lack of visibility into what's actually coming.</p>
|
||||
|
||||
<p>Tom Rivera had served as treasurer of a 200-unit community in Austin for three years before he built his first proper cash flow forecast. "I'd always known, roughly, when money was tight. But I'd never actually mapped it out. When I finally did, I saw that we'd been within $8,000 of not being able to cover payroll twice in the last two years. Nobody knew. I didn't know."</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What a good forecast shows:</strong> Expected assessment income by date, committed expenses with approximate timing, reserve contribution schedule, and a running projected balance 90 days out. That's it. You don't need anything more complicated to stay ahead of a cash crunch.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SCREENSHOT CAROUSEL -->
|
||||
<section class="article-showcase">
|
||||
<div class="container">
|
||||
<div class="article-showcase-header">
|
||||
<div class="section-label">See How Modern HOA Financial Management Works</div>
|
||||
<h2>HOA LedgerIQ gives your board real-time cash flow visibility and forward forecasting</h2>
|
||||
</div>
|
||||
<div class="screenshot-carousel" id="screenshotCarousel">
|
||||
<div class="carousel-frame">
|
||||
<div class="carousel-slides">
|
||||
<div class="carousel-slide active">
|
||||
<img src="../img/screenshot-dashboard.png" alt="HOA LedgerIQ Dashboard — Fund health scores, operating and reserve balances" />
|
||||
<div class="slide-caption">Real-time financial dashboard with instant visibility into cash flow and reserves</div>
|
||||
</div>
|
||||
<div class="carousel-slide">
|
||||
<img src="../img/screenshot-cashflow.png" alt="HOA LedgerIQ Cash Flow — Projected balances with forward forecasting chart" />
|
||||
<div class="slide-caption">Automated cash flow tracking and 90-day forward forecasting</div>
|
||||
</div>
|
||||
<div class="carousel-slide">
|
||||
<img src="../img/screenshot-capital.png" alt="HOA LedgerIQ Capital Planning — Multi-year project timeline and budget view" />
|
||||
<div class="slide-caption">Reserve fund management and capital planning tools</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-btn carousel-prev" aria-label="Previous screenshot">←</button>
|
||||
<div class="carousel-dots">
|
||||
<span class="carousel-dot active" data-index="0"></span>
|
||||
<span class="carousel-dot" data-index="1"></span>
|
||||
<span class="carousel-dot" data-index="2"></span>
|
||||
</div>
|
||||
<button class="carousel-btn carousel-next" aria-label="Next screenshot">→</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- More Article Content -->
|
||||
<section class="article-body-section">
|
||||
<div class="container">
|
||||
<div class="article-prose">
|
||||
|
||||
<h2>What Better Cash Flow Management Looks Like in Practice</h2>
|
||||
|
||||
<p>Let's return to Maplewood Crossing—the community that couldn't pay their landscaping contractor in December despite having $112,000 in October.</p>
|
||||
|
||||
<p>After that difficult season, the board hired a new property manager who introduced them to a forward-looking cash flow model. For the first time, they mapped out every expected income and expense across a full 12-month window. The pattern was immediately obvious: October looked flush, but November through January was a valley—high expenses, no new assessment cycle, almost no buffer.</p>
|
||||
|
||||
<p>They made two changes. First, they shifted their reserve contribution timing to smooth out the crunch. Second, they negotiated their largest annual vendor contracts to be invoiced in September instead of November, before the valley began. Neither change required a single extra dollar from homeowners. They simply rearranged the timing of money they already had.</p>
|
||||
|
||||
<p>By the following December, they had a $35,000 operating cushion at the lowest point of the year—down from $112,000 at the peak, but stable enough to handle anything routine. More importantly, the board walked into every meeting with a 90-day projected balance, not just a current balance. Questions changed from "how much do we have?" to "what's our position heading into spring?"</p>
|
||||
|
||||
<blockquote>
|
||||
"We went from reacting to cash problems to preventing them. Same budget, same assessments—we just finally knew what was coming." — Maplewood Crossing Board President
|
||||
</blockquote>
|
||||
|
||||
<h2>Building Cash Flow Discipline Into Your Board's Routine</h2>
|
||||
|
||||
<p>You don't need a finance degree to run solid HOA cash flow management. You need three habits, applied consistently.</p>
|
||||
|
||||
<p><strong>Review a 90-day projection at every board meeting.</strong> Not just the current balance—the projected balance 30, 60, and 90 days out. This single habit would have caught the Maplewood Crossing problem three months earlier. If your current tools don't support this, a simple spreadsheet with known income and expense dates is a meaningful start.</p>
|
||||
|
||||
<p><strong>Separate committed funds from available funds.</strong> Before the board approves any discretionary spending, confirm how much of the current balance is already spoken for in the next 60 days. This takes five minutes to check and prevents the most common board-meeting budgeting errors.</p>
|
||||
|
||||
<p><strong>Treat reserve contributions as non-negotiable.</strong> Fund them first, every month, before making any other financial decisions. Your community's long-term financial stability depends on consistent reserve funding far more than any short-term operating flexibility.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>The bottom line:</strong> Cash flow discipline isn't about having more money. It's about knowing where your money is going—and when—so you're never caught off guard by a perfectly predictable problem.
|
||||
</div>
|
||||
|
||||
<h2>The Role of Better Tools</h2>
|
||||
|
||||
<p>Spreadsheets can get you started, but they don't scale well with the complexity of a real community's finances. Keeping a rolling forecast up to date requires someone to manually update it every month, cross-referencing bank statements, unpaid invoices, and assessment schedules. For a volunteer treasurer already stretched thin, that maintenance often slips—and the moment the forecast goes stale, it's worse than no forecast at all because it creates false confidence.</p>
|
||||
|
||||
<p>Modern HOA financial management platforms handle this automatically. Bank feeds update transaction data daily. The system tracks assessment schedules and flags expected income. Known recurring expenses populate forward projections without manual entry. The result is a living cash flow picture that's accurate without requiring a monthly rebuild.</p>
|
||||
|
||||
<p>That kind of continuous visibility changes how boards behave. When a 90-day forecast is always available and always current, conversations shift from "are we okay?" to "what do we want to accomplish?" That's the environment where great financial decisions get made—not the one where the treasurer is scrambling to update a spreadsheet the night before the meeting.</p>
|
||||
|
||||
<p>Most HOAs have the financial discipline they need. What they're missing is the visibility to apply it at the right moment. Cash flow management isn't about working harder—it's about seeing clearly.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section class="article-cta">
|
||||
<div class="container">
|
||||
<h2>Ready to See Your Community's Cash Flow Clearly?</h2>
|
||||
<p>HOA LedgerIQ gives your board a live 90-day cash flow forecast—automatically updated, no spreadsheet required.</p>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" class="btn btn-primary btn-large" target="_blank" rel="noopener">Start Your Free 14-Day Trial</a>
|
||||
<p class="cta-note">No credit card required · 14-day free trial · No contracts</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Article Navigation -->
|
||||
<nav class="article-nav">
|
||||
<div class="container">
|
||||
<div class="article-nav-grid">
|
||||
<a href="hoa-financial-transparency.html" class="article-nav-prev">
|
||||
<span class="nav-label">Previous Article</span>
|
||||
<span class="nav-title">HOA Financial Transparency: What Homeowners Deserve to Know</span>
|
||||
</a>
|
||||
<a href="hoa-treasurer-burnout-guide.html" class="article-nav-next">
|
||||
<span class="nav-label">More Reading</span>
|
||||
<span class="nav-title">The True Cost of HOA Treasurer Burnout</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer">
|
||||
<div class="container footer-inner">
|
||||
<div class="footer-logo">
|
||||
<img src="../logo_house.svg" alt="HOA LedgerIQ" class="logo-img logo-img--footer" />
|
||||
<p>AI-powered HOA finance management.</p>
|
||||
</div>
|
||||
<div class="footer-links">
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Product</div>
|
||||
<a href="../index.html#features">Features</a>
|
||||
<a href="../index.html#pricing">Pricing</a>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" target="_blank" rel="noopener">Start Free Trial</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Pages</div>
|
||||
<a href="../investment-management.html">Investment Management</a>
|
||||
<a href="../reserve-study-software.html">Reserve Studies</a>
|
||||
<a href="index.html">Insights</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Legal</div>
|
||||
<a href="../privacy.html">Privacy Policy</a>
|
||||
<a href="../terms.html">Terms of Service</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<div class="container">
|
||||
<span>© 2026 HOA LedgerIQ. All rights reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="../app.js"></script>
|
||||
|
||||
<!-- Support Chat Widget -->
|
||||
<script>
|
||||
(function(d,t) {
|
||||
var BASE_URL="https://chat.hoaledgeriq.com";
|
||||
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=BASE_URL+"/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g,s);
|
||||
g.onload=function(){
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: '1QMW1fycL5xHvd6XMfg4Dbb4',
|
||||
baseUrl: BASE_URL
|
||||
})
|
||||
}
|
||||
})(document,"script");
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
282
articles/hoa-reserve-fund-health-score.html
Normal file
282
articles/hoa-reserve-fund-health-score.html
Normal file
@@ -0,0 +1,282 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>How to Read Your HOA's Reserve Fund Health Score | HOA LedgerIQ Insights</title>
|
||||
<meta name="description" content="Your reserve study hands your board a percent-funded number and moves on. Here's what that score actually measures, why 100% isn't always the goal, and what to do at every level." />
|
||||
<meta name="keywords" content="HOA reserve fund health score, percent funded HOA, reserve fund funding ratio, HOA reserve study, reserve fund benchmarks, HOA capital planning, underfunded reserve fund, community association reserves" />
|
||||
<link rel="canonical" href="https://www.hoaledgeriq.com/articles/hoa-reserve-fund-health-score" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="../styles.css" />
|
||||
<meta property="og:title" content="How to Read Your HOA's Reserve Fund Health Score" />
|
||||
<meta property="og:description" content="A percent-funded number gets read aloud at every board meeting, but few boards know what actually moves it or what to do when it's low. Here's the real breakdown." />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://www.hoaledgeriq.com/articles/hoa-reserve-fund-health-score" />
|
||||
<meta property="article:published_time" content="2026-07-15" />
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-RTWNVXPMRF"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-RTWNVXPMRF');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- NAV -->
|
||||
<nav class="nav">
|
||||
<div class="nav-inner">
|
||||
<a href="../index.html" class="nav-logo">
|
||||
<img src="../logo_house_transparent.svg" alt="HOA LedgerIQ" class="logo-img" />
|
||||
</a>
|
||||
<ul class="nav-links">
|
||||
<li><a href="../index.html">Home</a></li>
|
||||
<li><a href="../index.html#features">Features</a></li>
|
||||
<li><a href="../index.html#pricing">Pricing</a></li>
|
||||
<li><a href="index.html" class="nav-active">Insights</a></li>
|
||||
</ul>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" class="btn btn-primary nav-btn" target="_blank" rel="noopener">Start Free Trial</a>
|
||||
<a href="https://app.hoaledgeriq.com" class="btn btn-outline nav-btn nav-login" target="_blank" rel="noopener">Login</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Article Header -->
|
||||
<header class="article-header">
|
||||
<div class="container">
|
||||
<nav class="article-breadcrumb">
|
||||
<a href="../index.html">Home</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<a href="index.html">Insights</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<span>HOA Reserve Fund Health Score</span>
|
||||
</nav>
|
||||
<span class="article-tag">Reserve Funds</span>
|
||||
<h1 class="article-title">How to Read Your HOA's Reserve Fund Health Score</h1>
|
||||
<p class="article-subtitle">Your reserve study hands the board a single percentage and everyone nods like they understand it. Here's what that number actually measures, why 100% isn't always the right target, and exactly what to do at every level.</p>
|
||||
<div class="article-meta">
|
||||
<span>HOA LedgerIQ Team</span>
|
||||
<span class="meta-separator">•</span>
|
||||
<span>July 15, 2026</span>
|
||||
<span class="meta-separator">•</span>
|
||||
<span>9 min read</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Article Body -->
|
||||
<section class="article-body-section">
|
||||
<div class="container">
|
||||
<div class="article-prose">
|
||||
|
||||
<p class="lead">The reserve study landed in the board's inbox three weeks before the annual meeting, forty-one pages long, and the only number anyone actually discussed was on page six: "Percent Funded: 58%." The treasurer read it aloud. A homeowner in the back asked if that was bad. Nobody on the board could say for certain—was 58% a crisis, a mild concern, or perfectly normal for a fifteen-year-old community? The meeting moved on without an answer, and the number went back into a drawer until next year's study.</p>
|
||||
|
||||
<p>This scene repeats in HOA boardrooms constantly, and it's not because boards are careless—it's because the percent-funded score is one of the least understood numbers in community association finance. It sounds simple: reserves as a percentage of what they should be. But the number that produces that percentage, the assumptions behind it, and the right response to it are almost never explained to the volunteers who are supposed to act on it.</p>
|
||||
|
||||
<p>Understanding your reserve fund health score isn't about becoming an actuary. It's about knowing what the number is built from, what range you're actually in, and what specific action—if any—that range calls for. Once a board understands that, the percent-funded line stops being a mystery number read aloud once a year and becomes one of the most useful signals a community has.</p>
|
||||
|
||||
<h2>What the Percent Funded Score Actually Measures</h2>
|
||||
|
||||
<p>At its core, the percent-funded score is a ratio of two numbers: what your reserve fund actually holds today, divided by what it would hold if every component—roof, pavement, pool equipment, elevators, siding—had been funded in perfect proportion to how much of its useful life it has consumed. A roof that's ten years into a twenty-year life should, in a perfectly funded community, have roughly half its replacement cost sitting in reserves. Add that logic up across every reserve component and you get the "fully funded balance." Your actual balance divided by that number is your percent funded.</p>
|
||||
|
||||
<p>The number that trips boards up is the fully funded balance itself, because it's not a fixed target—it moves every year as components age, get replaced, or get re-estimated for cost. A community that contributes exactly the same amount every year can still watch its percent-funded score decline, simply because the fully funded balance grew faster than the fund did. That's not mismanagement. It's math. But without understanding this, a board can look at a declining percentage and panic, or look at a flat percentage and wrongly assume nothing needs attention.</p>
|
||||
|
||||
<blockquote>
|
||||
"For years I thought percent funded was like a bank statement—if it went down, we'd spent too much. It took a conversation with our reserve specialist to understand it's really a comparison against a moving target. That changed how I read the number completely." — HOA Treasurer, Fort Collins, CO
|
||||
</blockquote>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>The core formula:</strong> Percent Funded = Actual Reserve Balance ÷ Fully Funded Balance. The fully funded balance is what your reserves would hold if every component were funded exactly in proportion to its consumed useful life—not a static number, but one that shifts as your components age and get re-appraised.
|
||||
</div>
|
||||
|
||||
<h2>Why 100% Funded Isn't Always the Right Target</h2>
|
||||
|
||||
<p>Reserve specialists and community association institutes generally describe percent-funded ranges in three broad bands: below 30% is considered weak and carries meaningful special assessment risk; 30% to 70% is considered fair, adequate for many stable communities; and above 70% is considered strong. Very few well-run associations sit at 100%, and that's by design, not failure.</p>
|
||||
|
||||
<p>Chasing 100% funded means collecting assessments today for replacements that might be a decade away, which means homeowners are paying in advance for value they won't see for years—money that, in most cases, could be earning better returns elsewhere or easing the burden on current owners. A community sitting comfortably at 75% to 85% funded, with a reserve plan that shows contributions keeping pace with the fully funded balance over time, is often in a stronger practical position than a community rigidly targeting 100% at the cost of large annual increases.</p>
|
||||
|
||||
<p>What actually matters isn't hitting a specific percentage—it's whether the trajectory is stable or improving, and whether the fund can absorb the community's largest near-term expense without a special assessment. A 68% funded community with a clear, funded plan for its next major project is in far better shape than a 74% funded community whose roof replacement is due in eighteen months and isn't accounted for in the number at all.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What to ask instead of "are we at 100%?":</strong> "Given our largest upcoming project, does our current trajectory get us there without an assessment—and if not, what's the gap and the timeline to close it?"
|
||||
</div>
|
||||
|
||||
<h2>The Three Numbers Hiding Behind Every Health Score</h2>
|
||||
|
||||
<p>A single percentage compresses a lot of information, and boards that only look at the top-line number miss the parts that actually predict trouble. Three numbers sit underneath every reserve fund health score, and each tells a different part of the story.</p>
|
||||
|
||||
<p>The first is the current balance—straightforward, the actual dollars sitting in the reserve account today. The second is the fully funded balance, the moving target described above. The third, and the one most boards never see broken out, is the funding threshold for the community's single largest near-term component. A community with $400,000 in reserves and a $380,000 roof replacement due in fourteen months has a very different risk profile than one with the same $400,000 balance and no major project for six years, even if their percent-funded scores land in the same range.</p>
|
||||
|
||||
<p>This is why a reserve study's appendix—the component-by-component funding table—often matters more than its summary page. It shows not just the aggregate percentage but which specific components are underfunded relative to their timeline. A board that only reads the cover page might feel reassured by a 65% overall score, unaware that the single component driving the community's next assessment risk is funded at 20%.</p>
|
||||
|
||||
<blockquote>
|
||||
"We were sitting at 71% funded and felt fine. Then someone actually opened the component table and found our clubhouse HVAC system—due for replacement in two years—was funded at 12%. The overall number hid it completely." — HOA Board Secretary, Naples, FL
|
||||
</blockquote>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>What to ask:</strong> "Beyond the overall percentage, which individual components are most underfunded relative to their replacement timeline—and what's our largest expense in the next 24 months?"
|
||||
</div>
|
||||
|
||||
<h2>Reading the Trend, Not Just the Snapshot</h2>
|
||||
|
||||
<p>A reserve study is typically produced once every three to five years, sometimes updated annually with a simpler desktop review in between. That cadence means most boards experience their percent-funded score as a series of disconnected snapshots rather than a continuous line—and a single snapshot, without context for where the number has been or where it's heading, tells you far less than it seems to.</p>
|
||||
|
||||
<p>A community that moved from 82% funded to 74% funded over three years is telling a very different story than one that's been steady at 74% for a decade. The first suggests contributions aren't keeping pace with rising replacement costs or newly identified components—a trend that, left alone, compounds. The second may simply reflect a community that has calibrated its funding policy to a sustainable, intentional level and is holding it there.</p>
|
||||
|
||||
<p>The boards that manage reserves well don't wait for the next formal study to check their trajectory. They track contributions against the funding plan every month, they revisit cost estimates when a vendor quote comes in meaningfully different from the reserve study's projection, and they treat the percent-funded number as a running conversation rather than a once-every-few-years report card. That shift—from event to habit—is often the single biggest difference between communities that avoid special assessments and communities that get blindsided by them.</p>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>The bottom line:</strong> One percent-funded number tells you almost nothing. Three years of percent-funded numbers, read together with your upcoming project timeline, tell you almost everything.
|
||||
</div>
|
||||
|
||||
<h2>What to Do When Your Score Is Low</h2>
|
||||
|
||||
<p>A weak percent-funded score—generally under 30%, or trending down toward it—isn't a reason to panic, but it is a reason to act deliberately rather than reactively. The instinct in a lot of boardrooms is to either ignore the number until a crisis forces a special assessment, or to overcorrect with a dramatic assessment increase that homeowners resist and resent.</p>
|
||||
|
||||
<p>The more sustainable path is usually a multi-year glide plan: a defined schedule of gradual contribution increases, timed to close the gap before the community's largest project comes due, communicated to homeowners well in advance and tied explicitly to specific components rather than a vague appeal for "more money in reserves." Homeowners tolerate predictable, explained increases far better than sudden ones, and a board that can point to "this increase closes the gap on the roof fund two years ahead of the replacement date" earns far more trust than one that simply says reserves are low.</p>
|
||||
|
||||
<p>In some cases, a modest, planned loan or line of credit against future assessments—paired with a funding plan to repay it—is a more homeowner-friendly option than a lump-sum special assessment, spreading the cost over time rather than demanding it all at once. The right answer depends on the community's specific timeline and risk tolerance, but the wrong answer, in almost every case, is doing nothing and hoping the gap closes itself.</p>
|
||||
|
||||
<h2>What This Looks Like in Practice</h2>
|
||||
|
||||
<p>Sienna Ridge is a 140-unit townhome community outside Denver that came in at 41% funded on its 2024 reserve study—solidly in the "fair, trending toward weak" range, with a shared roof and gutter system due for replacement in five years at an estimated $610,000. The board's first instinct was to raise assessments significantly and get to 70% funded as fast as possible, but a closer look at the component table showed that wasn't actually necessary: the roof project was the only major near-term expense, and a steady five-year ramp in contributions would fully fund it right on schedule without a dramatic single-year jump.</p>
|
||||
|
||||
<p>The board built a five-year contribution schedule with modest annual increases—about 6% per year rather than one large jump—and presented it to homeowners with a simple visual showing exactly how the increases mapped to the roof project timeline. They also began tracking contributions against that plan every quarter instead of waiting for the next formal study, catching a small shortfall in year two when a vendor's updated estimate came in $40,000 higher than the original study projected, and adjusting the fourth-year contribution slightly to compensate.</p>
|
||||
|
||||
<p>By the time the roof project came due, Sienna Ridge had the full $610,000 in reserves, no special assessment, and a board that had spent five years explaining a clear, credible plan to homeowners rather than five years hoping the number would somehow resolve itself. Their percent-funded score at year five: 68%—still not 100%, and not meant to be, but exactly aligned with what their upcoming project timeline required.</p>
|
||||
|
||||
<blockquote>
|
||||
"We used to treat the reserve study like a report card we didn't want to get. Now we treat the percent-funded number like a dashboard gauge—something we check often, understand, and can actually steer." — Sienna Ridge HOA Treasurer
|
||||
</blockquote>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>The bottom line:</strong> A reserve fund health score isn't a grade to fear or a target to chase blindly—it's a diagnostic tool. Boards that understand what drives it, track it continuously, and connect it to their actual project timeline make calmer, cheaper decisions than boards that only glance at it once a year.
|
||||
</div>
|
||||
|
||||
<p>The percentage on page six of your reserve study will keep getting read aloud at board meetings whether or not anyone understands it. The communities that avoid special assessments and homeowner backlash are the ones that stop treating it as a mystery number and start treating it as what it actually is: a running measurement of whether today's decisions are keeping pace with tomorrow's bills.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- SCREENSHOT CAROUSEL -->
|
||||
<section class="article-showcase">
|
||||
<div class="container">
|
||||
<div class="article-showcase-header">
|
||||
<div class="section-label">See How Modern HOA Financial Management Works</div>
|
||||
<h2>HOA LedgerIQ tracks your reserve fund health score continuously — not just once every few years</h2>
|
||||
</div>
|
||||
<div class="screenshot-carousel" id="screenshotCarousel">
|
||||
<div class="carousel-frame">
|
||||
<div class="carousel-slides">
|
||||
<div class="carousel-slide active">
|
||||
<img src="../img/screenshot-dashboard.png" alt="HOA LedgerIQ Dashboard — Fund health scores, operating and reserve balances" />
|
||||
<div class="slide-caption">Real-time fund health scores so your board never has to wait for the next reserve study</div>
|
||||
</div>
|
||||
<div class="carousel-slide">
|
||||
<img src="../img/screenshot-cashflow.png" alt="HOA LedgerIQ Cash Flow — Projected balances with forward forecasting chart" />
|
||||
<div class="slide-caption">Forward cash flow forecasting that connects reserve contributions to real project timelines</div>
|
||||
</div>
|
||||
<div class="carousel-slide">
|
||||
<img src="../img/screenshot-capital.png" alt="HOA LedgerIQ Capital Planning — Multi-year project timeline and budget view" />
|
||||
<div class="slide-caption">Component-level capital planning that shows exactly which reserve items need attention</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<button class="carousel-btn carousel-prev" aria-label="Previous screenshot">←</button>
|
||||
<div class="carousel-dots">
|
||||
<span class="carousel-dot active" data-index="0"></span>
|
||||
<span class="carousel-dot" data-index="1"></span>
|
||||
<span class="carousel-dot" data-index="2"></span>
|
||||
</div>
|
||||
<button class="carousel-btn carousel-next" aria-label="Next screenshot">→</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section class="article-cta">
|
||||
<div class="container">
|
||||
<h2>Ready to Track Your Reserve Fund Health Year-Round?</h2>
|
||||
<p>HOA LedgerIQ gives your board a live, component-level view of reserve funding—so your percent-funded score is a number you check monthly, not a surprise you read once a year.</p>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" class="btn btn-primary btn-large" target="_blank" rel="noopener">Start Your Free 14-Day Trial</a>
|
||||
<p class="cta-note">No credit card required · 14-day free trial · No contracts</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Article Navigation -->
|
||||
<nav class="article-nav">
|
||||
<div class="container">
|
||||
<div class="article-nav-grid">
|
||||
<a href="hoa-board-meeting-financial-questions.html" class="article-nav-prev">
|
||||
<span class="nav-label">Previous Article</span>
|
||||
<span class="nav-title">5 Questions Every HOA Board Should Ask at Every Meeting</span>
|
||||
</a>
|
||||
<a href="hoa-reserve-fund-cd-laddering.html" class="article-nav-next">
|
||||
<span class="nav-label">More Reading</span>
|
||||
<span class="nav-title">CD Laddering for HOA Reserve Funds: A Practical Guide</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="footer">
|
||||
<div class="container footer-inner">
|
||||
<div class="footer-logo">
|
||||
<img src="../logo_house.svg" alt="HOA LedgerIQ" class="logo-img logo-img--footer" />
|
||||
<p>AI-powered HOA finance management.</p>
|
||||
</div>
|
||||
<div class="footer-links">
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Product</div>
|
||||
<a href="../index.html#features">Features</a>
|
||||
<a href="../index.html#pricing">Pricing</a>
|
||||
<a href="https://app.hoaledgeriq.com/pricing" target="_blank" rel="noopener">Start Free Trial</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Pages</div>
|
||||
<a href="../investment-management.html">Investment Management</a>
|
||||
<a href="../reserve-study-software.html">Reserve Studies</a>
|
||||
<a href="index.html">Insights</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<div class="footer-col-title">Legal</div>
|
||||
<a href="../privacy.html">Privacy Policy</a>
|
||||
<a href="../terms.html">Terms of Service</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<div class="container">
|
||||
<span>© 2026 HOA LedgerIQ. All rights reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="../app.js"></script>
|
||||
|
||||
<!-- Support Chat Widget -->
|
||||
<script>
|
||||
(function(d,t) {
|
||||
var BASE_URL="https://chat.hoaledgeriq.com";
|
||||
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=BASE_URL+"/packs/js/sdk.js";
|
||||
g.async = true;
|
||||
s.parentNode.insertBefore(g,s);
|
||||
g.onload=function(){
|
||||
window.chatwootSDK.run({
|
||||
websiteToken: '1QMW1fycL5xHvd6XMfg4Dbb4',
|
||||
baseUrl: BASE_URL
|
||||
})
|
||||
}
|
||||
})(document,"script");
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -54,6 +54,51 @@
|
||||
|
||||
<div class="article-grid">
|
||||
|
||||
<!-- Article 10 — Newest first -->
|
||||
<a href="hoa-reserve-fund-health-score.html" class="article-card" style="text-decoration:none;">
|
||||
<span class="article-card-tag">Reserve Funds</span>
|
||||
<h2 class="article-card-title">How to Read Your HOA's Reserve Fund Health Score</h2>
|
||||
<p class="article-card-excerpt">Your reserve study hands the board a single percentage and everyone nods like they understand it. Here's what that number actually measures, why 100% funded isn't always the right target, and what to do at every level.</p>
|
||||
<div class="article-card-meta">
|
||||
<span>HOA LedgerIQ Team</span>
|
||||
<span class="article-card-meta-dot"></span>
|
||||
<span>July 15, 2026</span>
|
||||
<span class="article-card-meta-dot"></span>
|
||||
<span>9 min read</span>
|
||||
</div>
|
||||
<span class="article-card-read-more">Read article →</span>
|
||||
</a>
|
||||
|
||||
<!-- Article 9 — Newest first -->
|
||||
<a href="hoa-board-meeting-financial-questions.html" class="article-card" style="text-decoration:none;">
|
||||
<span class="article-card-tag">Board Management</span>
|
||||
<h2 class="article-card-title">5 Questions Every HOA Board Should Ask at Every Meeting</h2>
|
||||
<p class="article-card-excerpt">Most board meetings spend four minutes on finances and forty minutes on pool furniture. These five questions — asked at every meeting without exception — shift your board from reactive to genuinely in control.</p>
|
||||
<div class="article-card-meta">
|
||||
<span>HOA LedgerIQ Team</span>
|
||||
<span class="article-card-meta-dot"></span>
|
||||
<span>July 1, 2026</span>
|
||||
<span class="article-card-meta-dot"></span>
|
||||
<span>8 min read</span>
|
||||
</div>
|
||||
<span class="article-card-read-more">Read article →</span>
|
||||
</a>
|
||||
|
||||
<!-- Article 8 — Newest first -->
|
||||
<a href="hoa-cash-flow-management-mistakes.html" class="article-card" style="text-decoration:none;">
|
||||
<span class="article-card-tag">Financial Planning</span>
|
||||
<h2 class="article-card-title">What HOA Boards Get Wrong About Cash Flow Management</h2>
|
||||
<p class="article-card-excerpt">A healthy bank balance doesn't mean healthy cash flow. Here are the four mistakes HOA boards make—and how to catch them before they quietly drain your community.</p>
|
||||
<div class="article-card-meta">
|
||||
<span>HOA LedgerIQ Team</span>
|
||||
<span class="article-card-meta-dot"></span>
|
||||
<span>June 15, 2026</span>
|
||||
<span class="article-card-meta-dot"></span>
|
||||
<span>8 min read</span>
|
||||
</div>
|
||||
<span class="article-card-read-more">Read article →</span>
|
||||
</a>
|
||||
|
||||
<!-- Article 7 — Newest first -->
|
||||
<a href="hoa-financial-transparency.html" class="article-card" style="text-decoration:none;">
|
||||
<span class="article-card-tag">Financial Planning</span>
|
||||
|
||||
27
index.html
27
index.html
@@ -71,10 +71,10 @@
|
||||
"mainEntity": [
|
||||
{ "@type": "Question", "name": "How long is the free trial?", "acceptedAnswer": { "@type": "Answer", "text": "Every plan includes a 14-day free trial. No credit card is required to explore the platform, and there are no setup fees or long-term contracts." } },
|
||||
{ "@type": "Question", "name": "Is my financial data secure?", "acceptedAnswer": { "@type": "Answer", "text": "Yes. HOA LedgerIQ uses bank-level 256-bit encryption in transit and at rest, with a complete signed audit trail on every transaction for CPA and reserve-study reviews." } },
|
||||
{ "@type": "Question", "name": "Do I need to be an accountant to use it?", "acceptedAnswer": { "@type": "Answer", "text": "No. HOA LedgerIQ is designed for board treasurers, property managers, and homeowners — not just CPAs. The AI assistant answers complex financial questions in plain English." } },
|
||||
{ "@type": "Question", "name": "Do I need to be an accountant to use it?", "acceptedAnswer": { "@type": "Answer", "text": "No. HOA LedgerIQ is designed for board treasurers, property managers, and board members — not just CPAs. The AI assistant answers complex financial questions in plain English." } },
|
||||
{ "@type": "Question", "name": "Does it replace our reserve study?", "acceptedAnswer": { "@type": "Answer", "text": "It works alongside your existing reserve study. LedgerIQ keeps your funding plan live against actual cash flow, so the study stays useful between formal updates rather than going stale." } },
|
||||
{ "@type": "Question", "name": "Can property management companies use it for multiple communities?", "acceptedAnswer": { "@type": "Answer", "text": "Yes. The Professional and Enterprise plans support multiple communities under a single management workspace, with consolidated reporting across all properties." } },
|
||||
{ "@type": "Question", "name": "How quickly can we get started?", "acceptedAnswer": { "@type": "Answer", "text": "Most communities are live in under 30 minutes. Connect your bank and investment accounts, upload prior-year financials, and the AI builds your initial forecast automatically." } }
|
||||
{ "@type": "Question", "name": "Can property management companies use it for multiple communities?", "acceptedAnswer": { "@type": "Answer", "text": "Yes. The Enterprise plan support multiple communities under a single management workspace, contact us for more details." } },
|
||||
{ "@type": "Question", "name": "How quickly can we get started?", "acceptedAnswer": { "@type": "Answer", "text": "Most communities are live in under 30 minutes. Configure your bank and investment accounts, upload prior-year financials, and the AI builds your initial forecast automatically." } }
|
||||
]
|
||||
}
|
||||
</script>
|
||||
@@ -172,13 +172,13 @@
|
||||
<div class="steps">
|
||||
<article class="step">
|
||||
<div class="step-num">1</div>
|
||||
<h3>Connect your accounts</h3>
|
||||
<p>Securely link your operating bank, reserve investments, and prior financials. No CSV gymnastics — most communities are live in under thirty minutes.</p>
|
||||
<h3>Configure your accounts</h3>
|
||||
<p>Define your operating bank, reserve investments, and prior financials. No CSV gymnastics — most communities are live in under thirty minutes.</p>
|
||||
</article>
|
||||
<article class="step">
|
||||
<div class="step-num">2</div>
|
||||
<h3>AI builds your forecast</h3>
|
||||
<p>LedgerIQ analyzes spending patterns, reserve study commitments, and projected cash flow to surface a year-by-year funding plan you can actually defend at a board meeting.</p>
|
||||
<p>LedgerIQ analyzes spending patterns, reserve study commitments, budget vs actuals, and projected cash flow to surface a year-by-year funding plan you can actually defend at a board meeting.</p>
|
||||
</article>
|
||||
<article class="step">
|
||||
<div class="step-num">3</div>
|
||||
@@ -268,7 +268,7 @@
|
||||
<div class="container">
|
||||
<p class="eyebrow eyebrow--center">Simple, transparent pricing</p>
|
||||
<h2 class="section-title section-title--center">Pick the plan that fits your community.</h2>
|
||||
<p class="section-sub">All plans include a 14-day free trial. No setup fees. No contracts.</p>
|
||||
<p class="section-sub">All plans include a 14-day free trial. No setup fees. No contracts. Annual Discounts also available</p>
|
||||
|
||||
<div class="billing-toggle" role="tablist" aria-label="Billing interval">
|
||||
<button class="billing-opt is-active" data-billing="month" role="tab" aria-selected="true">Monthly</button>
|
||||
@@ -381,7 +381,7 @@
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>Do I need to be an accountant to use it?</summary>
|
||||
<p>No. The platform is built for board treasurers, property managers, and homeowners — not just CPAs. The AI assistant answers complex financial questions in plain English.</p>
|
||||
<p>No. The platform is built for board treasurers, property managers, and board members — not just CPAs. The AI assistant answers complex financial questions in plain English.</p>
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>Does it replace our reserve study?</summary>
|
||||
@@ -389,7 +389,7 @@
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>Can property management firms manage multiple communities?</summary>
|
||||
<p>Yes. The Professional and Enterprise plans support multiple communities in a single management workspace with consolidated reporting.</p>
|
||||
<p>Yes. The Enterprise plan supports multiple communities in a single management workspace.</p>
|
||||
</details>
|
||||
<details class="faq-item">
|
||||
<summary>How quickly can we get started?</summary>
|
||||
@@ -509,8 +509,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Honeypot: hidden from humans, irresistible to bots. Leave it empty. -->
|
||||
<div class="calc-hp" aria-hidden="true">
|
||||
<label for="hpCompanyUrl">Company website</label>
|
||||
<input type="text" id="hpCompanyUrl" name="hp_company_url" tabindex="-1" autocomplete="off" />
|
||||
</div>
|
||||
|
||||
<p class="calc-error hidden" id="calcError">Please fill in homesites and annual dues income to continue.</p>
|
||||
|
||||
<!-- CAPTCHA widget — rendered only when Turnstile keys are configured -->
|
||||
<div class="calc-captcha" id="calcCaptcha"></div>
|
||||
|
||||
<div class="calc-email-row">
|
||||
<div class="calc-field calc-field--full">
|
||||
<label for="calcEmail">Your email address <span class="calc-optional">(recommended)</span></label>
|
||||
|
||||
220
security.js
Normal file
220
security.js
Normal file
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* HOA LedgerIQ — Form abuse protection
|
||||
*
|
||||
* Layered defence for public form endpoints (ROI calculator, lead capture):
|
||||
*
|
||||
* 1. Cloudflare Turnstile — real CAPTCHA, active when TURNSTILE_* keys are set.
|
||||
* 2. Honeypot field — a hidden input humans never fill in.
|
||||
* 3. Signed form token — proves the form was actually loaded, and enforces a
|
||||
* minimum fill time (bots submit instantly).
|
||||
* 4. Per-IP rate limiting — caps bursts and daily volume from one source.
|
||||
*
|
||||
* Layers 2–4 need no configuration and work on their own; adding Turnstile keys
|
||||
* upgrades the protection to a full CAPTCHA challenge.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
// ── Config ───────────────────────────────────────────────
|
||||
const TURNSTILE_SITE_KEY = process.env.TURNSTILE_SITE_KEY || '';
|
||||
const TURNSTILE_SECRET = process.env.TURNSTILE_SECRET_KEY || '';
|
||||
const TURNSTILE_VERIFY_URL = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
|
||||
|
||||
// If no explicit secret is configured, generate one per process. Tokens then stop
|
||||
// validating across restarts — harmless, the client just fetches a fresh one.
|
||||
const FORM_SECRET = process.env.FORM_TOKEN_SECRET || crypto.randomBytes(32).toString('hex');
|
||||
|
||||
const MIN_FILL_MS = 4 * 1000; // faster than this is not a human
|
||||
const MAX_TOKEN_AGE_MS = 2 * 60 * 60 * 1000; // tokens expire after 2 hours
|
||||
|
||||
// Sliding-window caps per IP: short burst window + daily ceiling.
|
||||
const RATE_WINDOWS = [
|
||||
{ windowMs: 10 * 60 * 1000, max: 5, label: '10 minutes' },
|
||||
{ windowMs: 24 * 60 * 60 * 1000, max: 25, label: '24 hours' },
|
||||
];
|
||||
|
||||
const turnstileEnabled = Boolean(TURNSTILE_SITE_KEY && TURNSTILE_SECRET);
|
||||
|
||||
// ── Signed, single-use form tokens ───────────────────────
|
||||
const usedTokens = new Map(); // token -> expiry ms
|
||||
const hits = new Map(); // ip -> [timestamps]
|
||||
|
||||
function sign(payload) {
|
||||
return crypto.createHmac('sha256', FORM_SECRET).update(payload).digest('hex').slice(0, 32);
|
||||
}
|
||||
|
||||
function issueFormToken() {
|
||||
const payload = `${Date.now()}.${crypto.randomBytes(9).toString('base64url')}`;
|
||||
return `${payload}.${sign(payload)}`;
|
||||
}
|
||||
|
||||
function verifyFormToken(token) {
|
||||
if (typeof token !== 'string' || token.length > 200) {
|
||||
return { ok: false, reason: 'missing_token' };
|
||||
}
|
||||
|
||||
const parts = token.split('.');
|
||||
if (parts.length !== 3) return { ok: false, reason: 'bad_token' };
|
||||
|
||||
const [tsRaw, nonce, sig] = parts;
|
||||
const expected = sign(`${tsRaw}.${nonce}`);
|
||||
if (sig.length !== expected.length ||
|
||||
!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
|
||||
return { ok: false, reason: 'bad_token' };
|
||||
}
|
||||
|
||||
const issuedAt = Number(tsRaw);
|
||||
if (!Number.isFinite(issuedAt)) return { ok: false, reason: 'bad_token' };
|
||||
|
||||
const age = Date.now() - issuedAt;
|
||||
if (age > MAX_TOKEN_AGE_MS || age < -60_000) return { ok: false, reason: 'expired_token' };
|
||||
if (age < MIN_FILL_MS) return { ok: false, reason: 'too_fast' };
|
||||
if (usedTokens.has(token)) return { ok: false, reason: 'replayed_token' };
|
||||
|
||||
usedTokens.set(token, Date.now() + MAX_TOKEN_AGE_MS);
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
// ── Rate limiting ────────────────────────────────────────
|
||||
function clientIp(req) {
|
||||
// Requires `app.set('trust proxy', ...)` when running behind nginx.
|
||||
return req.ip || req.socket?.remoteAddress || 'unknown';
|
||||
}
|
||||
|
||||
/** Check the caps without consuming a slot. */
|
||||
function checkRateLimit(ip) {
|
||||
const now = Date.now();
|
||||
const list = hits.get(ip) || [];
|
||||
|
||||
for (const { windowMs, max, label } of RATE_WINDOWS) {
|
||||
const recent = list.filter(t => now - t < windowMs).length;
|
||||
if (recent >= max) return { ok: false, reason: 'rate_limited', label };
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
/** Record a successful submission against the caller's IP. */
|
||||
function recordSubmission(ip) {
|
||||
const now = Date.now();
|
||||
const widest = Math.max(...RATE_WINDOWS.map(w => w.windowMs));
|
||||
const list = (hits.get(ip) || []).filter(t => now - t < widest);
|
||||
list.push(now);
|
||||
hits.set(ip, list);
|
||||
}
|
||||
|
||||
// ── Turnstile ────────────────────────────────────────────
|
||||
async function verifyTurnstile(token, ip) {
|
||||
if (!turnstileEnabled) return { ok: true, skipped: true };
|
||||
if (typeof token !== 'string' || !token) return { ok: false, reason: 'captcha_missing' };
|
||||
|
||||
try {
|
||||
const body = new URLSearchParams({ secret: TURNSTILE_SECRET, response: token });
|
||||
if (ip && ip !== 'unknown') body.set('remoteip', ip);
|
||||
|
||||
const resp = await fetch(TURNSTILE_VERIFY_URL, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body,
|
||||
signal: AbortSignal.timeout(8000),
|
||||
});
|
||||
const data = await resp.json();
|
||||
|
||||
if (!data.success) {
|
||||
return { ok: false, reason: 'captcha_failed', codes: data['error-codes'] };
|
||||
}
|
||||
return { ok: true };
|
||||
} catch (err) {
|
||||
console.error('Turnstile verify error:', err.message);
|
||||
// Fail closed: an unverifiable challenge is not a passed challenge.
|
||||
return { ok: false, reason: 'captcha_unavailable' };
|
||||
}
|
||||
}
|
||||
|
||||
// ── Combined guard ───────────────────────────────────────
|
||||
const MESSAGES = {
|
||||
honeypot: 'Submission rejected.',
|
||||
missing_token: 'Your session expired. Please reload the page and try again.',
|
||||
bad_token: 'Your session expired. Please reload the page and try again.',
|
||||
expired_token: 'Your session expired. Please reload the page and try again.',
|
||||
replayed_token: 'This form was already submitted. Please reload the page to run another estimate.',
|
||||
too_fast: 'That was a little too quick — please take a moment and try again.',
|
||||
rate_limited: 'Too many submissions from this network. Please try again later.',
|
||||
captcha_missing: 'Please complete the verification challenge.',
|
||||
captcha_failed: 'Verification failed. Please try the challenge again.',
|
||||
captcha_unavailable: 'Verification is temporarily unavailable. Please try again in a moment.',
|
||||
};
|
||||
|
||||
const STATUS = { rate_limited: 429, honeypot: 400 };
|
||||
|
||||
/**
|
||||
* Run every protection layer for a public form POST.
|
||||
* Returns { ok: true, ip } or { ok: false, status, error, reason }.
|
||||
*/
|
||||
async function guardSubmission(req, { honeypotField = 'hp_company_url' } = {}) {
|
||||
const ip = clientIp(req);
|
||||
const body = req.body ?? {};
|
||||
|
||||
const fail = ({ reason, label }) => ({
|
||||
ok: false,
|
||||
reason,
|
||||
status: STATUS[reason] ?? 403,
|
||||
error: label ? `${MESSAGES[reason]} (limit: ${label})` : MESSAGES[reason],
|
||||
});
|
||||
|
||||
// 1. Honeypot — any value at all means a bot filled every field it found.
|
||||
if (typeof body[honeypotField] === 'string' && body[honeypotField].trim() !== '') {
|
||||
console.warn(`[abuse] honeypot tripped from ${ip}`);
|
||||
return fail({ reason: 'honeypot' });
|
||||
}
|
||||
|
||||
// 2. Rate limit (checked before the outbound Turnstile call).
|
||||
const rate = checkRateLimit(ip);
|
||||
if (!rate.ok) {
|
||||
console.warn(`[abuse] rate limit hit by ${ip}`);
|
||||
return fail(rate);
|
||||
}
|
||||
|
||||
// 3. Signed single-use token + minimum fill time.
|
||||
const tok = verifyFormToken(body.formToken);
|
||||
if (!tok.ok) {
|
||||
console.warn(`[abuse] form token rejected (${tok.reason}) from ${ip}`);
|
||||
return fail(tok);
|
||||
}
|
||||
|
||||
// 4. CAPTCHA.
|
||||
const captcha = await verifyTurnstile(body.captchaToken, ip);
|
||||
if (!captcha.ok) {
|
||||
console.warn(`[abuse] captcha rejected (${captcha.reason}) from ${ip}`);
|
||||
return fail(captcha);
|
||||
}
|
||||
|
||||
recordSubmission(ip);
|
||||
return { ok: true, ip };
|
||||
}
|
||||
|
||||
function publicConfig() {
|
||||
return { turnstileSiteKey: turnstileEnabled ? TURNSTILE_SITE_KEY : null };
|
||||
}
|
||||
|
||||
// ── Housekeeping ─────────────────────────────────────────
|
||||
const sweep = setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [token, exp] of usedTokens) if (exp < now) usedTokens.delete(token);
|
||||
|
||||
const widest = Math.max(...RATE_WINDOWS.map(w => w.windowMs));
|
||||
for (const [ip, list] of hits) {
|
||||
const kept = list.filter(t => now - t < widest);
|
||||
if (kept.length) hits.set(ip, kept); else hits.delete(ip);
|
||||
}
|
||||
}, 10 * 60 * 1000);
|
||||
sweep.unref?.();
|
||||
|
||||
module.exports = {
|
||||
turnstileEnabled,
|
||||
issueFormToken,
|
||||
guardSubmission,
|
||||
publicConfig,
|
||||
clientIp,
|
||||
};
|
||||
30
server.js
30
server.js
@@ -16,6 +16,8 @@ const express = require('express');
|
||||
const Database = require('better-sqlite3');
|
||||
const OpenAI = require('openai');
|
||||
|
||||
const security = require('./security');
|
||||
|
||||
// ── Config ──────────────────────────────────────────────
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
@@ -107,9 +109,22 @@ const getAllLeads = db.prepare(`
|
||||
|
||||
// ── App ───────────────────────────────────────────────────
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.set('trust proxy', 1); // behind nginx — needed for correct client IPs
|
||||
app.use(express.json({ limit: '32kb' }));
|
||||
app.use(express.static(__dirname)); // serve the marketing site
|
||||
|
||||
// GET /api/form-config — public config the forms need (CAPTCHA site key)
|
||||
app.get('/api/form-config', (_req, res) => {
|
||||
res.set('Cache-Control', 'no-store');
|
||||
res.json(security.publicConfig());
|
||||
});
|
||||
|
||||
// GET /api/form-token — single-use, signed token proving the form was loaded
|
||||
app.get('/api/form-token', (_req, res) => {
|
||||
res.set('Cache-Control', 'no-store');
|
||||
res.json({ token: security.issueFormToken() });
|
||||
});
|
||||
|
||||
// POST /api/leads — capture a new preview sign-up
|
||||
app.post('/api/leads', (req, res) => {
|
||||
const { firstName, lastName, email, orgName, state, role, unitCount, betaInterest, source } = req.body ?? {};
|
||||
@@ -193,9 +208,11 @@ app.post('/api/calculate', async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (!aiClient) {
|
||||
saveCalcSubmission(null);
|
||||
return res.status(503).json({ error: 'AI service not configured.' });
|
||||
// ── Abuse protection: CAPTCHA, honeypot, form token, rate limit ──
|
||||
// Runs before anything is written to the DB or sent to the AI provider.
|
||||
const guard = await security.guardSubmission(req);
|
||||
if (!guard.ok) {
|
||||
return res.status(guard.status).json({ error: guard.error, blocked: true });
|
||||
}
|
||||
|
||||
const {
|
||||
@@ -207,6 +224,11 @@ app.post('/api/calculate', async (req, res) => {
|
||||
return res.status(400).json({ error: 'homesites and annualIncome are required.' });
|
||||
}
|
||||
|
||||
if (!aiClient) {
|
||||
saveCalcSubmission(null);
|
||||
return res.status(503).json({ error: 'AI service not configured.' });
|
||||
}
|
||||
|
||||
const fmt = n => '$' + Math.round(n).toLocaleString();
|
||||
const typeLabel = { sfh: 'single-family home', townhomes: 'townhome', condos: 'condo', mixed: 'mixed-use' }[propertyType] || '';
|
||||
const freqDivisor = { monthly: 12, quarterly: 4, annually: 1 }[paymentFreq] || 12;
|
||||
|
||||
23
sitemap.xml
23
sitemap.xml
@@ -37,11 +37,32 @@
|
||||
<!-- Insights / Blog -->
|
||||
<url>
|
||||
<loc>https://www.hoaledgeriq.com/articles/</loc>
|
||||
<lastmod>2026-06-01</lastmod>
|
||||
<lastmod>2026-07-15</lastmod>
|
||||
<changefreq>weekly</changefreq>
|
||||
<priority>0.85</priority>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://www.hoaledgeriq.com/articles/hoa-reserve-fund-health-score</loc>
|
||||
<lastmod>2026-07-15</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://www.hoaledgeriq.com/articles/hoa-board-meeting-financial-questions</loc>
|
||||
<lastmod>2026-07-01</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://www.hoaledgeriq.com/articles/hoa-cash-flow-management-mistakes</loc>
|
||||
<lastmod>2026-06-15</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://www.hoaledgeriq.com/articles/hoa-financial-transparency</loc>
|
||||
<lastmod>2026-06-01</lastmod>
|
||||
|
||||
17
styles.css
17
styles.css
@@ -821,6 +821,23 @@ a.feature-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg)
|
||||
}
|
||||
.input-prefix-wrap input { padding-left: 28px; }
|
||||
.calc-error { color: var(--red); font-size: 13px; margin: 8px 0; font-weight: 500; }
|
||||
|
||||
/* Honeypot — visually and semantically hidden, but still fillable by bots.
|
||||
Deliberately not `display:none`, which the better bots skip. */
|
||||
.calc-hp {
|
||||
position: absolute !important;
|
||||
left: -9999px;
|
||||
top: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* CAPTCHA widget slot — collapsed until a challenge is actually rendered */
|
||||
.calc-captcha:empty { display: none; }
|
||||
.calc-captcha { margin: 12px 0 0; display: flex; justify-content: center; }
|
||||
.calc-submit-btn { width: 100%; justify-content: center; margin-top: 16px; }
|
||||
.calc-fine {
|
||||
font-size: 11px;
|
||||
|
||||
Reference in New Issue
Block a user