<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>OpenSolano - Civic Data &amp; Government Transparency for Solano County</title>
    <description>Open-source governance analysis covering Fairfield, Vallejo, Vacaville, Suisun City, Benicia, Dixon, and Rio Vista. Municipal budgets, impact fees, and civic transparency for all Solano County jurisdictions.</description>
    <link>https://opensolano.org</link>
    <atom:link
      href="https://opensolano.org/feed.xml"
      rel="self"
      type="application/rss+xml"/>
    <lastBuildDate>Fri, 24 Jul 2026 06:34:04 +0000</lastBuildDate>
    
    <item>
      <title>Vacaville Parcels: Activating Dormant Spaces Through Public Dialogue</title>
      <link>https://opensolano.org/2026/05/15/vacaville-parcels-activating-dormant-spaces.html</link>
      <guid isPermaLink="true">https://opensolano.org/2026/05/15/vacaville-parcels-activating-dormant-spaces.html</guid>
      <pubDate>Fri, 15 May 2026 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;Every city has them.
Vacant lots behind chain-link.
Shuttered storefronts on otherwise busy blocks.
Parcels that sit, year after year, while the city grows around them.&lt;/p&gt;

&lt;p&gt;In Vacaville, we’ve started mapping them.&lt;/p&gt;

&lt;h2 id=&quot;what-parcels-is&quot;&gt;What Parcels is&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/parcels/&quot;&gt;Parcels&lt;/a&gt; is an experiment in public attention.
It lists opportunity parcels in Vacaville – vacant or underutilized sites where something could happen if enough people cared about what went there.&lt;/p&gt;

&lt;p&gt;Each parcel has a map pin, a description, and a feedback form.
The form asks simple questions: What would you like to see here?
What matters most to you?
Would you participate?&lt;/p&gt;

&lt;p&gt;The data is placeholder right now.
The addresses are approximate, the APNs are generic, and the boundaries aren’t drawn.
That’s the point – this is a prototype, not a final product.
We’re testing whether the format works before investing in verified parcel data.&lt;/p&gt;

&lt;h2 id=&quot;why-this-matters&quot;&gt;Why this matters&lt;/h2&gt;

&lt;p&gt;Most land use decisions happen in planning commission meetings that few people attend.
By the time a project reaches public hearing, the developer has already spent months on plans.
The window for meaningful community input is narrow and often too late.&lt;/p&gt;

&lt;p&gt;What if we moved upstream?
What if, before anyone filed an application, neighbors could look at a vacant lot and say: here’s what we need here?&lt;/p&gt;

&lt;p&gt;That’s the idea behind /parcels.
Not to replace the formal planning process, but to create a visible, low-friction space for people to express what they want from their city – parcel by parcel, block by block.&lt;/p&gt;

&lt;h2 id=&quot;what-we-mean-by-activate&quot;&gt;What we mean by “activate”&lt;/h2&gt;

&lt;p&gt;Activation doesn’t require construction.
A dormant space can come alive with a farmers market, a popup, a mural, a community garden, a conversation.
The first step is just noticing the space exists and imagining it differently.&lt;/p&gt;

&lt;p&gt;/parcels is that first step: a public inventory of possibility.&lt;/p&gt;

&lt;h2 id=&quot;how-you-can-contribute&quot;&gt;How you can contribute&lt;/h2&gt;

&lt;p&gt;This is an open project.
If you want to help make it real, here’s what we need:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Verify the data.&lt;/strong&gt;
The current parcel list uses placeholder addresses and APNs.
If you know Vacaville’s vacant and underutilized parcels – especially downtown and along the Monte Vista corridor – we need real addresses, real APNs, and real zoning designations.
The county assessor’s parcel viewer is a good starting point.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Add photos.&lt;/strong&gt;
A vacant lot looks different on a map than it does from the sidewalk.
Street-level photos help people connect with a place.
If you’re walking past one of these sites, take a picture and send it in.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Submit feedback.&lt;/strong&gt;
Visit &lt;a href=&quot;/parcels/&quot;&gt;/parcels&lt;/a&gt;, pick a site, and tell us what you’d like to see there.
The form takes two minutes.
Every response helps build a picture of what the community actually wants.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Share it.&lt;/strong&gt;
The more people who see these parcels, the harder they are to ignore.
Share individual parcel pages with neighbors, local business owners, or anyone who’s ever said “I wish something would go there.”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Bring context.&lt;/strong&gt;
Some of these sites have history – prior proposals, environmental constraints, ownership complications.
If you know the backstory on a parcel, that context is valuable.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-its-built&quot;&gt;How it’s built&lt;/h2&gt;

&lt;p&gt;/parcels is part of &lt;a href=&quot;https://www.opensolano.org&quot;&gt;OpenSolano&lt;/a&gt;, a Jekyll static site focused on civic data for Solano County.
The parcel data lives in a JSON file.
Each parcel gets its own page with a map and feedback form powered by &lt;a href=&quot;https://touchpoints.app&quot;&gt;Touchpoints&lt;/a&gt;, an open-source platform for collecting public feedback.&lt;/p&gt;

&lt;p&gt;The code is open source.
If you’re technical and want to contribute data, fix something, or extend the concept to other jurisdictions, the repo is on GitHub.&lt;/p&gt;

&lt;h2 id=&quot;what-comes-next&quot;&gt;What comes next&lt;/h2&gt;

&lt;p&gt;If people use it, we’ll invest in making the data real: verified parcels, accurate boundaries, GIS integration.
If feedback clusters around specific sites, we can bring that signal to city staff and the planning commission as evidence of community interest.&lt;/p&gt;

&lt;p&gt;The long game is a city where participation doesn’t require attending a Tuesday night meeting.
Where the question “what do you want here?” is always open, always visible, always accumulating signal.&lt;/p&gt;

&lt;p&gt;/parcels is a small experiment toward that.
Try it. Tell us what you think.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/parcels/&quot;&gt;Browse Vacaville Parcels&lt;/a&gt;&lt;/p&gt;
</description>
      
      <category>parcels</category>
      
      <category>participation</category>
      
      <category>vacaville</category>
      
      <category>land use</category>
      
      <category>community</category>
      
    </item>
    
    <item>
      <title>Assessing the Public Sector: Stewardship, Service, and the Tax Recirculation Loop</title>
      <link>https://opensolano.org/2026/04/12/public-sector-assessment-and-tax-recirculation.html</link>
      <guid isPermaLink="true">https://opensolano.org/2026/04/12/public-sector-assessment-and-tax-recirculation.html</guid>
      <pubDate>Sun, 12 Apr 2026 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;A mid-sized Solano County city operates on roughly $280M a year.
About a third of that now services pension obligations, and the share keeps rising.
The city is also, legitimately, one of the largest employers in town — public jobs are a feature, not a bug.
So is the trajectory unsustainable, or just misunderstood?&lt;/p&gt;

&lt;p&gt;This post argues both questions are worth separating from the aggregate “is the budget balanced” question.
It also proposes a lens — the &lt;em&gt;tax recirculation coefficient&lt;/em&gt; — for thinking about how different economies respond to tax policy depending on how much of a worker’s tax dollar flows back to fund their own wage.&lt;/p&gt;

&lt;h2 id=&quot;three-accountabilities-usually-collapsed-into-one&quot;&gt;Three accountabilities, usually collapsed into one&lt;/h2&gt;

&lt;p&gt;When residents ask whether their city is well-run, they are usually asking three different questions at once.
Separating them makes the answer more honest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Service delivery.&lt;/strong&gt;
Outputs per dollar.
Lane-miles paved, permits issued per FTE, median emergency response time, park acres maintained.
These are measurable and comparable across jurisdictions.
This is what most people mean by “is government working.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stewardship.&lt;/strong&gt;
The balance-sheet trajectory.
Unfunded pension liability as a share of revenue.
Pension contribution as a share of the general fund.
Deferred maintenance backlog.
OPEB (retiree health) exposure.
Stewardship is usually invisible until it crowds out service delivery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Economic base.&lt;/strong&gt;
Jobs provided.
Wage floor set by public pay scales.
Counter-cyclical employment that stabilizes the local economy in downturns.
This is real value, and it rarely appears in budget documents as a benefit — only as a cost line.&lt;/p&gt;

&lt;p&gt;A city can look fine on any one dimension and be failing on another.
The diagnostic question is not “is the budget balanced this year” but &lt;strong&gt;“is stewardship crowding out service delivery, and how fast?”&lt;/strong&gt;
That ratio — pension-and-debt-service share versus discretionary service share, tracked over five or ten years — tells you whether the trajectory is extractive.&lt;/p&gt;

&lt;h2 id=&quot;the-tax-recirculation-coefficient&quot;&gt;The tax recirculation coefficient&lt;/h2&gt;

&lt;p&gt;Here is an observation that changed how I think about my own paycheck.&lt;/p&gt;

&lt;p&gt;I work in the public sector.
My wages are paid from a pool funded by taxes.
When I pay my taxes, a meaningful fraction of that dollar flows back into the same pool that pays me.
My “effective” tax rate — the rate at which dollars leave my household sector and do not return — is lower than the headline rate suggests.&lt;/p&gt;

&lt;p&gt;A private-sector worker’s tax dollar does not typically flow back to fund their own employer.
For them, tax is a more straightforward one-way transfer.&lt;/p&gt;

&lt;p&gt;Call the returning fraction &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;&lt;/strong&gt;, the &lt;em&gt;recirculation coefficient&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r = 0&lt;/code&gt; — a private-sector worker in an industry with no public contracts.
Every tax dollar is a pure outflow from their sector.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r = 1&lt;/code&gt; — a fully self-funded public sector (theoretical limit; nobody’s actually here).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r ≈ 0.3–0.5&lt;/code&gt; — a typical public employee in a locally-funded agency.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r ≈ 0.1–0.2&lt;/code&gt; — a private-sector worker in a company with meaningful government contracts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a moral claim.
It is a structural one.
And it has consequences for how a local economy responds to tax decisions.&lt;/p&gt;

&lt;h2 id=&quot;interactive-how-r-changes-the-effective-tax-dynamic&quot;&gt;Interactive: how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; changes the effective tax dynamic&lt;/h2&gt;

&lt;p&gt;Drag the slider to see how the recirculation coefficient changes the effective flow of a worker’s tax dollar.&lt;/p&gt;

&lt;div class=&quot;my-8 rounded-xl border border-gray-200 bg-gray-50 p-6&quot;&gt;
  &lt;div class=&quot;flex items-center justify-between mb-4&quot;&gt;
    &lt;label for=&quot;r-slider&quot; class=&quot;text-sm font-semibold text-gray-900&quot;&gt;Recirculation coefficient (r)&lt;/label&gt;
    &lt;span id=&quot;r-value&quot; class=&quot;text-sm font-mono text-amber-700&quot;&gt;0.00&lt;/span&gt;
  &lt;/div&gt;
  &lt;input type=&quot;range&quot; id=&quot;r-slider&quot; min=&quot;0&quot; max=&quot;1&quot; step=&quot;0.01&quot; value=&quot;0&quot; class=&quot;w-full accent-amber-600&quot; /&gt;
  &lt;div class=&quot;mt-2 flex justify-between text-xs text-gray-500&quot;&gt;
    &lt;span&gt;pure private&lt;/span&gt;
    &lt;span&gt;typical private w/ gov contracts&lt;/span&gt;
    &lt;span&gt;typical public employee&lt;/span&gt;
    &lt;span&gt;fully self-funded&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class=&quot;mt-6 grid grid-cols-1 sm:grid-cols-3 gap-4 text-center&quot;&gt;
    &lt;div class=&quot;rounded-lg bg-white border border-gray-200 p-4&quot;&gt;
      &lt;div class=&quot;text-xs uppercase tracking-wide text-gray-500&quot;&gt;Headline tax rate&lt;/div&gt;
      &lt;div class=&quot;mt-1 text-2xl font-bold text-gray-900&quot;&gt;25%&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;rounded-lg bg-white border border-gray-200 p-4&quot;&gt;
      &lt;div class=&quot;text-xs uppercase tracking-wide text-gray-500&quot;&gt;Effective outflow&lt;/div&gt;
      &lt;div id=&quot;effective-rate&quot; class=&quot;mt-1 text-2xl font-bold text-amber-700&quot;&gt;25.0%&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;rounded-lg bg-white border border-gray-200 p-4&quot;&gt;
      &lt;div class=&quot;text-xs uppercase tracking-wide text-gray-500&quot;&gt;Returns via wage pool&lt;/div&gt;
      &lt;div id=&quot;return-rate&quot; class=&quot;mt-1 text-2xl font-bold text-emerald-600&quot;&gt;0.0%&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;

  &lt;p id=&quot;r-narrative&quot; class=&quot;mt-4 text-sm text-gray-600 leading-relaxed&quot;&gt;
    At &lt;strong&gt;r = 0&lt;/strong&gt;, every tax dollar leaves the worker&apos;s sector.
    This is the case assumed by most public finance intuition.
  &lt;/p&gt;
&lt;/div&gt;

&lt;script&gt;
(function() {
  var slider = document.getElementById(&apos;r-slider&apos;);
  var rVal = document.getElementById(&apos;r-value&apos;);
  var effEl = document.getElementById(&apos;effective-rate&apos;);
  var retEl = document.getElementById(&apos;return-rate&apos;);
  var narr = document.getElementById(&apos;r-narrative&apos;);
  var headline = 0.25;

  function update() {
    var r = parseFloat(slider.value);
    var effective = headline * (1 - r);
    var returned = headline * r;
    rVal.textContent = r.toFixed(2);
    effEl.textContent = (effective * 100).toFixed(1) + &apos;%&apos;;
    retEl.textContent = (returned * 100).toFixed(1) + &apos;%&apos;;

    var msg;
    if (r &lt; 0.1) {
      msg = &apos;At &lt;strong&gt;r = &apos; + r.toFixed(2) + &apos;&lt;/strong&gt;, nearly every tax dollar leaves the worker\&apos;s sector. This is the case assumed by most public finance intuition.&apos;;
    } else if (r &lt; 0.35) {
      msg = &apos;At &lt;strong&gt;r = &apos; + r.toFixed(2) + &apos;&lt;/strong&gt;, a small but real fraction of taxes returns to fund wages in the same sector. Typical for private workers in regions with meaningful government contracting.&apos;;
    } else if (r &lt; 0.7) {
      msg = &apos;At &lt;strong&gt;r = &apos; + r.toFixed(2) + &apos;&lt;/strong&gt;, a substantial share of tax dollars recirculates. This is where many public employees in locally-funded agencies sit. Tax cuts here directly compress the wage pool.&apos;;
    } else {
      msg = &apos;At &lt;strong&gt;r = &apos; + r.toFixed(2) + &apos;&lt;/strong&gt;, the sector is nearly self-funded. Stabilizing, but the feedback loop can ossify — political incentives around taxation collapse because payers and recipients are the same population.&apos;;
    }
    narr.innerHTML = msg;
  }

  slider.addEventListener(&apos;input&apos;, update);
  update();
})();
&lt;/script&gt;

