The FY2025 revenue bridge is built, and it reconciles to the dollar. Revenue is essentially flat: $11,243,300 in FY2024 and $11,238,378 in FY2025, a change of –$4,922.

| Step | Amount |
|---|---:|
| **FY2024 revenue** | **11,243,300** |
| New customers (6) | +462,893 |
| Churned customers (5) | –1,288,224 |
| Expansion, excluding timing | +1,210,651 |
| Contraction, excluding timing | –443,322 |
| Timing | +53,080 |
| **FY2025 revenue** | **11,238,378** |

- **Churn offsets growth:** The five churned customers took out $1.29M. That includes two large Enterprise accounts, Birchway Foods ($503K) and Fenwick Legal ($686K). Expansion and new logos added $1.67M, which nearly cancels it.
- **Segments:**
  - Enterprise fell from $6.26M to $5.51M.
  - Mid-Market rose from $4.04M to $4.37M.
  - SMB rose from $0.95M to $1.36M.
- **Timing assumption:** I read `timing_amount` as the part of a customer's year-over-year change that comes from timing, not from underlying growth or decline. I pulled it out as its own bar and removed it from expansion and contraction. The file doesn't define the column, so please confirm that reading. If timing should stay inside expansion and contraction, those two lines change by the timing amounts. Only three customers carry timing:
  - Cobalt Dental: +$53,231
  - Lumen Retail: –$13,813
  - Saltmarsh Energy: +$13,662
- **Classification:** A customer with zero FY2024 revenue counts as new. A customer with zero FY2025 revenue counts as churned. Everyone else counts as expansion or contraction, based on the change after removing timing.

I saved the script as `bridge.py` and the table as `revenue_bridge_fy2025.csv`, both in the working directory. I haven't made a waterfall chart. I can add one if you want it.