I built the FY2025 revenue bridge, and it reconciles to the dollar at the total level and for each segment.

| Item | Amount ($) |
|---|---|
| **FY2024 revenue** | **11,243,300** |
| New customers (6) | +462,893 |
| Churned customers (4) | −1,288,224 |
| Expansion | +1,210,651 |
| Contraction | −443,322 |
| Timing | +53,080 |
| **FY2025 revenue** | **11,238,378** |

- **Net change:** revenue is down about $5K (−0.04%). Churn of $1.29M, mostly from two Enterprise losses, was almost fully offset by expansion and new logos.
- **Enterprise churn:** Birchway Foods and Fenwick Legal account for $1.19M of the churn.
- **New customers:** all six are SMB.

I had to assume how to treat `timing_amount`, since the file doesn't define it. I read it as the part of a customer's year-over-year change that comes from timing rather than underlying growth. I took it out of that customer's expansion or contraction and showed it as its own bar. Only three customers have a timing amount: Cobalt Dental, Lumen Retail and Saltmarsh Energy. If it means something else, such as a one-time item that should sit inside expansion, the bridge needs to be re-cut.

I classified a customer as new if FY2024 revenue is 0, and as churned if FY2025 revenue is 0.

Files are in `output/`:
- `revenue_bridge_fy25.csv`
- `revenue_bridge_fy25_by_segment.csv`
- `bridge.py`, which regenerates both CSVs

I didn't make a waterfall chart. I can add one if you want it.