&lt;h2 id=&quot;why-r-matters-at-the-policy-level&quot;&gt;Why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; matters at the policy level&lt;/h2&gt;

&lt;p&gt;Two cities with the same headline tax rate can have very different political dynamics depending on their aggregate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;High-&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; economies&lt;/strong&gt; (company towns, heavy public-sector cities).
Tax cuts hurt more because residents are partly cutting their own wages.
Tax hikes sting less for the same reason.
The system is stabilizing but can ossify — political incentives around fiscal discipline weaken when payers and beneficiaries overlap heavily.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Low-&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; economies.&lt;/strong&gt;
Sharper political conflict over taxation, because the population that pays is structurally distinct from the population that receives.
Budget fights are more adversarial.
Reform pressure is higher but so is volatility.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mixed economies&lt;/strong&gt; — most actual places.
The ratio shapes which coalitions form around budget decisions, which ballot measures pass, and how quickly structural problems get addressed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is adjacent to but distinct from fiscal incidence analysis, which usually treats “who pays, who benefits” as a static question.
The recirculation lens treats it as a feedback loop.&lt;/p&gt;

&lt;h2 id=&quot;a-causal-loop-diagram-of-the-citys-fiscal-system&quot;&gt;A causal loop diagram of the city’s fiscal system&lt;/h2&gt;

&lt;p&gt;Here is an intermediately complex stocks-and-flows sketch — eight variables, three feedback loops — that illustrates how pension obligations, service delivery, and the recirculation loop interact.&lt;/p&gt;

&lt;div class=&quot;my-8 overflow-x-auto rounded-xl border border-gray-200 bg-white p-6&quot;&gt;
&lt;svg viewBox=&quot;0 0 820 520&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; class=&quot;w-full h-auto&quot; role=&quot;img&quot; aria-labelledby=&quot;cld-title cld-desc&quot;&gt;
  &lt;title id=&quot;cld-title&quot;&gt;Causal loop diagram: municipal fiscal system&lt;/title&gt;
  &lt;desc id=&quot;cld-desc&quot;&gt;Diagram showing three feedback loops: a reinforcing loop between public wages and the general fund (R1), a balancing loop between pension obligations and service quality (B1), and a slow reinforcing decline loop through tax base erosion (R2).&lt;/desc&gt;

  &lt;defs&gt;
    &lt;marker id=&quot;arrow-pos&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L10,5 L0,10 z&quot; fill=&quot;#059669&quot; /&gt;
    &lt;/marker&gt;
    &lt;marker id=&quot;arrow-neg&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto&quot;&gt;
      &lt;path d=&quot;M0,0 L10,5 L0,10 z&quot; fill=&quot;#dc2626&quot; /&gt;
    &lt;/marker&gt;
  &lt;/defs&gt;

  &lt;!-- Nodes: stocks as rectangles, flows/variables as ellipses --&gt;
  &lt;!-- Stocks --&gt;
  &lt;rect x=&quot;340&quot; y=&quot;20&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#fef3c7&quot; stroke=&quot;#d97706&quot; stroke-width=&quot;2&quot; /&gt;
  &lt;text x=&quot;410&quot; y=&quot;50&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;600&quot; fill=&quot;#78350f&quot;&gt;General Fund&lt;/text&gt;

  &lt;rect x=&quot;600&quot; y=&quot;150&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#fee2e2&quot; stroke=&quot;#dc2626&quot; stroke-width=&quot;2&quot; /&gt;
  &lt;text x=&quot;680&quot; y=&quot;180&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;600&quot; fill=&quot;#7f1d1d&quot;&gt;Pension Liability&lt;/text&gt;

  &lt;rect x=&quot;60&quot; y=&quot;150&quot; width=&quot;160&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#dbeafe&quot; stroke=&quot;#2563eb&quot; stroke-width=&quot;2&quot; /&gt;
  &lt;text x=&quot;140&quot; y=&quot;180&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;600&quot; fill=&quot;#1e3a8a&quot;&gt;Public Wages (stock)&lt;/text&gt;

  &lt;rect x=&quot;340&quot; y=&quot;280&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;6&quot; fill=&quot;#dcfce7&quot; stroke=&quot;#16a34a&quot; stroke-width=&quot;2&quot; /&gt;
  &lt;text x=&quot;410&quot; y=&quot;310&quot; text-anchor=&quot;middle&quot; font-size=&quot;14&quot; font-weight=&quot;600&quot; fill=&quot;#14532d&quot;&gt;Service Quality&lt;/text&gt;

  &lt;!-- Flow variables --&gt;
  &lt;ellipse cx=&quot;140&quot; cy=&quot;290&quot; rx=&quot;80&quot; ry=&quot;25&quot; fill=&quot;#eff6ff&quot; stroke=&quot;#60a5fa&quot; stroke-width=&quot;1.5&quot; /&gt;
  &lt;text x=&quot;140&quot; y=&quot;295&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#1e40af&quot;&gt;Tax Revenue (via r)&lt;/text&gt;

  &lt;ellipse cx=&quot;680&quot; cy=&quot;290&quot; rx=&quot;80&quot; ry=&quot;25&quot; fill=&quot;#fef2f2&quot; stroke=&quot;#f87171&quot; stroke-width=&quot;1.5&quot; /&gt;
  &lt;text x=&quot;680&quot; y=&quot;295&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#991b1b&quot;&gt;Pension Contribution&lt;/text&gt;

  &lt;ellipse cx=&quot;140&quot; cy=&quot;420&quot; rx=&quot;80&quot; ry=&quot;25&quot; fill=&quot;#f5f3ff&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;1.5&quot; /&gt;
  &lt;text x=&quot;140&quot; y=&quot;425&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#5b21b6&quot;&gt;Tax Base / Population&lt;/text&gt;

  &lt;ellipse cx=&quot;680&quot; cy=&quot;420&quot; rx=&quot;80&quot; ry=&quot;25&quot; fill=&quot;#f5f3ff&quot; stroke=&quot;#a78bfa&quot; stroke-width=&quot;1.5&quot; /&gt;
  &lt;text x=&quot;680&quot; y=&quot;425&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; fill=&quot;#5b21b6&quot;&gt;Outmigration Pressure&lt;/text&gt;

  &lt;!-- Arrows with polarity labels --&gt;
  &lt;!-- R1: General Fund -&gt; Public Wages (+) --&gt;
  &lt;path d=&quot;M340,50 Q230,70 200,150&quot; fill=&quot;none&quot; stroke=&quot;#059669&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-pos)&quot; /&gt;
  &lt;text x=&quot;245&quot; y=&quot;100&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#059669&quot;&gt;+&lt;/text&gt;

  &lt;!-- Public Wages -&gt; Tax Revenue (+) --&gt;
  &lt;path d=&quot;M140,200 L140,265&quot; fill=&quot;none&quot; stroke=&quot;#059669&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-pos)&quot; /&gt;
  &lt;text x=&quot;148&quot; y=&quot;235&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#059669&quot;&gt;+&lt;/text&gt;

  &lt;!-- Tax Revenue -&gt; General Fund (+) [closes R1] --&gt;
  &lt;path d=&quot;M220,285 Q330,240 370,70&quot; fill=&quot;none&quot; stroke=&quot;#059669&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-pos)&quot; /&gt;
  &lt;text x=&quot;315&quot; y=&quot;180&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#059669&quot;&gt;+&lt;/text&gt;

  &lt;!-- R1 label --&gt;
  &lt;circle cx=&quot;260&quot; cy=&quot;160&quot; r=&quot;18&quot; fill=&quot;#ecfdf5&quot; stroke=&quot;#059669&quot; stroke-width=&quot;1.5&quot; /&gt;
  &lt;text x=&quot;260&quot; y=&quot;165&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; font-weight=&quot;700&quot; fill=&quot;#059669&quot;&gt;R1&lt;/text&gt;

  &lt;!-- B1: Pension Liability -&gt; Pension Contribution (+) --&gt;
  &lt;path d=&quot;M680,200 L680,265&quot; fill=&quot;none&quot; stroke=&quot;#059669&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-pos)&quot; /&gt;
  &lt;text x=&quot;688&quot; y=&quot;235&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#059669&quot;&gt;+&lt;/text&gt;

  &lt;!-- Pension Contribution -&gt; General Fund (-) [drains it] --&gt;
  &lt;path d=&quot;M600,290 Q500,230 480,70&quot; fill=&quot;none&quot; stroke=&quot;#dc2626&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-neg)&quot; /&gt;
  &lt;text x=&quot;510&quot; y=&quot;180&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#dc2626&quot;&gt;−&lt;/text&gt;

  &lt;!-- General Fund -&gt; Service Quality (+) --&gt;
  &lt;path d=&quot;M410,70 L410,280&quot; fill=&quot;none&quot; stroke=&quot;#059669&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-pos)&quot; /&gt;
  &lt;text x=&quot;418&quot; y=&quot;180&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#059669&quot;&gt;+&lt;/text&gt;

  &lt;!-- Service Quality -&gt; Pension Liability (indirect via tax tolerance): we&apos;ll draw Service Quality -&gt; Outmigration (-) instead --&gt;
  &lt;path d=&quot;M480,305 Q580,360 600,420&quot; fill=&quot;none&quot; stroke=&quot;#dc2626&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-neg)&quot; /&gt;
  &lt;text x=&quot;555&quot; y=&quot;370&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#dc2626&quot;&gt;−&lt;/text&gt;

  &lt;!-- B1 label --&gt;
  &lt;circle cx=&quot;555&quot; cy=&quot;160&quot; r=&quot;18&quot; fill=&quot;#fef2f2&quot; stroke=&quot;#dc2626&quot; stroke-width=&quot;1.5&quot; /&gt;
  &lt;text x=&quot;555&quot; y=&quot;165&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; font-weight=&quot;700&quot; fill=&quot;#dc2626&quot;&gt;B1&lt;/text&gt;

  &lt;!-- R2: Outmigration -&gt; Tax Base (-) --&gt;
  &lt;path d=&quot;M600,425 L220,422&quot; fill=&quot;none&quot; stroke=&quot;#dc2626&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-neg)&quot; /&gt;
  &lt;text x=&quot;410&quot; y=&quot;415&quot; text-anchor=&quot;middle&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#dc2626&quot;&gt;−&lt;/text&gt;

  &lt;!-- Tax Base -&gt; Tax Revenue (+) --&gt;
  &lt;path d=&quot;M140,395 L140,315&quot; fill=&quot;none&quot; stroke=&quot;#059669&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-pos)&quot; /&gt;
  &lt;text x=&quot;148&quot; y=&quot;360&quot; font-size=&quot;13&quot; font-weight=&quot;700&quot; fill=&quot;#059669&quot;&gt;+&lt;/text&gt;

  &lt;!-- R2 label --&gt;
  &lt;circle cx=&quot;410&quot; cy=&quot;460&quot; r=&quot;18&quot; fill=&quot;#fef2f2&quot; stroke=&quot;#dc2626&quot; stroke-width=&quot;1.5&quot; /&gt;
  &lt;text x=&quot;410&quot; y=&quot;465&quot; text-anchor=&quot;middle&quot; font-size=&quot;12&quot; font-weight=&quot;700&quot; fill=&quot;#dc2626&quot;&gt;R2&lt;/text&gt;

  &lt;!-- Legend --&gt;
  &lt;g transform=&quot;translate(20,20)&quot;&gt;
    &lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;200&quot; height=&quot;90&quot; rx=&quot;6&quot; fill=&quot;#f9fafb&quot; stroke=&quot;#d1d5db&quot; stroke-width=&quot;1&quot; /&gt;
    &lt;text x=&quot;10&quot; y=&quot;18&quot; font-size=&quot;11&quot; font-weight=&quot;700&quot; fill=&quot;#374151&quot;&gt;Legend&lt;/text&gt;
    &lt;line x1=&quot;10&quot; y1=&quot;34&quot; x2=&quot;40&quot; y2=&quot;34&quot; stroke=&quot;#059669&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-pos)&quot; /&gt;
    &lt;text x=&quot;48&quot; y=&quot;38&quot; font-size=&quot;11&quot; fill=&quot;#374151&quot;&gt;same-direction (+)&lt;/text&gt;
    &lt;line x1=&quot;10&quot; y1=&quot;54&quot; x2=&quot;40&quot; y2=&quot;54&quot; stroke=&quot;#dc2626&quot; stroke-width=&quot;2&quot; marker-end=&quot;url(#arrow-neg)&quot; /&gt;
    &lt;text x=&quot;48&quot; y=&quot;58&quot; font-size=&quot;11&quot; fill=&quot;#374151&quot;&gt;opposite-direction (−)&lt;/text&gt;
    &lt;rect x=&quot;10&quot; y=&quot;68&quot; width=&quot;14&quot; height=&quot;10&quot; fill=&quot;#fef3c7&quot; stroke=&quot;#d97706&quot; /&gt;
    &lt;text x=&quot;30&quot; y=&quot;78&quot; font-size=&quot;11&quot; fill=&quot;#374151&quot;&gt;stock&lt;/text&gt;
    &lt;ellipse cx=&quot;90&quot; cy=&quot;73&quot; rx=&quot;14&quot; ry=&quot;6&quot; fill=&quot;#eff6ff&quot; stroke=&quot;#60a5fa&quot; /&gt;
    &lt;text x=&quot;112&quot; y=&quot;78&quot; font-size=&quot;11&quot; fill=&quot;#374151&quot;&gt;flow&lt;/text&gt;
  &lt;/g&gt;
&lt;/svg&gt;
&lt;/div&gt;

&lt;p&gt;Three loops worth naming:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;R1 — the wage recirculation loop (reinforcing, fast).&lt;/strong&gt;
General fund pays public wages.
Public wages generate tax revenue (scaled by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;).
Tax revenue feeds the general fund.
This is the loop my opening observation describes.
It stabilizes the system in normal times and makes public employment a genuine counter-cyclical asset.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;B1 — the stewardship loop (balancing, structural).&lt;/strong&gt;
Pension liabilities drive required contributions.
Contributions drain the general fund.
The general fund that remains funds services.
When pension share grows faster than revenue, services erode.
This is the loop my city is losing.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;R2 — the slow decline loop (reinforcing, years to decades).&lt;/strong&gt;
Eroded services increase outmigration pressure.
Outmigration shrinks the tax base.
A smaller tax base reduces revenue.
Less revenue means more pressure on services.
Once R2 dominates, recovery is expensive and slow — this is the Vallejo-in-2008 story.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interesting policy question is &lt;strong&gt;which loop dominates at which horizon&lt;/strong&gt;, and what interventions shift that.
Pension reform acts on B1.
Economic development acts on R2.
Neither is visible in a single fiscal year.&lt;/p&gt;

&lt;h2 id=&quot;what-this-suggests-for-civic-assessment&quot;&gt;What this suggests for civic assessment&lt;/h2&gt;

&lt;p&gt;A productive public-sector performance assessment should, at minimum, track:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Service delivery ratios&lt;/strong&gt; — outputs per dollar, year over year, and benchmarked against peer jurisdictions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Stewardship trajectory&lt;/strong&gt; — pension-and-debt-service as a share of general fund, five- and ten-year trend.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Recirculation estimate&lt;/strong&gt; — rough &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; for the local economy, to calibrate how tax policy will actually land.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Loop dominance&lt;/strong&gt; — which of R1, B1, R2 is moving fastest, and in which direction.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these are hard to compute.
Most are buried in the ACFR (the comprehensive annual financial report) that every city publishes.
The work is surfacing them in a form residents can read, and tracking them over time so trajectories are visible.&lt;/p&gt;

&lt;p&gt;That’s the direction OpenSolano is heading.
If you want to help — or if you want to argue with any of the framing above — &lt;a href=&quot;mailto:ryan@civic.studio&quot;&gt;get in touch&lt;/a&gt; or join the next &lt;a href=&quot;/meetup/&quot;&gt;meetup&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;further-reading-and-caveats&quot;&gt;Further reading and caveats&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;The recirculation coefficient is a sketch, not a calibrated model.
A real estimate would account for indirect recirculation (public employee spending at local businesses that pay local taxes), progressive rate structures, and the share of taxes that go to non-local levels of government.&lt;/li&gt;
  &lt;li&gt;The CLD omits several real loops: state and federal transfers, bond issuance, capital project cycles, and the political economy of ballot measures.
Any of these can dominate in particular years.&lt;/li&gt;
  &lt;li&gt;“Unsustainable” is a direction, not a state.
A trajectory that looks dire over twenty years can be redirected by five years of disciplined stewardship.
The point of the assessment is to make the trajectory visible early enough to act.&lt;/li&gt;
&lt;/ul&gt;
</description>
      
      <category>municipal finance</category>
      
      <category>pensions</category>
      
      <category>public sector</category>
      
      <category>systems thinking</category>
      
      <category>transparency</category>
      
    </item>
    
    <item>
      <title>FY2025 Budget Comparison: Fairfield, Vallejo, and Vacaville</title>
      <link>https://opensolano.org/2026/03/12/solano-county-fy2025-budget-comparison.html</link>
      <guid isPermaLink="true">https://opensolano.org/2026/03/12/solano-county-fy2025-budget-comparison.html</guid>
      <pubDate>Thu, 12 Mar 2026 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;How do Solano County’s three largest cities allocate their general fund dollars? We compiled FY2024-25 adopted budget data for Fairfield, Vallejo, and Vacaville to make side-by-side comparison possible.&lt;/p&gt;

&lt;h2 id=&quot;the-big-picture&quot;&gt;The Big Picture&lt;/h2&gt;

&lt;p&gt;All three cities share a common pattern: &lt;strong&gt;public safety dominates general fund spending&lt;/strong&gt;, consuming roughly half of every discretionary dollar. Beyond that, the similarities start to diverge.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;City&lt;/th&gt;
      &lt;th&gt;Population&lt;/th&gt;
      &lt;th&gt;General Fund Revenue&lt;/th&gt;
      &lt;th&gt;General Fund Expenditure&lt;/th&gt;
      &lt;th&gt;Balance&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Fairfield&lt;/td&gt;
      &lt;td&gt;119,881&lt;/td&gt;
      &lt;td&gt;$168.2M&lt;/td&gt;
      &lt;td&gt;$165.8M&lt;/td&gt;
      &lt;td&gt;+$2.4M&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vallejo&lt;/td&gt;
      &lt;td&gt;121,692&lt;/td&gt;
      &lt;td&gt;$152.7M&lt;/td&gt;
      &lt;td&gt;$158.3M&lt;/td&gt;
      &lt;td&gt;-$5.6M&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vacaville&lt;/td&gt;
      &lt;td&gt;103,590&lt;/td&gt;
      &lt;td&gt;$131.4M&lt;/td&gt;
      &lt;td&gt;$128.9M&lt;/td&gt;
      &lt;td&gt;+$2.5M&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Vallejo is the only city spending more than it takes in from its general fund — a structural deficit that reflects ongoing fiscal pressures from its 2008 bankruptcy recovery and pension obligations.&lt;/p&gt;

&lt;h2 id=&quot;where-the-money-goes&quot;&gt;Where the Money Goes&lt;/h2&gt;

&lt;p&gt;Public safety (police and fire) is the largest category for all three cities, but the shares differ:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vallejo: 51.9%&lt;/strong&gt; of general fund to public safety — the highest share, driven in part by consent decree requirements and post-bankruptcy staffing rebuilds&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fairfield: 47.3%&lt;/strong&gt; — mid-range, reflecting a larger city footprint with more balanced service demands&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vacaville: 47.9%&lt;/strong&gt; — similar to Fairfield despite a smaller population&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implication: when residents ask “why can’t the city fix the roads / open the pool / hire more code enforcement,” the answer is often that half the budget is already committed before those conversations begin.&lt;/p&gt;

&lt;h2 id=&quot;where-the-money-comes-from&quot;&gt;Where the Money Comes From&lt;/h2&gt;

&lt;p&gt;Sales tax is the top revenue source for all three cities, but reliance varies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vacaville: 34.4%&lt;/strong&gt; from sales tax — highest dependence, reflecting its role as a regional retail center&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Fairfield: 31.1%&lt;/strong&gt; — also retail-dependent, with Travis Air Force Base driving commercial activity&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vallejo: 28.9%&lt;/strong&gt; — lower base sales tax share, supplemented by Measure B (a voter-approved sales tax add-on generating $15.2M)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Property tax is the second-largest source everywhere, ranging from 24.9% (Fairfield) to 25.3% (Vallejo). This relative uniformity makes sense — Proposition 13 constrains property tax growth statewide.&lt;/p&gt;

&lt;h2 id=&quot;revenue-per-capita&quot;&gt;Revenue Per Capita&lt;/h2&gt;

&lt;p&gt;Normalizing for population reveals meaningful differences:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;City&lt;/th&gt;
      &lt;th&gt;Revenue per Capita&lt;/th&gt;
      &lt;th&gt;Expenditure per Capita&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Fairfield&lt;/td&gt;
      &lt;td&gt;$1,403&lt;/td&gt;
      &lt;td&gt;$1,383&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vallejo&lt;/td&gt;
      &lt;td&gt;$1,255&lt;/td&gt;
      &lt;td&gt;$1,301&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Vacaville&lt;/td&gt;
      &lt;td&gt;$1,268&lt;/td&gt;
      &lt;td&gt;$1,244&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Fairfield collects and spends the most per resident. Vallejo collects the least but spends more than it takes in — a gap that must be closed through growth, cuts, or new revenue measures.&lt;/p&gt;

&lt;h2 id=&quot;what-this-data-doesnt-show&quot;&gt;What This Data Doesn’t Show&lt;/h2&gt;

&lt;p&gt;Budget documents tell you what a city &lt;em&gt;plans&lt;/em&gt; to spend, not what it &lt;em&gt;actually&lt;/em&gt; spends. Actual expenditures often differ from adopted budgets due to mid-year adjustments, unfilled positions, and unexpected costs. The Annual Comprehensive Financial Reports (ACFRs), published after the fiscal year ends, provide the true accounting.&lt;/p&gt;

&lt;p&gt;This comparison also excludes:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Pension obligations&lt;/strong&gt;: CalPERS unfunded liabilities are an additional cost pressure not fully visible in annual budget documents&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Capital budgets&lt;/strong&gt;: Infrastructure investments funded through bonds, grants, and special funds&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Enterprise funds&lt;/strong&gt;: Water, sewer, and other services that operate on fee revenue rather than general fund dollars&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Special districts&lt;/strong&gt;: Fire protection, transit, and other services provided by entities outside city government&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-comes-next&quot;&gt;What Comes Next&lt;/h2&gt;

&lt;p&gt;We plan to add budget data for Benicia, Dixon, Suisun City, and Rio Vista as those cities publish their FY2025 adopted budgets. We’re also building a &lt;a href=&quot;/public-funds/&quot;&gt;Public Funds Tracker&lt;/a&gt; that will make this data interactive and include historical trends.&lt;/p&gt;

&lt;p&gt;If you have access to budget documents we’re missing, or if you spot an error in this data, please &lt;a href=&quot;mailto:ryan@civic.studio?subject=Budget Data Feedback&quot;&gt;let us know&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Data sourced from adopted budget documents published by each city’s finance department. Population figures from California Department of Finance 2025 estimates. See the &lt;a href=&quot;/public-funds/&quot;&gt;datasets page&lt;/a&gt; for more detail on methodology and sources.&lt;/em&gt;&lt;/p&gt;
</description>
      
      <category>budgets</category>
      
      <category>transparency</category>
      
      <category>municipal finance</category>
      
      <category>fairfield</category>
      
      <category>vallejo</category>
      
      <category>vacaville</category>
      
    </item>
    
    <item>
      <title>Renewing Measure T: What Journalists Should Know</title>
      <link>https://opensolano.org/2024/09/06/renewing-measure-t.html</link>
      <guid isPermaLink="true">https://opensolano.org/2024/09/06/renewing-measure-t.html</guid>
      <pubDate>Fri, 06 Sep 2024 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;This reporter’s brief outlines what Measure T is, why it’s up for renewal, the fiscal impacts, accountability mechanisms, and story angles you can localize for your audience. Copy, adapt, and cite original sources linked below.&lt;/p&gt;

&lt;h2 id=&quot;the-basics&quot;&gt;The Basics&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;What it is: A local transactions and use tax (sales tax) that funds transportation investments countywide (roads, transit, safety, bike/ped improvements).&lt;/li&gt;
  &lt;li&gt;Rate: Typically 0.25% to 0.5% stacked on top of the state base. Confirm current rate and renewal proposal text for exact figures.&lt;/li&gt;
  &lt;li&gt;Term: Most renewals propose 20–30 years to support bonding and long-horizon capital plans.&lt;/li&gt;
  &lt;li&gt;Admin: Usually administered via the countywide transportation authority (e.g., Solano Transportation Authority, STA) with expenditure plans adopted by ordinance.&lt;/li&gt;
  &lt;li&gt;Voter threshold: Transportation special tax renewals often require two-thirds (66.7%) voter approval if revenues are legally earmarked; confirm with county counsel/elections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;whats-changing-in-the-renewal&quot;&gt;What’s Changing In The Renewal&lt;/h2&gt;

&lt;p&gt;Ask and report on differences between the existing and proposed measure:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Rate and term: Any change to the rate or years (e.g., extend 30 years vs. sunset in 203X)?&lt;/li&gt;
  &lt;li&gt;Project list: New corridor projects, interchanges, safety hotspots, transit frequency, paratransit, safe routes to school, maintenance backlog.&lt;/li&gt;
  &lt;li&gt;Revenue sharing: City/County formula changes; “local streets and roads” flexible share vs. set-asides.&lt;/li&gt;
  &lt;li&gt;Equity and safety: Dedicated funding for underserved neighborhoods, crash reduction targets, ADA curb ramps, heat/flood resilience.&lt;/li&gt;
  &lt;li&gt;Climate alignment: Transit/bike/ped priorities, VMT reduction strategies, zero-emission bus deployment, coordination with CAPs and RTP/SCS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;money-how-much-from-where-for-what&quot;&gt;Money: How Much, From Where, For What&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Revenue forecast: $X per year, $Y over the measure term (state your assumed growth and elasticity; cite source memo/table).&lt;/li&gt;
  &lt;li&gt;Sources: Local add-on sales tax on taxable retail; sensitivity to recessions and retail mix shifts (auto sales, e‑commerce allocation rules).&lt;/li&gt;
  &lt;li&gt;Uses: Break down by program buckets (percentages) and example projects. Show what portion is “pay‑as‑you‑go” vs. leveraged for grants/bonds.&lt;/li&gt;
  &lt;li&gt;Leverage: How local $1 unlocks $3–$6 in state/federal funds (illustrate with recent ATP, SB1, RAISE, MEGA awards if applicable).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;quick-math-you-can-localize&quot;&gt;Quick math you can localize&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Household impact: Multiply local median taxable retail spend by the add-on rate. Note that essentials (most groceries, rent, services) are not taxed.&lt;/li&gt;
  &lt;li&gt;City-by-city share: If there’s a population/road-mile formula, estimate annual allocations for each city and unincorporated area.&lt;/li&gt;
  &lt;li&gt;Backlog framing: Compare expected local streets/roads allocations to pavement management needs (PCI targets) to illustrate the gap.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;accountability--oversight&quot;&gt;Accountability &amp;amp; Oversight&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Independent Citizens’ Oversight Committee: Membership, meeting cadence, annual reports, Brown Act compliance, vacancies.&lt;/li&gt;
  &lt;li&gt;Annual audits: Financial + compliance audits published on the authority’s website; include links.&lt;/li&gt;
  &lt;li&gt;Performance measures: Safety (KSI reductions), state of good repair, on-time delivery, cost containment, climate/air metrics.&lt;/li&gt;
  &lt;li&gt;Project controls: Programming policies, change-order thresholds, risk management, right-of-way readiness standards.&lt;/li&gt;
  &lt;li&gt;Transparency: Public project dashboard, spend-to-date, schedule status, map of funded locations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;timeline--ballot-mechanics&quot;&gt;Timeline &amp;amp; Ballot Mechanics&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Key dates: Board action to place on ballot, ballot argument deadlines, voter guide publication, vote date, effective/sunset dates.&lt;/li&gt;
  &lt;li&gt;Ballot label/summary: 75-word limit highlights; verify claims about “no increase” or “independent oversight”.&lt;/li&gt;
  &lt;li&gt;Legal standards: Two-thirds vs. simple majority—depends on whether revenues are earmarked (special tax) or general and whether council/initiative.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;comparisons--context&quot;&gt;Comparisons &amp;amp; Context&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Peer counties: How Solano’s rate and program mix compare to Napa, Yolo, Contra Costa, Sonoma, Alameda.&lt;/li&gt;
  &lt;li&gt;Past performance: Delivery of prior Measure T commitments; notable overruns or under-budget deliverables.&lt;/li&gt;
  &lt;li&gt;Grant competitiveness: Whether a local match strengthens applications (ATP, SB1 Solutions for Congested Corridors, FTA/FTA CIG).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;story-angles-you-can-localize&quot;&gt;Story Angles You Can Localize&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Safety first: Map deadly and severe-injury crash corridors; match to proposed safety investments.&lt;/li&gt;
  &lt;li&gt;Commute reality: Transit frequency gaps and travel-time reliability fixes for top commute flows.&lt;/li&gt;
  &lt;li&gt;Equity lens: Which neighborhoods see capital and maintenance dollars—pair with CalEnviroScreen/low-income tracts.&lt;/li&gt;
  &lt;li&gt;Main Street maintenance: Pavement and ADA upgrades in city centers; before/after PCI targets.&lt;/li&gt;
  &lt;li&gt;Schools: Safe Routes to School projects near campuses; student arrival/dismissal safety.&lt;/li&gt;
  &lt;li&gt;Procurement &amp;amp; jobs: Local hire, small business participation, DBE goals, apprenticeship pathways.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sourcing-checklist-drop-these-links-into-your-piece&quot;&gt;Sourcing Checklist (drop these links into your piece)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Ordinance + Expenditure Plan (renewal draft)&lt;/li&gt;
  &lt;li&gt;STA Board packets, staff reports, slide decks&lt;/li&gt;
  &lt;li&gt;Independent Oversight Committee bylaws, rosters, annual reports&lt;/li&gt;
  &lt;li&gt;Annual audited financial statements; single audit if applicable&lt;/li&gt;
  &lt;li&gt;Pavement Management Program/PCI reports (MTC StreetSaver)&lt;/li&gt;
  &lt;li&gt;Collision data: SWITRS summaries; county Vision Zero plans&lt;/li&gt;
  &lt;li&gt;Environmental/air: CAP, regional SCS, MTC Plan Bay Area docs&lt;/li&gt;
  &lt;li&gt;Election calendar: County Registrar of Voters deadlines&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;questions-to-put-to-officials&quot;&gt;Questions To Put To Officials&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;What percent of the program directly reduces severe injuries and fatalities within five years?&lt;/li&gt;
  &lt;li&gt;Which projects will start construction in the first 2–3 years versus later in the term?&lt;/li&gt;
  &lt;li&gt;How will the agency keep costs in check if bids come in high—scope cuts, phasing, or additional match?&lt;/li&gt;
  &lt;li&gt;What happens if revenues underperform—what’s the contingency policy?&lt;/li&gt;
  &lt;li&gt;How will progress be reported to the public—dashboard cadence, success metrics, and independent validation?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;data-box-fill-with-local-numbers-before-publishing&quot;&gt;Data Box (fill with local numbers before publishing)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Proposed rate: 0.25% (example)&lt;/li&gt;
  &lt;li&gt;Term: 30 years (2025–2054)&lt;/li&gt;
  &lt;li&gt;Annual revenue (year 1): $XX.XM (baseline)&lt;/li&gt;
  &lt;li&gt;Total program: $X.XXB (nominal)&lt;/li&gt;
  &lt;li&gt;Buckets (example): 35% Local Streets &amp;amp; Roads; 20% Safety; 20% Transit; 10% Active Transportation; 10% Congestion Relief; 5% Program/Admin&lt;/li&gt;
  &lt;li&gt;Oversight: Independent citizens’ committee; annual audit; public dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;visuals-you-can-reproduce&quot;&gt;Visuals You Can Reproduce&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Map: Top 10 high-injury corridors (last 5 years) with proposed countermeasures.&lt;/li&gt;
  &lt;li&gt;Bar chart: Annual allocations by city vs. pavement needs (PCI target line).&lt;/li&gt;
  &lt;li&gt;Timeline: Renewal milestones from board vote to first construction start.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;boilerplate-language-attributionfriendly&quot;&gt;Boilerplate Language (Attribution‑Friendly)&lt;/h2&gt;

&lt;p&gt;“Measure T is a local transactions and use tax that funds transportation improvements throughout Solano County, including safety, transit, street maintenance, and bicycle/pedestrian projects. The renewal would extend the program for an additional term to continue investments and leverage state and federal matching funds. Revenues are subject to independent oversight and annual audits.”&lt;/p&gt;

&lt;p&gt;—&lt;/p&gt;

&lt;p&gt;Have questions or need help with data for your story? Email ryan@civic.studio and we can share sources, numbers, and map layers to back up your reporting.&lt;/p&gt;

</description>
      
      <category>measure t</category>
      
      <category>sales tax</category>
      
      <category>transportation</category>
      
      <category>accountability</category>
      
      <category>solano county</category>
      
    </item>
    
    <item>
      <title>Building Digital Capacity in Solano County: Data Visualization for Civic Understanding</title>
      <link>https://opensolano.org/2024/09/05/building-digital-capacity-solano-county.html</link>
      <guid isPermaLink="true">https://opensolano.org/2024/09/05/building-digital-capacity-solano-county.html</guid>
      <pubDate>Thu, 05 Sep 2024 00:00:00 +0000</pubDate>
      
      <dc:creator>Maria Santos</dc:creator>
      
      <description>&lt;p&gt;Effective civic engagement requires accessible information. Too often, municipal budget data remains locked in dense PDFs or spreadsheet formats that create barriers for community members who want to understand how their tax dollars are collected and spent.&lt;/p&gt;

&lt;p&gt;Digital capacity building in Solano County means creating tools and visualizations that make complex civic information understandable to all residents, regardless of their technical background or familiarity with government finance.&lt;/p&gt;

&lt;h2 id=&quot;making-budget-data-accessible&quot;&gt;Making Budget Data Accessible&lt;/h2&gt;

&lt;p&gt;The path from tax collection to public services involves multiple steps that can be difficult to follow. Interactive data visualizations help bridge this gap by showing these relationships clearly.&lt;/p&gt;

&lt;h3 id=&quot;monthly-budget-tracking&quot;&gt;Monthly Budget Tracking&lt;/h3&gt;

&lt;p&gt;Understanding budget performance requires looking at trends over time. How does actual spending compare to budgeted amounts throughout the year?&lt;/p&gt;

&lt;div id=&quot;budget-bar-chart&quot; style=&quot;width: 100%; height: 400px;&quot;&gt;&lt;/div&gt;

&lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
// 12-Month Budget Bar Chart
(function() {
  // Sample data - replace with actual budget data
  const data = [
    { month: &apos;Jan&apos;, budget: 45000000, actual: 42000000 },
    { month: &apos;Feb&apos;, budget: 48000000, actual: 46000000 },
    { month: &apos;Mar&apos;, budget: 52000000, actual: 51000000 },
    { month: &apos;Apr&apos;, budget: 49000000, actual: 47000000 },
    { month: &apos;May&apos;, budget: 51000000, actual: 50000000 },
    { month: &apos;Jun&apos;, budget: 53000000, actual: 52500000 },
    { month: &apos;Jul&apos;, budget: 48000000, actual: 46500000 },
    { month: &apos;Aug&apos;, budget: 50000000, actual: 49000000 },
    { month: &apos;Sep&apos;, budget: 54000000, actual: 53000000 },
    { month: &apos;Oct&apos;, budget: 52000000, actual: 51500000 },
    { month: &apos;Nov&apos;, budget: 49000000, actual: 48000000 },
    { month: &apos;Dec&apos;, budget: 51000000, actual: 50500000 }
  ];

  const container = d3.select(&quot;#budget-bar-chart&quot;);
  const containerNode = container.node();
  const containerWidth = containerNode.getBoundingClientRect().width;
  
  const margin = { top: 20, right: 80, bottom: 40, left: 60 };
  const width = containerWidth - margin.left - margin.right;
  const height = 400 - margin.top - margin.bottom;

  // Clear any existing content
  container.selectAll(&quot;*&quot;).remove();

  const svg = container.append(&quot;svg&quot;)
    .attr(&quot;width&quot;, containerWidth)
    .attr(&quot;height&quot;, 400);

  const g = svg.append(&quot;g&quot;)
    .attr(&quot;transform&quot;, `translate(${margin.left},${margin.top})`);

  // Scales
  const x0 = d3.scaleBand()
    .domain(data.map(d =&gt; d.month))
    .range([0, width])
    .padding(0.1);

  const x1 = d3.scaleBand()
    .domain([&apos;budget&apos;, &apos;actual&apos;])
    .range([0, x0.bandwidth()])
    .padding(0.05);

  const y = d3.scaleLinear()
    .domain([0, d3.max(data, d =&gt; Math.max(d.budget, d.actual))])
    .nice()
    .range([height, 0]);

  const color = d3.scaleOrdinal()
    .domain([&apos;budget&apos;, &apos;actual&apos;])
    .range([&apos;#4f46e5&apos;, &apos;#10b981&apos;]);

  // X axis
  g.append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;x-axis&quot;)
    .attr(&quot;transform&quot;, `translate(0,${height})`)
    .call(d3.axisBottom(x0))
    .selectAll(&quot;text&quot;)
    .style(&quot;font-size&quot;, &quot;12px&quot;)
    .style(&quot;fill&quot;, &quot;#6b7280&quot;);

  // Y axis
  g.append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;y-axis&quot;)
    .call(d3.axisLeft(y)
      .tickFormat(d =&gt; `$${(d / 1000000).toFixed(0)}M`))
    .selectAll(&quot;text&quot;)
    .style(&quot;font-size&quot;, &quot;12px&quot;)
    .style(&quot;fill&quot;, &quot;#6b7280&quot;);

  // Y axis label
  g.append(&quot;text&quot;)
    .attr(&quot;transform&quot;, &quot;rotate(-90)&quot;)
    .attr(&quot;y&quot;, 0 - margin.left)
    .attr(&quot;x&quot;, 0 - (height / 2))
    .attr(&quot;dy&quot;, &quot;1em&quot;)
    .style(&quot;text-anchor&quot;, &quot;middle&quot;)
    .style(&quot;font-size&quot;, &quot;14px&quot;)
    .style(&quot;fill&quot;, &quot;#374151&quot;)
    .text(&quot;Amount (Millions USD)&quot;);

  // Bars
  const monthGroups = g.selectAll(&quot;.month-group&quot;)
    .data(data)
    .enter().append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;month-group&quot;)
    .attr(&quot;transform&quot;, d =&gt; `translate(${x0(d.month)},0)`);

  // Budget bars
  monthGroups.append(&quot;rect&quot;)
    .attr(&quot;class&quot;, &quot;budget-bar&quot;)
    .attr(&quot;x&quot;, x1(&apos;budget&apos;))
    .attr(&quot;y&quot;, d =&gt; y(d.budget))
    .attr(&quot;width&quot;, x1.bandwidth())
    .attr(&quot;height&quot;, d =&gt; height - y(d.budget))
    .attr(&quot;fill&quot;, color(&apos;budget&apos;))
    .on(&quot;mouseover&quot;, function(event, d) {
      const tooltip = d3.select(&quot;body&quot;).append(&quot;div&quot;)
        .attr(&quot;class&quot;, &quot;tooltip&quot;)
        .style(&quot;position&quot;, &quot;absolute&quot;)
        .style(&quot;background&quot;, &quot;rgba(0,0,0,0.8)&quot;)
        .style(&quot;color&quot;, &quot;white&quot;)
        .style(&quot;padding&quot;, &quot;8px&quot;)
        .style(&quot;border-radius&quot;, &quot;4px&quot;)
        .style(&quot;font-size&quot;, &quot;12px&quot;)
        .style(&quot;pointer-events&quot;, &quot;none&quot;)
        .text(`Budget ${d.month}: $${(d.budget / 1000000).toFixed(1)}M`);
      
      tooltip
        .style(&quot;left&quot;, (event.pageX + 10) + &quot;px&quot;)
        .style(&quot;top&quot;, (event.pageY - 10) + &quot;px&quot;);
    })
    .on(&quot;mouseout&quot;, function() {
      d3.selectAll(&quot;.tooltip&quot;).remove();
    });

  // Actual bars
  monthGroups.append(&quot;rect&quot;)
    .attr(&quot;class&quot;, &quot;actual-bar&quot;)
    .attr(&quot;x&quot;, x1(&apos;actual&apos;))
    .attr(&quot;y&quot;, d =&gt; y(d.actual))
    .attr(&quot;width&quot;, x1.bandwidth())
    .attr(&quot;height&quot;, d =&gt; height - y(d.actual))
    .attr(&quot;fill&quot;, color(&apos;actual&apos;))
    .on(&quot;mouseover&quot;, function(event, d) {
      const tooltip = d3.select(&quot;body&quot;).append(&quot;div&quot;)
        .attr(&quot;class&quot;, &quot;tooltip&quot;)
        .style(&quot;position&quot;, &quot;absolute&quot;)
        .style(&quot;background&quot;, &quot;rgba(0,0,0,0.8)&quot;)
        .style(&quot;color&quot;, &quot;white&quot;)
        .style(&quot;padding&quot;, &quot;8px&quot;)
        .style(&quot;border-radius&quot;, &quot;4px&quot;)
        .style(&quot;font-size&quot;, &quot;12px&quot;)
        .style(&quot;pointer-events&quot;, &quot;none&quot;)
        .text(`Actual ${d.month}: $${(d.actual / 1000000).toFixed(1)}M`);
      
      tooltip
        .style(&quot;left&quot;, (event.pageX + 10) + &quot;px&quot;)
        .style(&quot;top&quot;, (event.pageY - 10) + &quot;px&quot;);
    })
    .on(&quot;mouseout&quot;, function() {
      d3.selectAll(&quot;.tooltip&quot;).remove();
    });

  // Legend
  const legend = svg.append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;legend&quot;)
    .attr(&quot;transform&quot;, `translate(${width - 60}, 30)`);

  const legendItems = legend.selectAll(&quot;.legend-item&quot;)
    .data([&apos;budget&apos;, &apos;actual&apos;])
    .enter().append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;legend-item&quot;)
    .attr(&quot;transform&quot;, (d, i) =&gt; `translate(0, ${i * 20})`);

  legendItems.append(&quot;rect&quot;)
    .attr(&quot;width&quot;, 15)
    .attr(&quot;height&quot;, 15)
    .attr(&quot;fill&quot;, d =&gt; color(d));

  legendItems.append(&quot;text&quot;)
    .attr(&quot;x&quot;, 20)
    .attr(&quot;y&quot;, 12)
    .style(&quot;font-size&quot;, &quot;12px&quot;)
    .style(&quot;fill&quot;, &quot;#374151&quot;)
    .text(d =&gt; d.charAt(0).toUpperCase() + d.slice(1));

  // Title
  svg.append(&quot;text&quot;)
    .attr(&quot;x&quot;, containerWidth / 2)
    .attr(&quot;y&quot;, 20)
    .attr(&quot;text-anchor&quot;, &quot;middle&quot;)
    .style(&quot;font-size&quot;, &quot;16px&quot;)
    .style(&quot;font-weight&quot;, &quot;bold&quot;)
    .style(&quot;fill&quot;, &quot;#111827&quot;)
    .text(&quot;Monthly Budget vs Actual Spending&quot;);

})();
&lt;/script&gt;

&lt;p&gt;This monthly view reveals seasonal patterns in spending and helps identify when actual expenditures diverge from planned budgets. For community advocates, this information is crucial for understanding when to engage in budget discussions and where potential adjustments might be needed.&lt;/p&gt;

&lt;h3 id=&quot;budget-category-breakdown&quot;&gt;Budget Category Breakdown&lt;/h3&gt;

&lt;p&gt;Where does the money actually go? A clear breakdown of budget allocation by category helps residents understand spending priorities.&lt;/p&gt;

&lt;div id=&quot;budget-pie-chart&quot; style=&quot;width: 100%; height: 400px;&quot;&gt;&lt;/div&gt;

&lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
// Budget Allocation Pie Chart
(function() {
  // Sample data - replace with actual budget allocation data
  const data = [
    { category: &apos;Public Safety&apos;, amount: 180000000, color: &apos;#dc2626&apos; },
    { category: &apos;Education&apos;, amount: 220000000, color: &apos;#2563eb&apos; },
    { category: &apos;Infrastructure&apos;, amount: 95000000, color: &apos;#16a34a&apos; },
    { category: &apos;Health Services&apos;, amount: 85000000, color: &apos;#ca8a04&apos; },
    { category: &apos;Parks &amp; Recreation&apos;, amount: 45000000, color: &apos;#9333ea&apos; },
    { category: &apos;Administration&apos;, amount: 55000000, color: &apos;#dc2626&apos; },
    { category: &apos;Economic Development&apos;, amount: 35000000, color: &apos;#0891b2&apos; },
    { category: &apos;Other&apos;, amount: 25000000, color: &apos;#6b7280&apos; }
  ];

  const container = d3.select(&quot;#budget-pie-chart&quot;);
  const containerNode = container.node();
  const containerWidth = containerNode.getBoundingClientRect().width;
  
  const width = containerWidth;
  const height = 400;
  const radius = Math.min(width, height) / 2 - 40;

  // Clear any existing content
  container.selectAll(&quot;*&quot;).remove();

  const svg = container.append(&quot;svg&quot;)
    .attr(&quot;width&quot;, width)
    .attr(&quot;height&quot;, height);

  const g = svg.append(&quot;g&quot;)
    .attr(&quot;transform&quot;, `translate(${width/2}, ${height/2})`);

  // Calculate total for percentages
  const total = d3.sum(data, d =&gt; d.amount);

  // Color scale
  const color = d3.scaleOrdinal()
    .domain(data.map(d =&gt; d.category))
    .range(data.map(d =&gt; d.color));

  // Pie generator
  const pie = d3.pie()
    .value(d =&gt; d.amount)
    .sort(null);

  // Arc generator
  const arc = d3.arc()
    .innerRadius(0)
    .outerRadius(radius);

  // Arc generator for labels
  const labelArc = d3.arc()
    .innerRadius(radius + 10)
    .outerRadius(radius + 10);

  // Create arcs
  const arcs = g.selectAll(&quot;.arc&quot;)
    .data(pie(data))
    .enter().append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;arc&quot;);

  // Draw pie slices
  arcs.append(&quot;path&quot;)
    .attr(&quot;d&quot;, arc)
    .attr(&quot;fill&quot;, d =&gt; color(d.data.category))
    .attr(&quot;stroke&quot;, &quot;white&quot;)
    .attr(&quot;stroke-width&quot;, 2)
    .on(&quot;mouseover&quot;, function(event, d) {
      d3.select(this)
        .transition()
        .duration(200)
        .attr(&quot;transform&quot;, function() {
          const centroid = arc.centroid(d);
          return `translate(${centroid[0] * 0.1}, ${centroid[1] * 0.1})`;
        });

      const tooltip = d3.select(&quot;body&quot;).append(&quot;div&quot;)
        .attr(&quot;class&quot;, &quot;tooltip&quot;)
        .style(&quot;position&quot;, &quot;absolute&quot;)
        .style(&quot;background&quot;, &quot;rgba(0,0,0,0.8)&quot;)
        .style(&quot;color&quot;, &quot;white&quot;)
        .style(&quot;padding&quot;, &quot;12px&quot;)
        .style(&quot;border-radius&quot;, &quot;4px&quot;)
        .style(&quot;font-size&quot;, &quot;14px&quot;)
        .style(&quot;pointer-events&quot;, &quot;none&quot;)
        .html(`
          &lt;strong&gt;${d.data.category}&lt;/strong&gt;&lt;br/&gt;
          Amount: $${(d.data.amount / 1000000).toFixed(1)}M&lt;br/&gt;
          Percentage: ${((d.data.amount / total) * 100).toFixed(1)}%
        `);
      
      tooltip
        .style(&quot;left&quot;, (event.pageX + 10) + &quot;px&quot;)
        .style(&quot;top&quot;, (event.pageY - 10) + &quot;px&quot;);
    })
    .on(&quot;mouseout&quot;, function(event, d) {
      d3.select(this)
        .transition()
        .duration(200)
        .attr(&quot;transform&quot;, &quot;translate(0,0)&quot;);
      
      d3.selectAll(&quot;.tooltip&quot;).remove();
    });

  // Add labels for larger slices
  arcs.filter(d =&gt; (d.data.amount / total) &gt; 0.05)
    .append(&quot;text&quot;)
    .attr(&quot;transform&quot;, d =&gt; `translate(${labelArc.centroid(d)})`)
    .attr(&quot;dy&quot;, &quot;0.35em&quot;)
    .attr(&quot;text-anchor&quot;, &quot;middle&quot;)
    .style(&quot;font-size&quot;, &quot;12px&quot;)
    .style(&quot;font-weight&quot;, &quot;bold&quot;)
    .style(&quot;fill&quot;, &quot;#374151&quot;)
    .text(d =&gt; `${((d.data.amount / total) * 100).toFixed(0)}%`);

  // Legend
  const legend = svg.append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;legend&quot;)
    .attr(&quot;transform&quot;, `translate(20, 30)`);

  const legendItems = legend.selectAll(&quot;.legend-item&quot;)
    .data(data)
    .enter().append(&quot;g&quot;)
    .attr(&quot;class&quot;, &quot;legend-item&quot;)
    .attr(&quot;transform&quot;, (d, i) =&gt; `translate(0, ${i * 22})`);

  legendItems.append(&quot;rect&quot;)
    .attr(&quot;width&quot;, 15)
    .attr(&quot;height&quot;, 15)
    .attr(&quot;fill&quot;, d =&gt; color(d.category))
    .attr(&quot;rx&quot;, 2);

  legendItems.append(&quot;text&quot;)
    .attr(&quot;x&quot;, 22)
    .attr(&quot;y&quot;, 12)
    .style(&quot;font-size&quot;, &quot;12px&quot;)
    .style(&quot;fill&quot;, &quot;#374151&quot;)
    .text(d =&gt; d.category);

  legendItems.append(&quot;text&quot;)
    .attr(&quot;x&quot;, 22)
    .attr(&quot;y&quot;, 12)
    .attr(&quot;dx&quot;, &quot;120px&quot;)
    .style(&quot;font-size&quot;, &quot;11px&quot;)
    .style(&quot;fill&quot;, &quot;#6b7280&quot;)
    .text(d =&gt; `$${(d.amount / 1000000).toFixed(0)}M`);

  // Title
  svg.append(&quot;text&quot;)
    .attr(&quot;x&quot;, width / 2)
    .attr(&quot;y&quot;, 20)
    .attr(&quot;text-anchor&quot;, &quot;middle&quot;)
    .style(&quot;font-size&quot;, &quot;16px&quot;)
    .style(&quot;font-weight&quot;, &quot;bold&quot;)
    .style(&quot;fill&quot;, &quot;#111827&quot;)
    .text(&quot;Budget Allocation by Category&quot;);

  // Total amount
  g.append(&quot;text&quot;)
    .attr(&quot;text-anchor&quot;, &quot;middle&quot;)
    .attr(&quot;dy&quot;, &quot;-0.5em&quot;)
    .style(&quot;font-size&quot;, &quot;14px&quot;)
    .style(&quot;font-weight&quot;, &quot;bold&quot;)
    .style(&quot;fill&quot;, &quot;#374151&quot;)
    .text(&quot;Total Budget&quot;);

  g.append(&quot;text&quot;)
    .attr(&quot;text-anchor&quot;, &quot;middle&quot;)
    .attr(&quot;dy&quot;, &quot;1em&quot;)
    .style(&quot;font-size&quot;, &quot;18px&quot;)
    .style(&quot;font-weight&quot;, &quot;bold&quot;)
    .style(&quot;fill&quot;, &quot;#111827&quot;)
    .text(`$${(total / 1000000).toFixed(0)}M`);

})();
&lt;/script&gt;

&lt;p&gt;Public safety and education typically represent the largest budget categories in most jurisdictions. This visualization makes it easy to see the relative size of different spending areas and spark informed discussions about community priorities.&lt;/p&gt;

&lt;h3 id=&quot;following-the-money-flow&quot;&gt;Following the Money Flow&lt;/h3&gt;

&lt;p&gt;Perhaps most importantly, residents need to understand the complete flow from tax collection through budget categories to actual spending.&lt;/p&gt;

&lt;style&gt;
  .bfs-wrap {
    font-family: system-ui, -apple-system, &quot;Segoe UI&quot;, sans-serif;
    color: #0b0b0b;
  }
  .bfs-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.1rem;
    font-size: 0.82rem;
    color: #52514e;
    padding: 0 0.25rem 0.75rem;
  }
  .bfs-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
  }
  .bfs-swatch {
    width: 11px;
    height: 11px;
    border-radius: 3px;
    display: inline-block;
  }
  .bfs-scroll {
    overflow-x: auto;
  }
  .bfs-chart {
    position: relative;
    min-width: 960px;
  }
  .bfs-tooltip {
    position: absolute;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.12s;
    background: rgba(11, 11, 11, 0.92);
    color: #fff;
    padding: 0.55rem 0.7rem;
    border-radius: 8px;
    font-size: 0.8rem;
    line-height: 1.45;
    max-width: 240px;
    z-index: 10;
  }
  .bfs-tip-sub {
    color: #c3c2b7;
    font-size: 0.72rem;
  }
  .bfs-table-details {
    margin-top: 1rem;
    font-size: 0.85rem;
  }
  .bfs-table-details summary {
    cursor: pointer;
    color: #0f766e;
    font-weight: 600;
  }
  .bfs-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 0.75rem;
  }
  .bfs-table th,
  .bfs-table td {
    text-align: left;
    padding: 0.35rem 0.6rem;
    border-bottom: 1px solid #e1e0d9;
    vertical-align: top;
  }
  .bfs-table th {
    color: #898781;
    font-weight: 600;
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.05em;
  }
  .bfs-table .bfs-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
&lt;/style&gt;

&lt;div class=&quot;bfs-wrap&quot; id=&quot;bfs-wrap-vacaville&quot;&gt;
  &lt;div class=&quot;bfs-legend&quot; id=&quot;bfs-legend-vacaville&quot;&gt;
  &lt;/div&gt;
  &lt;div class=&quot;bfs-scroll&quot;&gt;
    &lt;div class=&quot;bfs-chart&quot; id=&quot;bfs-chart-vacaville&quot;&gt;
      &lt;div class=&quot;bfs-tooltip&quot; id=&quot;bfs-tooltip-vacaville&quot;&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;details class=&quot;bfs-table-details&quot;&gt;
    &lt;summary&gt;
      View every published line item as a table
    &lt;/summary&gt;
    &lt;table class=&quot;bfs-table&quot;&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Side&lt;/th&gt;
          &lt;th&gt;Group&lt;/th&gt;
          &lt;th&gt;Line item&lt;/th&gt;
          &lt;th class=&quot;bfs-num&quot;&gt;Amount&lt;/th&gt;
          &lt;th&gt;Note&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Sales tax (Bradley-Burns)&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;27506262&quot;&gt;$27506262&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Measure M sales tax&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;21348950&quot;&gt;$21348950&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Property tax&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;21100471&quot;&gt;$21100471&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Property tax in lieu of VLF&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;15057016&quot;&gt;$15057016&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Excise taxes (Measures I &amp;amp; G)&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;9409983&quot;&gt;$9409983&lt;/td&gt;
          &lt;td&gt;Measure I (1989/2012) utility-bill, hotel, and per-employee excise (~$3.0M) plus Measure G (2005) utility franchise/excise (~$6.4M).&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Paramedic tax&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;7312900&quot;&gt;$7312900&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;RDA pass-through / TI excess&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;6152400&quot;&gt;$6152400&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Franchise tax&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;5705593&quot;&gt;$5705593&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Transient lodging tax&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;2087102&quot;&gt;$2087102&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Public safety sales tax (Prop 172)&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;540000&quot;&gt;$540000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Real property transfer tax&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;527100&quot;&gt;$527100&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Taxes&lt;/td&gt;
          &lt;td&gt;Business license tax&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;435000&quot;&gt;$435000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Fees &amp;amp; charges&lt;/td&gt;
          &lt;td&gt;Emergency medical fees&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;6000000&quot;&gt;$6000000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Fees &amp;amp; charges&lt;/td&gt;
          &lt;td&gt;Recreation &amp;amp; facilities fees&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;4954456&quot;&gt;$4954456&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Fees &amp;amp; charges&lt;/td&gt;
          &lt;td&gt;Police &amp;amp; fire fees&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;1145635&quot;&gt;$1145635&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Fees &amp;amp; charges&lt;/td&gt;
          &lt;td&gt;Other departmental fees&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;457618&quot;&gt;$457618&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;GEMT program (intergovernmental)&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;1442000&quot;&gt;$1442000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;Partnership Health transport&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;1000000&quot;&gt;$1000000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;In-lieu development impact fees&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;509394&quot;&gt;$509394&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;Cell tower leases&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;486875&quot;&gt;$486875&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;Interest, penalties &amp;amp; rents&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;382000&quot;&gt;$382000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;Homeowners subvention&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;180000&quot;&gt;$180000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;State reimbursements&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;145000&quot;&gt;$145000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Other revenue&lt;/td&gt;
          &lt;td&gt;Miscellaneous&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;153000&quot;&gt;$153000&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Transfers &amp;amp; reserves&lt;/td&gt;
          &lt;td&gt;Transfers in (CFDs &amp;amp; traffic fines)&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;10925235&quot;&gt;$10925235&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Transfers &amp;amp; reserves&lt;/td&gt;
          &lt;td&gt;Overhead recovered from other funds&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;6574920&quot;&gt;$6574920&lt;/td&gt;
          &lt;td&gt;Internal cost allocation — General Fund overhead charged to utility and special revenue funds, shown in the budget as a negative expenditure (-$6,574,920); presented here as an inflow so the diagram balances gross.&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;revenue&lt;/td&gt;
          &lt;td&gt;Transfers &amp;amp; reserves&lt;/td&gt;
          &lt;td&gt;Drawn from reserves &amp;amp; one-time sources &lt;em&gt;(derived)&lt;/em&gt;&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;13428517&quot;&gt;$13428517&lt;/td&gt;
          &lt;td&gt;Balancing figure: gross uses ($164,967,427) minus budgeted revenues and other inflows ($151,538,910). The budget&apos;s own Sources and Uses schedule, which nets transfers differently, states a planned &quot;use of fund balance&quot; of $8,892,389 — either way, FY2025-26 spending exceeds revenue and the gap is covered from fund balance.&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Public safety&lt;/td&gt;
          &lt;td&gt;Police Department&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;58947980&quot;&gt;$58947980&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Public safety&lt;/td&gt;
          &lt;td&gt;Fire Department&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;45099727&quot;&gt;$45099727&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Public works&lt;/td&gt;
          &lt;td&gt;Public Works (general)&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;12267906&quot;&gt;$12267906&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Public works&lt;/td&gt;
          &lt;td&gt;Park maintenance&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;4125868&quot;&gt;$4125868&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Community services&lt;/td&gt;
          &lt;td&gt;Parks &amp;amp; Recreation&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;11330706&quot;&gt;$11330706&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Community services&lt;/td&gt;
          &lt;td&gt;Housing &amp;amp; Community Services&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;159661&quot;&gt;$159661&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;Finance&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;5817527&quot;&gt;$5817527&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;Non-departmental&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;4760870&quot;&gt;$4760870&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;Human Resources&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;3858986&quot;&gt;$3858986&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;Information Technology&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;3497528&quot;&gt;$3497528&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;City Manager&apos;s Office / Clerk&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;3358373&quot;&gt;$3358373&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;City Attorney&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;2793011&quot;&gt;$2793011&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;Economic Development&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;1078113&quot;&gt;$1078113&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Administration&lt;/td&gt;
          &lt;td&gt;City Council / Treasurer&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;128755&quot;&gt;$128755&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
        &lt;/tr&gt;
        
        
        &lt;tr&gt;
          &lt;td&gt;spending&lt;/td&gt;
          &lt;td&gt;Transfers out&lt;/td&gt;
          &lt;td&gt;Transfers out (capital, equipment, districts)&lt;/td&gt;
          &lt;td class=&quot;bfs-num&quot; data-amount=&quot;7742416&quot;&gt;$7742416&lt;/td&gt;
          &lt;td&gt;Support to community development, park maintenance districts, vehicle/equipment replacement, technology projects, and capital improvement projects.&lt;/td&gt;
        &lt;/tr&gt;
        
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/details&gt;
&lt;/div&gt;

&lt;script src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;

&lt;script src=&quot;https://unpkg.com/d3-sankey@0.12.3/dist/d3-sankey.min.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
(function () {
  var DATA = {&quot;slug&quot;:&quot;vacaville&quot;,&quot;name&quot;:&quot;City of Vacaville&quot;,&quot;fund&quot;:&quot;General Fund (including Measure M)&quot;,&quot;fiscal_year&quot;:&quot;FY2025-26&quot;,&quot;population&quot;:103590,&quot;hub_label&quot;:&quot;General Fund&quot;,&quot;total_official&quot;:158392508,&quot;source&quot;:{&quot;title&quot;:&quot;City of Vacaville FY2025-26 Final Budget Document&quot;,&quot;publisher&quot;:&quot;City of Vacaville Finance Department&quot;,&quot;url&quot;:&quot;https://www.ci.vacaville.ca.us/government/finance&quot;,&quot;pages&quot;:&quot;Schedule of General Fund Revenue (p. 9); Summary of Expenditures by Department (p. 11); Summary of Expenditures by Fund (p. 13); Sources and Uses — General Fund Operations (pp. 14-15)&quot;,&quot;basis&quot;:&quot;FY 2025/26 Proposed Budget column, Final (adopted) budget&quot;,&quot;retrieved&quot;:&quot;2026-07-22&quot;,&quot;notes&quot;:&quot;Revenue detail sums to the printed $134,038,755 subtotal exactly. General Fund department detail sums to the printed $157,225,012 subtotal (within $1 of printed rounding). Official total General Fund budget: $158,392,508 = departments $157,225,012 + transfers out $7,742,416 - internal cost allocation $6,574,920.&quot;},&quot;groups&quot;:[{&quot;key&quot;:&quot;taxes&quot;,&quot;label&quot;:&quot;Taxes&quot;,&quot;side&quot;:&quot;revenue&quot;},{&quot;key&quot;:&quot;fees&quot;,&quot;label&quot;:&quot;Fees &amp; charges&quot;,&quot;side&quot;:&quot;revenue&quot;},{&quot;key&quot;:&quot;other-revenue&quot;,&quot;label&quot;:&quot;Other revenue&quot;,&quot;side&quot;:&quot;revenue&quot;},{&quot;key&quot;:&quot;transfers-reserves&quot;,&quot;label&quot;:&quot;Transfers &amp; reserves&quot;,&quot;side&quot;:&quot;revenue&quot;},{&quot;key&quot;:&quot;public-safety&quot;,&quot;label&quot;:&quot;Public safety&quot;,&quot;side&quot;:&quot;spending&quot;},{&quot;key&quot;:&quot;public-works&quot;,&quot;label&quot;:&quot;Public works&quot;,&quot;side&quot;:&quot;spending&quot;},{&quot;key&quot;:&quot;community&quot;,&quot;label&quot;:&quot;Community services&quot;,&quot;side&quot;:&quot;spending&quot;},{&quot;key&quot;:&quot;administration&quot;,&quot;label&quot;:&quot;Administration&quot;,&quot;side&quot;:&quot;spending&quot;},{&quot;key&quot;:&quot;transfers-out&quot;,&quot;label&quot;:&quot;Transfers out&quot;,&quot;side&quot;:&quot;spending&quot;,&quot;neutral&quot;:true,&quot;direct&quot;:true}],&quot;flows&quot;:[{&quot;name&quot;:&quot;Sales tax (Bradley-Burns)&quot;,&quot;amount&quot;:27506262,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Measure M sales tax&quot;,&quot;amount&quot;:21348950,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Property tax&quot;,&quot;amount&quot;:21100471,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Property tax in lieu of VLF&quot;,&quot;amount&quot;:15057016,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Excise taxes (Measures I &amp; G)&quot;,&quot;amount&quot;:9409983,&quot;group&quot;:&quot;taxes&quot;,&quot;note&quot;:&quot;Measure I (1989/2012) utility-bill, hotel, and per-employee excise (~$3.0M) plus Measure G (2005) utility franchise/excise (~$6.4M).&quot;},{&quot;name&quot;:&quot;Paramedic tax&quot;,&quot;amount&quot;:7312900,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;RDA pass-through / TI excess&quot;,&quot;amount&quot;:6152400,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Franchise tax&quot;,&quot;amount&quot;:5705593,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Transient lodging tax&quot;,&quot;amount&quot;:2087102,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Public safety sales tax (Prop 172)&quot;,&quot;amount&quot;:540000,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Real property transfer tax&quot;,&quot;amount&quot;:527100,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Business license tax&quot;,&quot;amount&quot;:435000,&quot;group&quot;:&quot;taxes&quot;},{&quot;name&quot;:&quot;Emergency medical fees&quot;,&quot;amount&quot;:6000000,&quot;group&quot;:&quot;fees&quot;},{&quot;name&quot;:&quot;Recreation &amp; facilities fees&quot;,&quot;amount&quot;:4954456,&quot;group&quot;:&quot;fees&quot;},{&quot;name&quot;:&quot;Police &amp; fire fees&quot;,&quot;amount&quot;:1145635,&quot;group&quot;:&quot;fees&quot;},{&quot;name&quot;:&quot;Other departmental fees&quot;,&quot;amount&quot;:457618,&quot;group&quot;:&quot;fees&quot;},{&quot;name&quot;:&quot;GEMT program (intergovernmental)&quot;,&quot;amount&quot;:1442000,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;Partnership Health transport&quot;,&quot;amount&quot;:1000000,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;In-lieu development impact fees&quot;,&quot;amount&quot;:509394,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;Cell tower leases&quot;,&quot;amount&quot;:486875,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;Interest, penalties &amp; rents&quot;,&quot;amount&quot;:382000,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;Homeowners subvention&quot;,&quot;amount&quot;:180000,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;State reimbursements&quot;,&quot;amount&quot;:145000,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;Miscellaneous&quot;,&quot;amount&quot;:153000,&quot;group&quot;:&quot;other-revenue&quot;},{&quot;name&quot;:&quot;Transfers in (CFDs &amp; traffic fines)&quot;,&quot;amount&quot;:10925235,&quot;group&quot;:&quot;transfers-reserves&quot;},{&quot;name&quot;:&quot;Overhead recovered from other funds&quot;,&quot;amount&quot;:6574920,&quot;group&quot;:&quot;transfers-reserves&quot;,&quot;note&quot;:&quot;Internal cost allocation — General Fund overhead charged to utility and special revenue funds, shown in the budget as a negative expenditure (-$6,574,920); presented here as an inflow so the diagram balances gross.&quot;},{&quot;name&quot;:&quot;Drawn from reserves &amp; one-time sources&quot;,&quot;amount&quot;:13428517,&quot;group&quot;:&quot;transfers-reserves&quot;,&quot;derived&quot;:true,&quot;note&quot;:&quot;Balancing figure: gross uses ($164,967,427) minus budgeted revenues and other inflows ($151,538,910). The budget&apos;s own Sources and Uses schedule, which nets transfers differently, states a planned \&quot;use of fund balance\&quot; of $8,892,389 — either way, FY2025-26 spending exceeds revenue and the gap is covered from fund balance.&quot;},{&quot;name&quot;:&quot;Police Department&quot;,&quot;amount&quot;:58947980,&quot;group&quot;:&quot;public-safety&quot;},{&quot;name&quot;:&quot;Fire Department&quot;,&quot;amount&quot;:45099727,&quot;group&quot;:&quot;public-safety&quot;},{&quot;name&quot;:&quot;Public Works (general)&quot;,&quot;amount&quot;:12267906,&quot;group&quot;:&quot;public-works&quot;},{&quot;name&quot;:&quot;Park maintenance&quot;,&quot;amount&quot;:4125868,&quot;group&quot;:&quot;public-works&quot;},{&quot;name&quot;:&quot;Parks &amp; Recreation&quot;,&quot;amount&quot;:11330706,&quot;group&quot;:&quot;community&quot;},{&quot;name&quot;:&quot;Housing &amp; Community Services&quot;,&quot;amount&quot;:159661,&quot;group&quot;:&quot;community&quot;},{&quot;name&quot;:&quot;Finance&quot;,&quot;amount&quot;:5817527,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;Non-departmental&quot;,&quot;amount&quot;:4760870,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;Human Resources&quot;,&quot;amount&quot;:3858986,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;Information Technology&quot;,&quot;amount&quot;:3497528,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;City Manager&apos;s Office / Clerk&quot;,&quot;amount&quot;:3358373,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;City Attorney&quot;,&quot;amount&quot;:2793011,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;Economic Development&quot;,&quot;amount&quot;:1078113,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;City Council / Treasurer&quot;,&quot;amount&quot;:128755,&quot;group&quot;:&quot;administration&quot;},{&quot;name&quot;:&quot;Transfers out (capital, equipment, districts)&quot;,&quot;amount&quot;:7742416,&quot;group&quot;:&quot;transfers-out&quot;,&quot;note&quot;:&quot;Support to community development, park maintenance districts, vehicle/equipment replacement, technology projects, and capital improvement projects.&quot;}]};

  // Validated 8-slot categorical palette (dataviz reference palette, light
  // mode). Slots are assigned to colored groups in their listed order —
  // fixed assignment, never cycled. Neutral groups and the hub render gray.
  var SLOTS = [&apos;#2a78d6&apos;, &apos;#eb6834&apos;, &apos;#1baf7a&apos;, &apos;#eda100&apos;, &apos;#e87ba4&apos;, &apos;#008300&apos;, &apos;#4a3aa7&apos;, &apos;#e34948&apos;];
  var NEUTRAL = &apos;#898781&apos;;
  var INK = &apos;#0b0b0b&apos;;
  var INK_SECONDARY = &apos;#52514e&apos;;
  var SURFACE = &apos;#fcfcfb&apos;;
  var AGG_THRESHOLD = 2500000; // diagram-only aggregation; table shows all lines

  var groupColor = {};
  var slotIdx = 0;
  DATA.groups.forEach(function (g) {
    groupColor[g.key] = g.neutral ? NEUTRAL : SLOTS[slotIdx++ % SLOTS.length];
  });

  function fmt(n) {
    if (n &gt;= 1e6) return &apos;$&apos; + (n / 1e6).toFixed(1) + &apos;M&apos;;
    if (n &gt;= 1e3) return &apos;$&apos; + Math.round(n / 1e3) + &apos;K&apos;;
    return &apos;$&apos; + Math.round(n);
  }
  function fmtExact(n) {
    return &apos;$&apos; + Math.round(n).toLocaleString();
  }

  // ---- Build the five-layer graph: detail -&gt; group -&gt; hub -&gt; group -&gt; detail
  function buildGraph() {
    var nodes = [];
    var links = [];
    function addNode(n) {
      n.index = nodes.length;
      nodes.push(n);
      return n.index;
    }

    var gross = 0;
    DATA.groups.forEach(function (g) {
      if (g.side === &apos;revenue&apos;) {
        DATA.flows.forEach(function (f) {
          if (f.group === g.key) gross += f.amount;
        });
      }
    });

    var hub = addNode({ name: DATA.hub_label, kind: &apos;hub&apos;, color: NEUTRAL, exact: gross });

    DATA.groups.forEach(function (g) {
      var items = DATA.flows
        .filter(function (f) { return f.group === g.key; })
        .slice()
        .sort(function (a, b) { return b.amount - a.amount; });
      if (!items.length) return;

      var total = items.reduce(function (s, f) { return s + f.amount; }, 0);

      // direct groups: no intermediate group node — each line links straight
      // to the hub (used for fund nodes, balancing/surplus nodes, transfers).
      if (g.direct) {
        items.forEach(function (f) {
          var di = addNode({ name: f.name, kind: &apos;detail&apos;, side: g.side, color: groupColor[g.key], exact: f.amount, derived: f.derived, note: f.note });
          if (g.side === &apos;revenue&apos;) {
            links.push({ source: di, target: hub, value: f.amount, color: groupColor[g.key] });
          } else {
            links.push({ source: hub, target: di, value: f.amount, color: groupColor[g.key] });
          }
        });
        return;
      }

      var gi = addNode({ name: g.label, kind: &apos;group&apos;, side: g.side, color: groupColor[g.key], exact: total, pct: total / gross });

      // Aggregate small lines (only when 2+ fall under the threshold).
      var small = items.filter(function (f) { return f.amount &lt; AGG_THRESHOLD; });
      var shown = items.filter(function (f) { return f.amount &gt;= AGG_THRESHOLD; });
      if (small.length &gt;= 2) {
        shown.push({
          name: small.length + &apos; smaller lines&apos;,
          amount: small.reduce(function (s, f) { return s + f.amount; }, 0),
          agg: small.map(function (f) { return f.name + &apos; &apos; + fmt(f.amount); })
        });
      } else {
        shown = items;
      }

      shown.forEach(function (f) {
        var di = addNode({ name: f.name, kind: &apos;detail&apos;, side: g.side, color: groupColor[g.key], exact: f.amount, agg: f.agg, derived: f.derived, note: f.note });
        if (g.side === &apos;revenue&apos;) {
          links.push({ source: di, target: gi, value: f.amount, color: groupColor[g.key] });
        } else {
          links.push({ source: gi, target: di, value: f.amount, color: groupColor[g.key] });
        }
      });

      if (g.side === &apos;revenue&apos;) {
        links.push({ source: gi, target: hub, value: total, color: groupColor[g.key] });
      } else {
        links.push({ source: hub, target: gi, value: total, color: groupColor[g.key] });
      }
    });

    return { nodes: nodes, links: links, gross: gross };
  }

  // ---- Legend (identity is never color-alone: every node is direct-labeled;
  // ---- the legend restates the group -&gt; color mapping).
  function renderLegend() {
    var el = document.getElementById(&apos;bfs-legend-&apos; + DATA.slug);
    var html = &apos;&apos;;
    DATA.groups.forEach(function (g) {
      html += &apos;&lt;span class=&quot;bfs-legend-item&quot;&gt;&apos; +
        &apos;&lt;span class=&quot;bfs-swatch&quot; style=&quot;background:&apos; + groupColor[g.key] + &apos;&quot;&gt;&lt;/span&gt;&apos; +
        g.label + &apos;&lt;/span&gt;&apos;;
    });
    el.innerHTML = html;
  }

  function render() {
    var container = document.getElementById(&apos;bfs-chart-&apos; + DATA.slug);
    var tooltip = document.getElementById(&apos;bfs-tooltip-&apos; + DATA.slug);
    d3.select(container).select(&apos;svg&apos;).remove();

    var outer = container.parentNode.parentNode; // .bfs-wrap
    var width = Math.max(960, Math.min(outer.clientWidth, 1200));
    var height = 640;
    var margin = { top: 56, right: 16, bottom: 16, left: 16 };

    var svg = d3.select(container)
      .insert(&apos;svg&apos;, &apos;:first-child&apos;)
      .attr(&apos;width&apos;, width)
      .attr(&apos;height&apos;, height)
      .attr(&apos;role&apos;, &apos;img&apos;)
      .attr(&apos;aria-label&apos;, DATA.name + &apos; &apos; + DATA.fiscal_year + &apos; budget flow diagram&apos;);

    var graph = buildGraph();

    var sankey = d3.sankey()
      .nodeId(function (d) { return d.index; })
      .nodeWidth(14)
      .nodePadding(9)
      .nodeSort(null)
      .linkSort(null)
      .extent([[margin.left, margin.top], [width - margin.right, height - margin.bottom]]);

    var g = sankey({
      nodes: graph.nodes.map(function (d) { return Object.assign({}, d); }),
      links: graph.links.map(function (d) { return Object.assign({}, d); })
    });

    // Links
    svg.append(&apos;g&apos;)
      .selectAll(&apos;path&apos;)
      .data(g.links)
      .join(&apos;path&apos;)
      .attr(&apos;d&apos;, d3.sankeyLinkHorizontal())
      .attr(&apos;fill&apos;, &apos;none&apos;)
      .attr(&apos;stroke&apos;, function (d) { return d.color; })
      .attr(&apos;stroke-opacity&apos;, 0.32)
      .attr(&apos;stroke-width&apos;, function (d) { return Math.max(1, d.width); })
      .on(&apos;mousemove&apos;, function (event, d) {
        d3.select(this).attr(&apos;stroke-opacity&apos;, 0.6);
        showTip(event, &apos;&lt;strong&gt;&apos; + d.source.name + &apos; &amp;rarr; &apos; + d.target.name + &apos;&lt;/strong&gt;&lt;br&gt;&apos; +
          fmtExact(d.value) + &apos; &amp;middot; &apos; + (100 * d.value / graph.gross).toFixed(1) + &apos;% of flow&apos;);
      })
      .on(&apos;mouseleave&apos;, function () {
        d3.select(this).attr(&apos;stroke-opacity&apos;, 0.32);
        hideTip();
      });

    // Nodes
    svg.append(&apos;g&apos;)
      .selectAll(&apos;rect&apos;)
      .data(g.nodes)
      .join(&apos;rect&apos;)
      .attr(&apos;x&apos;, function (d) { return d.x0; })
      .attr(&apos;y&apos;, function (d) { return d.y0; })
      .attr(&apos;width&apos;, function (d) { return d.x1 - d.x0; })
      .attr(&apos;height&apos;, function (d) { return Math.max(1, d.y1 - d.y0); })
      .attr(&apos;fill&apos;, function (d) { return d.color; })
      .attr(&apos;rx&apos;, 2)
      .attr(&apos;stroke&apos;, SURFACE)
      .attr(&apos;stroke-width&apos;, 1)
      .on(&apos;mousemove&apos;, function (event, d) {
        var extra = &apos;&apos;;
        if (d.agg) extra = &apos;&lt;br&gt;&lt;span class=&quot;bfs-tip-sub&quot;&gt;&apos; + d.agg.join(&apos;&lt;br&gt;&apos;) + &apos;&lt;/span&gt;&apos;;
        if (d.note) extra += &apos;&lt;br&gt;&lt;span class=&quot;bfs-tip-sub&quot;&gt;&apos; + d.note + &apos;&lt;/span&gt;&apos;;
        if (d.derived) extra += &apos;&lt;br&gt;&lt;span class=&quot;bfs-tip-sub&quot;&gt;Derived balancing figure — see methodology&lt;/span&gt;&apos;;
        showTip(event, &apos;&lt;strong&gt;&apos; + d.name + &apos;&lt;/strong&gt;&lt;br&gt;&apos; +
          fmtExact(d.exact) + &apos; &amp;middot; &apos; + (100 * d.exact / graph.gross).toFixed(1) + &apos;% of flow&apos; + extra);
      })
      .on(&apos;mouseleave&apos;, hideTip);

    // Labels — text wears ink tokens with a surface halo, never the series color.
    var label = svg.append(&apos;g&apos;)
      .attr(&apos;font-family&apos;, &apos;system-ui, -apple-system, &quot;Segoe UI&quot;, sans-serif&apos;)
      .selectAll(&apos;text&apos;)
      .data(g.nodes)
      .join(&apos;text&apos;)
      .attr(&apos;paint-order&apos;, &apos;stroke&apos;)
      .attr(&apos;stroke&apos;, SURFACE)
      .attr(&apos;stroke-width&apos;, 3)
      .attr(&apos;fill&apos;, INK);

    label.filter(function (d) { return d.kind === &apos;hub&apos;; })
      .attr(&apos;x&apos;, function (d) { return (d.x0 + d.x1) / 2; })
      .attr(&apos;y&apos;, function (d) { return d.y0 - 26; })
      .attr(&apos;text-anchor&apos;, &apos;middle&apos;)
      .attr(&apos;font-size&apos;, 14)
      .attr(&apos;font-weight&apos;, 700)
      .text(function (d) { return d.name; })
      .append(&apos;tspan&apos;)
      .attr(&apos;x&apos;, function (d) { return (d.x0 + d.x1) / 2; })
      .attr(&apos;dy&apos;, 15)
      .attr(&apos;font-weight&apos;, 400)
      .attr(&apos;fill&apos;, INK_SECONDARY)
      .text(function (d) { return fmt(d.exact); });

    label.filter(function (d) { return d.kind === &apos;group&apos;; })
      .attr(&apos;x&apos;, function (d) { return d.side === &apos;revenue&apos; ? d.x1 + 6 : d.x0 - 6; })
      .attr(&apos;y&apos;, function (d) { return (d.y0 + d.y1) / 2 - 2; })
      .attr(&apos;text-anchor&apos;, function (d) { return d.side === &apos;revenue&apos; ? &apos;start&apos; : &apos;end&apos;; })
      .attr(&apos;font-size&apos;, 12.5)
      .attr(&apos;font-weight&apos;, 700)
      .text(function (d) { return d.name; })
      .append(&apos;tspan&apos;)
      .attr(&apos;x&apos;, function (d) { return d.side === &apos;revenue&apos; ? d.x1 + 6 : d.x0 - 6; })
      .attr(&apos;dy&apos;, 14)
      .attr(&apos;font-weight&apos;, 400)
      .attr(&apos;fill&apos;, INK_SECONDARY)
      .text(function (d) { return fmt(d.exact) + &apos; · &apos; + (100 * d.pct).toFixed(1) + &apos;%&apos;; });

    var detail = label.filter(function (d) { return d.kind === &apos;detail&apos;; })
      .attr(&apos;x&apos;, function (d) { return d.side === &apos;revenue&apos; ? d.x1 + 6 : d.x0 - 6; })
      .attr(&apos;y&apos;, function (d) { return (d.y0 + d.y1) / 2 + 4; })
      .attr(&apos;text-anchor&apos;, function (d) { return d.side === &apos;revenue&apos; ? &apos;start&apos; : &apos;end&apos;; })
      .attr(&apos;font-size&apos;, 11.5)
      .text(function (d) { return d.name + &apos;  &apos; + fmt(d.exact); });

    // Greedy de-overlap of detail labels within each column side.
    [&apos;revenue&apos;, &apos;spending&apos;].forEach(function (side) {
      var texts = detail.filter(function (d) { return d.side === side; }).nodes();
      texts.sort(function (a, b) { return +a.getAttribute(&apos;y&apos;) - +b.getAttribute(&apos;y&apos;); });
      var minGap = 13;
      for (var i = 1; i &lt; texts.length; i++) {
        var prev = +texts[i - 1].getAttribute(&apos;y&apos;);
        var cur = +texts[i].getAttribute(&apos;y&apos;);
        if (cur - prev &lt; minGap) texts[i].setAttribute(&apos;y&apos;, prev + minGap);
      }
    });

    function showTip(event, html) {
      var rect = container.getBoundingClientRect();
      tooltip.innerHTML = html;
      tooltip.style.opacity = 1;
      tooltip.style.left = Math.min(event.clientX - rect.left + 14, width - 240) + &apos;px&apos;;
      tooltip.style.top = (event.clientY - rect.top + 14) + &apos;px&apos;;
    }
    function hideTip() {
      tooltip.style.opacity = 0;
    }
  }

  // Add thousands separators to the table&apos;s exact amounts.
  document.querySelectorAll(&apos;#bfs-wrap-&apos; + DATA.slug + &apos; .bfs-num[data-amount]&apos;).forEach(function (td) {
    td.textContent = fmtExact(+td.getAttribute(&apos;data-amount&apos;));
  });

  renderLegend();
  render();
  var resizeTimer;
  window.addEventListener(&apos;resize&apos;, function () {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(render, 150);
  });
})();
&lt;/script&gt;

&lt;p&gt;This flow diagram shows how revenue sources feed the General Fund, which then funds specific departments — here using Vacaville’s actual FY2025-26 adopted budget. Understanding these connections helps community members see how changes in tax policy or revenue streams affect the services they care about. An expanded, annotated version lives in the &lt;a href=&quot;/experiments/budget-flow&quot;&gt;Budget Flow experiment&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;building-community-capacity&quot;&gt;Building Community Capacity&lt;/h2&gt;

&lt;p&gt;Digital tools are most effective when they support broader community engagement efforts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Budget workshops&lt;/strong&gt; can use these visualizations to help residents understand current spending patterns before discussing priorities for future budgets&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Community organizations&lt;/strong&gt; can reference specific data points when advocating for policy changes&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Local journalists&lt;/strong&gt; can use interactive charts to tell more compelling stories about municipal finance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-role-of-decentralized-identity&quot;&gt;The Role of Decentralized Identity&lt;/h2&gt;

&lt;p&gt;As civic engagement moves online, verifying the identity and credentials of contributors becomes increasingly important. Decentralized identity systems can help build trust in digital civic spaces while protecting privacy.&lt;/p&gt;

&lt;p&gt;For example, community budget advocates could use verifiable credentials to demonstrate their training in budget analysis without revealing personal information. Journalists could verify their professional status when reporting on municipal finance issues.&lt;/p&gt;

&lt;h2 id=&quot;next-steps-for-digital-capacity&quot;&gt;Next Steps for Digital Capacity&lt;/h2&gt;

&lt;p&gt;Building digital capacity requires ongoing collaboration between:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Technical contributors&lt;/strong&gt; who create visualization tools and maintain data systems&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Community organizers&lt;/strong&gt; who understand resident needs and barriers to engagement&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Municipal staff&lt;/strong&gt; who can provide accurate, timely data in accessible formats&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Residents&lt;/strong&gt; who participate in testing and feedback to ensure tools meet real needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal isn’t just prettier charts—it’s creating the foundation for more informed, inclusive civic participation across Solano County.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have questions about these visualizations or ideas for other civic data that should be more accessible? &lt;a href=&quot;mailto:ryan@civic.studio?subject=Digital Capacity - OpenSolano&quot;&gt;Request specific datasets or volunteer to help document public meetings&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
      
      <category>digital capacity</category>
      
      <category>data visualization</category>
      
      <category>civic engagement</category>
      
      <category>budget transparency</category>
      
    </item>
    
    <item>
      <title>Understanding Solano County&apos;s Housing Development Impact Fees</title>
      <link>https://opensolano.org/2024/08/15/solano-county-housing-development-impact-fees.html</link>
      <guid isPermaLink="true">https://opensolano.org/2024/08/15/solano-county-housing-development-impact-fees.html</guid>
      <pubDate>Thu, 15 Aug 2024 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;Housing development impact fees play a crucial role in funding public infrastructure needed to support new residential growth across Solano County’s cities and unincorporated areas.&lt;/p&gt;

&lt;h2 id=&quot;what-are-impact-fees&quot;&gt;What are Impact Fees?&lt;/h2&gt;

&lt;p&gt;Development impact fees are one-time charges levied on new development to help fund the additional public facilities and services that growth necessitates. These fees help ensure that new development pays its fair share of infrastructure costs rather than burdening existing residents.&lt;/p&gt;

&lt;h2 id=&quot;current-fee-structure-across-solano-county&quot;&gt;Current Fee Structure Across Solano County&lt;/h2&gt;

&lt;p&gt;Different jurisdictions within Solano County have varying impact fee structures:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Fairfield&lt;/strong&gt;: Charges fees for transportation, parks, public facilities, and public safety&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vallejo&lt;/strong&gt;: Recently updated their fee schedule to address infrastructure backlogs&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vacaville&lt;/strong&gt;: Maintains separate fees for different development types and locations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-data-challenge&quot;&gt;The Data Challenge&lt;/h2&gt;

&lt;p&gt;One challenge facing both developers and community advocates is the lack of centralized, easily accessible data on impact fees across all jurisdictions. This makes it difficult to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compare costs across different cities&lt;/li&gt;
  &lt;li&gt;Track how fees change over time&lt;/li&gt;
  &lt;li&gt;Understand the relationship between fees and actual infrastructure investment&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;moving-forward&quot;&gt;Moving Forward&lt;/h2&gt;

&lt;p&gt;Greater transparency in impact fee data could help foster more informed public discourse about balancing development costs with infrastructure needs. Regular reporting on fee collections and infrastructure spending would benefit both developers and residents in understanding how these funds support community growth.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This analysis is based on publicly available data from various Solano County jurisdictions. For specific development projects, consult directly with the relevant planning department.&lt;/em&gt;&lt;/p&gt;
</description>
      
      <category>housing</category>
      
      <category>impact fees</category>
      
      <category>development</category>
      
      <category>finance</category>
      
    </item>
    
    <item>
      <title>Municipal Budget Transparency Across Solano County Cities</title>
      <link>https://opensolano.org/2024/06/22/municipal-budget-transparency-solano-cities.html</link>
      <guid isPermaLink="true">https://opensolano.org/2024/06/22/municipal-budget-transparency-solano-cities.html</guid>
      <pubDate>Sat, 22 Jun 2024 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;How accessible are municipal budgets across Solano County’s seven cities? A recent review reveals significant variation in how local governments present their financial information to the public.&lt;/p&gt;

&lt;h2 id=&quot;the-transparency-spectrum&quot;&gt;The Transparency Spectrum&lt;/h2&gt;

&lt;p&gt;Solano County cities fall along a spectrum of budget transparency:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most Accessible&lt;/strong&gt;: Cities that provide searchable, downloadable budget data with clear explanations of major expenditure categories and revenue sources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Moderately Accessible&lt;/strong&gt;: Cities that publish PDF budget documents with some supplementary materials but limited interactive features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Least Accessible&lt;/strong&gt;: Cities where budget information requires multiple clicks through various pages or lacks current-year details.&lt;/p&gt;

&lt;h2 id=&quot;key-findings&quot;&gt;Key Findings&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Only 3 out of 7 cities provide budget data in machine-readable formats&lt;/li&gt;
  &lt;li&gt;Public engagement opportunities vary widely during budget adoption processes&lt;/li&gt;
  &lt;li&gt;Capital improvement project tracking differs significantly between jurisdictions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-civic-impact&quot;&gt;The Civic Impact&lt;/h2&gt;

&lt;p&gt;Better budget transparency enables:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;More informed public participation in budget hearings&lt;/li&gt;
  &lt;li&gt;Easier comparison of spending priorities across cities&lt;/li&gt;
  &lt;li&gt;Enhanced accountability for financial stewardship&lt;/li&gt;
  &lt;li&gt;Improved data-driven advocacy by community groups&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;recommendations&quot;&gt;Recommendations&lt;/h2&gt;

&lt;p&gt;Cities could enhance budget transparency by:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Publishing budget data in standardized, downloadable formats&lt;/li&gt;
  &lt;li&gt;Creating budget summaries written for general audiences&lt;/li&gt;
  &lt;li&gt;Providing multi-year trend analysis&lt;/li&gt;
  &lt;li&gt;Implementing public feedback systems for budget priorities&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Analysis based on public budget documents available as of June 2024. Individual cities may have made improvements since this review.&lt;/em&gt;&lt;/p&gt;
</description>
      
      <category>budgets</category>
      
      <category>transparency</category>
      
      <category>municipal finance</category>
      
      <category>open data</category>
      
    </item>
    
    <item>
      <title>Analyzing Land Use Patterns in Solano County: What the Data Shows</title>
      <link>https://opensolano.org/2024/04/10/solano-county-land-use-patterns-data-analysis.html</link>
      <guid isPermaLink="true">https://opensolano.org/2024/04/10/solano-county-land-use-patterns-data-analysis.html</guid>
      <pubDate>Wed, 10 Apr 2024 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;Solano County’s diverse landscape encompasses urban centers, agricultural land, and protected open spaces. Understanding current land use patterns through data analysis reveals important trends for future planning decisions.&lt;/p&gt;

&lt;h2 id=&quot;current-land-use-distribution&quot;&gt;Current Land Use Distribution&lt;/h2&gt;

&lt;p&gt;Based on county assessor data and general plan designations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Agricultural&lt;/strong&gt;: ~65% of total county land area&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Residential&lt;/strong&gt;: ~15% (varying density from rural to urban)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Commercial/Industrial&lt;/strong&gt;: ~8%&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Open Space/Recreation&lt;/strong&gt;: ~7%&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Public/Institutional&lt;/strong&gt;: ~5%&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;urban-growth-patterns&quot;&gt;Urban Growth Patterns&lt;/h2&gt;

&lt;p&gt;Data from the past decade shows:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Most new residential development concentrated in existing urban areas&lt;/li&gt;
  &lt;li&gt;Limited conversion of agricultural land to urban uses&lt;/li&gt;
  &lt;li&gt;Increasing density in transit-accessible locations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-housing-jobs-balance&quot;&gt;The Housing-Jobs Balance&lt;/h2&gt;

&lt;p&gt;Analysis reveals spatial mismatches between where people live and work:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Many residents commute outside the county for employment&lt;/li&gt;
  &lt;li&gt;Job centers don’t always align with affordable housing locations&lt;/li&gt;
  &lt;li&gt;Transportation infrastructure impacts both housing and employment choices&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;agricultural-land-preservation&quot;&gt;Agricultural Land Preservation&lt;/h2&gt;

&lt;p&gt;Solano County’s agricultural economy depends on maintaining productive farmland:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Williamson Act contracts protect significant acreage&lt;/li&gt;
  &lt;li&gt;Development pressure varies by location and market conditions&lt;/li&gt;
  &lt;li&gt;Climate change impacts add complexity to land use planning&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;data-gaps-and-opportunities&quot;&gt;Data Gaps and Opportunities&lt;/h2&gt;

&lt;p&gt;Current land use analysis would benefit from:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;More frequent updates to land use classification data&lt;/li&gt;
  &lt;li&gt;Better integration of environmental and economic factors&lt;/li&gt;
  &lt;li&gt;Enhanced public access to planning and zoning information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Understanding these patterns helps inform discussions about growth management, housing policy, and agricultural preservation as the county plans for future development.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Analysis based on Solano County assessor data, general plan documents, and state land use surveys.&lt;/em&gt;&lt;/p&gt;
</description>
      
      <category>land use</category>
      
      <category>zoning</category>
      
      <category>urban planning</category>
      
      <category>data analysis</category>
      
    </item>
    
    <item>
      <title>Public Infrastructure Financing in Solano County: Bonds, Taxes, and User Fees</title>
      <link>https://opensolano.org/2024/02/28/public-infrastructure-financing-solano-county.html</link>
      <guid isPermaLink="true">https://opensolano.org/2024/02/28/public-infrastructure-financing-solano-county.html</guid>
      <pubDate>Wed, 28 Feb 2024 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;How does Solano County fund critical infrastructure like roads, water systems, and public buildings? The answer involves a complex mix of financing tools, each with different implications for taxpayers and service delivery.&lt;/p&gt;

&lt;h2 id=&quot;primary-funding-sources&quot;&gt;Primary Funding Sources&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;General Obligation Bonds&lt;/strong&gt;: Secured by property tax revenue, requiring voter approval for issuance. Recent examples include school construction bonds and transportation improvements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revenue Bonds&lt;/strong&gt;: Repaid through specific revenue streams like water rates or sewer fees, often not requiring voter approval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Special Assessments&lt;/strong&gt;: Property-based charges for localized improvements like streetlights, sidewalks, or landscaping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User Fees&lt;/strong&gt;: Direct charges for services like water, sewer, and solid waste collection.&lt;/p&gt;

&lt;h2 id=&quot;recent-financing-trends&quot;&gt;Recent Financing Trends&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Increased reliance on revenue bonds for utility infrastructure&lt;/li&gt;
  &lt;li&gt;Growing use of special assessment districts for maintenance&lt;/li&gt;
  &lt;li&gt;Federal and state grants becoming more competitive&lt;/li&gt;
  &lt;li&gt;Public-private partnerships emerging for major projects&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-challenge-of-deferred-maintenance&quot;&gt;The Challenge of Deferred Maintenance&lt;/h2&gt;

&lt;p&gt;Across Solano County jurisdictions, aging infrastructure creates ongoing financial pressure:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Many water and sewer systems need major upgrades&lt;/li&gt;
  &lt;li&gt;Road maintenance backlogs continue to grow&lt;/li&gt;
  &lt;li&gt;Public buildings require seismic and efficiency improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;financing-equity-considerations&quot;&gt;Financing Equity Considerations&lt;/h2&gt;

&lt;p&gt;Different financing mechanisms have varying impacts on different community segments:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Property-based assessments can disproportionately affect lower-income homeowners&lt;/li&gt;
  &lt;li&gt;User fees provide more direct connection between usage and cost&lt;/li&gt;
  &lt;li&gt;Bond financing spreads costs over time but includes interest expenses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;looking-forward&quot;&gt;Looking Forward&lt;/h2&gt;

&lt;p&gt;Sustainable infrastructure financing requires:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Long-term capital planning across all jurisdictions&lt;/li&gt;
  &lt;li&gt;Regional coordination for shared infrastructure needs&lt;/li&gt;
  &lt;li&gt;Public education about the true costs of infrastructure&lt;/li&gt;
  &lt;li&gt;Innovative financing approaches for climate resilience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This analysis draws from municipal financial reports, bond documents, and budget presentations across Solano County jurisdictions.&lt;/em&gt;&lt;/p&gt;
</description>
      
      <category>infrastructure</category>
      
      <category>bonds</category>
      
      <category>financing</category>
      
      <category>public works</category>
      
    </item>
    
    <item>
      <title>Better public meetings</title>
      <link>https://opensolano.org/2023/11/02/better-public-meetings.html</link>
      <guid isPermaLink="true">https://opensolano.org/2023/11/02/better-public-meetings.html</guid>
      <pubDate>Thu, 02 Nov 2023 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;What can we do to improve public meetings?&lt;/p&gt;

&lt;p&gt;The decorum and formalized process in a council chambers can
be understood and worked with and within, productively.&lt;/p&gt;

&lt;p&gt;One must understand, on some level, the etiquitte of public comment.
Being familiar with the agenda and the items on it, is a plus.&lt;/p&gt;

&lt;p&gt;Very little actually happens at a meeting.
Lots of words are spoken by board members, public staff, and citizens, during public comment.
Ultimately, a few motions are passed, constituting the action that does occur.&lt;/p&gt;

&lt;p&gt;Yet, there is opportunity for more productive interactions at a public a Board Meeting.&lt;/p&gt;

&lt;p&gt;Understand what is being voted on, by whom, and to the extent possible, what are the implications of a supporting or dissenting vote by an individual, and the board. For example, consider addressing your feedback to your appropriate representative, based on where you live.  Sharing good feedback to a neighboring jurisdiction may be well-intentioned, but is ultimately ineffective. Representatives value feedback from &lt;em&gt;their&lt;/em&gt; constituents relatively more, by definition.&lt;/p&gt;

&lt;p&gt;So, understanding how to participate begins with understanding a bit of what is and has been going on.
Attending a few meetings, or watching them online is a good place to start.&lt;/p&gt;

&lt;p&gt;The Solano County Board of Supervisors records their videos
and makes them available.&lt;/p&gt;

&lt;p&gt;Fortunately, the City of Vacaville’s City Council also records their videos and makes them available.&lt;/p&gt;

&lt;p&gt;Online public meeting videos are a great asset and an important artifact of municipal operations.&lt;/p&gt;

&lt;h2 id=&quot;what-if-we&quot;&gt;What if we:&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;made the transcripts searchable&lt;/li&gt;
  &lt;li&gt;identified people in the video, talking&lt;/li&gt;
  &lt;li&gt;annotated public meeting videos with captions, statistics, and commentary&lt;/li&gt;
  &lt;li&gt;linked additional context based on past meetings and other public documents (example: link budget documents or project plans across different points on a timeline)&lt;/li&gt;
&lt;/ul&gt;
</description>
      
      <category>public meetings</category>
      
      <category>automation</category>
      
      <category>media</category>
      
    </item>
    
    <item>
      <title>About Open Solano</title>
      <link>https://opensolano.org/2023/11/01/about-open-solano.html</link>
      <guid isPermaLink="true">https://opensolano.org/2023/11/01/about-open-solano.html</guid>
      <pubDate>Wed, 01 Nov 2023 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;OpenSolano is a way to bring people together to work on
shared issues that matter to them.
In many cases, the issues are civic in nature;
parks, education, public safety, public services, public accountability.&lt;/p&gt;

&lt;p&gt;OpenSolano runs this website and holds meetups to get people together to
discuss local civics and play with technology to shed some light on some of the issues.&lt;/p&gt;

&lt;p&gt;Goals for the group include sharing ideas and learning, and building things together.
I’d like to see many, if not all, aspects of a city’s ontology mapped and modeled.&lt;/p&gt;

&lt;p&gt;Ultimately, people will come with their own interests, skills, and desires, so we’ll see what makes sense, over time.&lt;/p&gt;
</description>
      
      <category>local</category>
      
      <category>opendata</category>
      
      <category>performance</category>
      
      <category>public sector</category>
      
    </item>
    
    <item>
      <title>City of Vacaville - State of the City 2023 - Video</title>
      <link>https://opensolano.org/2023/03/13/city-of-vacaville-state-of-the-city.html</link>
      <guid isPermaLink="true">https://opensolano.org/2023/03/13/city-of-vacaville-state-of-the-city.html</guid>
      <pubDate>Mon, 13 Mar 2023 00:00:00 +0000</pubDate>
      
      <dc:creator>Ryan Wold</dc:creator>
      
      <description>&lt;p&gt;Each year, the City of Vacaville Executive Staff present on the State of the City.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=3sbLPaUG2Rw&quot;&gt;Watch the 1hr 5min video&lt;/a&gt;&lt;/p&gt;
</description>
      
      <category>vacaville</category>
      
      <category>2023</category>
      
      <category>public meetings</category>
      
      <category>annual</category>
      
      <category>state-of-the-city</category>
      
    </item>
    
  </channel>
</rss>
