diff --git a/lib/slideshows.ts b/lib/slideshows.ts index 9aa3968..dd175f8 100644 --- a/lib/slideshows.ts +++ b/lib/slideshows.ts @@ -29,8 +29,10 @@ import { overhang2026LightningConfig } from "@/slideshows/overhang-2026-lightnin import { blsTaxsim2026Config } from "@/slideshows/bls-taxsim-2026/config"; import { scottishGovernment2026Config } from "@/slideshows/scottish-government-2026/config"; import { goodGrowthFoundation2026Config } from "@/slideshows/good-growth-foundation-2026/config"; +import { introduction2026Config } from "@/slideshows/introduction-2026/config"; export const slideshows: SlideshowConfig[] = [ + introduction2026Config, goodGrowthFoundation2026Config, scottishGovernment2026Config, blsTaxsim2026Config, diff --git a/public/images/introduction-2026/dashboard-qr.svg b/public/images/introduction-2026/dashboard-qr.svg new file mode 100644 index 0000000..d1c9a92 --- /dev/null +++ b/public/images/introduction-2026/dashboard-qr.svg @@ -0,0 +1 @@ + diff --git a/public/logos/orgs/good-growth-foundation.png b/public/logos/orgs/good-growth-foundation.png new file mode 100644 index 0000000..fdfec09 Binary files /dev/null and b/public/logos/orgs/good-growth-foundation.png differ diff --git a/public/screenshots/introduction-2026/autumn-budget-2025-in-review.png b/public/screenshots/introduction-2026/autumn-budget-2025-in-review.png new file mode 100644 index 0000000..2a43199 Binary files /dev/null and b/public/screenshots/introduction-2026/autumn-budget-2025-in-review.png differ diff --git a/slideshows/introduction-2026/README.md b/slideshows/introduction-2026/README.md new file mode 100644 index 0000000..f5142d0 --- /dev/null +++ b/slideshows/introduction-2026/README.md @@ -0,0 +1,21 @@ +# Analysing the UK Autumn Budget 2026 with PolicyEngine + +6 slides at `/slides/introduction-2026`, for the 28 October 2026 webinar: +what PolicyEngine is, how we prepared for Budget day, past Budgets on today's +model, and a slide that opens the live +[Autumn Budget 2026 dashboard](https://uk-autumn-budget-2026.vercel.app/uk/autumn-budget-2026), +where the analysis is presented. + +- `config.ts` controls the slide order and metadata. +- `content.ts` holds the sources, preparation cards and past events. +- `slides/index.tsx` contains the slides. The analysis slide is one card that + opens the dashboard in a new tab (click it, or focus it and press Enter), + with buttons for its Population impact, Household impact and Living + standards tabs. The deck draws no charts of its own, so nothing here goes + stale when the dashboard's data change. +- `SPEAKER-NOTES.md` gives the presenter track. + +`public/screenshots/introduction-2026/autumn-budget-2025-in-review.png` was +captured from https://autumn-budget-2025-in-review.vercel.app/uk/autumn-budget-2025-in-review +on 25 October 2026. `public/images/introduction-2026/dashboard-qr.svg` encodes +the dashboard's address. diff --git a/slideshows/introduction-2026/SPEAKER-NOTES.md b/slideshows/introduction-2026/SPEAKER-NOTES.md new file mode 100644 index 0000000..f9a949e --- /dev/null +++ b/slideshows/introduction-2026/SPEAKER-NOTES.md @@ -0,0 +1,43 @@ +# Speaker notes: Analysing the UK Autumn Budget 2026 with PolicyEngine + +## 1. Title + +Webinar, Wednesday 28 October 2026, 4:30pm UK time. Presenters: Vahid +Ahmadi, Max Ghenis, María Juaristi. + +## 2. What PolicyEngine is + +A brief view: the rules, the households and the results, and that all the +code is public. + +## 3. How we prepared + +- Four mock Budgets (28 September; 5, 12 and 19 October): drill issues #6 + (with the drill 1 retrospective), #8, #10 and #53 in the dashboard repo. +- The runbook is `docs/budget-day-runbook.md` (G0 to G5 checkpoints). +- Mark anything still in review as such on the slide before presenting. + +## 4. Past Budgets + +- Six events from Spring Budget 2023 to Autumn Budget 2025, rerun on + policyengine 6.10.2 and Microcosm UK 2024-25 (dashboard PR #107). These + are today's model and data, not what was known at the time. +- Autumn Budget 2025 in review is a separate dashboard (live). + +## 5. The analysis: live dashboard + +Click the card (or focus it and press Enter) to open the dashboard in a new +tab, then present from there. The three buttons open its tabs directly: + +- **Population impact**: revenue by year, households by income decile, the + map, and young people. +- **Household impact**: run one household live with Calculate; the result + takes about a minute, so start it before talking it through. +- **Living standards**: the current-law baseline (OBR forecast named on the + tab) for incomes and poverty. + +Come back to the deck with the browser tab for the close. + +## 6. Close + +The dashboard link, with a QR code for phones, and how to reach us. diff --git a/slideshows/introduction-2026/config.ts b/slideshows/introduction-2026/config.ts new file mode 100644 index 0000000..36dc3fb --- /dev/null +++ b/slideshows/introduction-2026/config.ts @@ -0,0 +1,28 @@ +import type { SlideshowConfig } from "@/lib/types"; +import { + ClosingSlide, + DashboardSlide, + PastBudgetsSlide, + PreparationSlide, + TitleSlide, + WhatSlide, +} from "./slides"; + +export const introduction2026Config: SlideshowConfig = { + id: "introduction-2026", + title: "Analysing the UK Autumn Budget 2026 with PolicyEngine", + description: + "What PolicyEngine is, how we prepared for Budget day, past Budgets on today's model, and the analysis, presented live on the dashboard.", + date: "2026-10-28", + location: "PolicyEngine", + // No footer text: the shared viewer's slide counter sits where it would go. + footerText: "", + slides: [ + TitleSlide, + WhatSlide, + PreparationSlide, + PastBudgetsSlide, + DashboardSlide, + ClosingSlide, + ], +}; diff --git a/slideshows/introduction-2026/content.ts b/slideshows/introduction-2026/content.ts new file mode 100644 index 0000000..3aa5c45 --- /dev/null +++ b/slideshows/introduction-2026/content.ts @@ -0,0 +1,118 @@ +// Content for the PolicyEngine and Autumn Budget 2026 deck. + +export type Source = { label: string; href: string }; + +export const sources = { + home: { label: "policyengine.org", href: "https://www.policyengine.org/uk" }, + model: { + label: "PolicyEngine UK code", + href: "https://github.com/PolicyEngine/policyengine-uk", + }, + data: { + label: "Microcosm data pipeline", + href: "https://github.com/PolicyEngine/microcosm", + }, + hansard: { + label: "Hansard, 24 February 2026", + href: "https://hansard.parliament.uk/Lords/2026-02-24/debates/A381F7D6-0A3C-48FD-8D9E-67751E25877A/NationalInsuranceContributions(EmployerPensionsContributions)Bill", + }, + tpa: { + label: "Tax Policy Associates, September 2026", + href: "https://taxpolicy.org.uk/2026/09/10/universities-uk-national-insurance-proposal/", + }, + cps: { + label: "Centre for Policy Studies, July 2023", + href: "https://cps.org.uk/research/family-friendly-taxation/", + }, + nuffield: { + label: "Nuffield Foundation project", + href: "https://www.nuffieldfoundation.org/project/enhancing-localising-and-democratising-tax-benefit-policy-analysis", + }, + nef: { + label: "New Economics Foundation, July 2026", + href: "https://neweconomics.org/2026/07/insecure-low-quality-work-a-major-driver-of-uks-neets-and-inactivity-crisis", + }, + no10Post: { + label: "PolicyEngine at No 10", + href: "https://www.policyengine.org/uk/research/policyengine-10-downing-street", + }, + dashboard: { + label: "Autumn Budget 2026 dashboard", + href: "https://uk-autumn-budget-2026.vercel.app/uk/autumn-budget-2026", + }, + dashboardCode: { + label: "Dashboard code", + href: "https://github.com/PolicyEngine/uk-autumn-budget-dashboard-2026", + }, + pastEvents: { + label: "Past fiscal events (#107)", + href: "https://github.com/PolicyEngine/uk-autumn-budget-dashboard-2026/pull/107", + }, + review2025: { + label: "Autumn Budget 2025 in review", + href: "https://autumn-budget-2025-in-review.vercel.app/uk/autumn-budget-2025-in-review", + }, +}; + +export const steps = [ + { + title: "The rules", + text: "UK tax and benefit law, written as open code.", + }, + { + title: "The households", + text: "A representative sample of UK households, matched to official statistics.", + }, + { + title: "The results", + text: "Who gains, who loses, and what a policy costs.", + }, +]; + +export type PrepItem = { title: string; text: string; status: "Done" | "In review" }; + +// Each line is checked against PolicyEngine/uk-autumn-budget-dashboard-2026 +// (main, and the open PRs named in the README). +export const preparation: PrepItem[] = [ + { + title: "Four mock Budgets", + text: "Full Budget-day runs on invented measures on 28 September and 5, 12 and 19 October, to rehearse every step of the day.", + status: "Done", + }, + { + title: "A Budget-day runbook", + text: "Timed checkpoints from the start of the day to the combined run, publication and the overnight briefing, built on the mock Budgets.", + status: "Done", + }, + { + title: "Fixed model and data", + text: "policyengine 6.10.2 with the certified Microcosm UK 2024-25 households, so every figure can be reproduced.", + status: "Done", + }, + { + title: "A household calculator", + text: "Any household's change in net income from the selected measures, live on the dashboard.", + status: "Done", + }, + { + title: "Every measure in about 8 minutes", + text: "All measures and the combined package run in parallel, with results identical to a one-at-a-time run.", + status: "In review", + }, + { + title: "Each measure published once reviewed", + text: "A measure goes live as soon as its figures pass review, and every public file must carry a review entry.", + status: "In review", + }, +]; + +// The six events in #107, with the measures each imports. +export const pastEvents = [ + { event: "Autumn Budget 2025", measures: 9 }, + { event: "Spring Statement 2025", measures: 2 }, + { event: "Autumn Budget 2024", measures: 5 }, + { event: "Spring Budget 2024", measures: 3 }, + { event: "Autumn Statement 2023", measures: 4 }, + { event: "Spring Budget 2023", measures: 2 }, +]; + diff --git a/slideshows/introduction-2026/slides/deck.module.css b/slideshows/introduction-2026/slides/deck.module.css new file mode 100644 index 0000000..9d9f892 --- /dev/null +++ b/slideshows/introduction-2026/slides/deck.module.css @@ -0,0 +1,660 @@ +/* Analysing the UK Autumn Budget 2026 with PolicyEngine deck. Colours come from + theme variables. */ + +.section { + margin-bottom: 0.5rem; + font-size: 1rem; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--pe-teal); +} + +.subtitle { + margin-top: 0.75rem; + font-size: 1.25rem; + line-height: 1.5; + color: var(--color-gray-600); +} + +.candidate { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin-top: 0.75rem; + border: 1px solid var(--color-teal-200); + border-radius: 0.5rem; + background: var(--pe-light); + padding: 0.3rem 0.75rem; + font-size: 0.95rem; + color: var(--pe-dark); +} + +.body { + display: flex; + min-height: 0; + flex: 1; + flex-direction: column; + padding-bottom: 2.5rem; +} + +/* Preparation */ +.prepCard { + border: 1px solid var(--color-gray-200); + border-left: 4px solid var(--pe-teal); + background: white; + padding: 1.25rem 1.5rem; +} + +.statusDone, +.statusReview { + display: inline-flex; + align-items: center; + gap: 0.35rem; + border-radius: 999px; + padding: 0.15rem 0.6rem; + font-size: 0.85rem; + font-weight: 600; +} + +.statusDone { + background: var(--pe-light); + color: var(--pe-teal-dark); +} + +.statusReview { + background: color-mix(in srgb, var(--pe-amber) 15%, white); + color: var(--pe-amber-dark); +} + +/* Past Budgets */ +.pastGrid { + display: grid; + min-height: 0; + flex: 1; + grid-template-columns: 1fr 1.25fr; + gap: 3rem; +} + +.panelTitle { + font-size: 1.4rem; + font-weight: 600; + color: var(--pe-dark); +} + +.eventTable { + margin-top: 1rem; + border-top: 2px solid var(--pe-dark); +} + +.eventHead, +.eventRow { + display: grid; + grid-template-columns: 1fr 12rem; + border-bottom: 1px solid var(--color-gray-200); + padding: 0.55rem 0; + font-size: 1.15rem; +} + +.eventHead { + font-size: 0.95rem; + font-weight: 600; + color: var(--color-gray-500); +} + +.panelNote { + margin-top: 1rem; + font-size: 1.05rem; + line-height: 1.5; + color: var(--color-gray-600); +} + +.shotCard { + display: flex; + min-height: 0; + flex-direction: column; + align-self: start; + border: 1px solid var(--color-gray-200); + border-left: 4px solid var(--pe-teal); + background: white; +} + +.shot { + width: 100%; + height: auto; + max-height: 38vh; + object-fit: cover; + object-position: top; +} + +.shotCaption { + padding: 0.9rem 1.1rem; + font-size: 1.05rem; + line-height: 1.45; + color: var(--color-gray-700); +} + +/* Closing */ +.closing { + display: flex; + width: 100%; + max-width: 64rem; + flex-direction: column; + align-items: center; + gap: 2.5rem; +} + +.closingTitle { + font-size: 3.75rem; + line-height: 1.1; + text-align: center; +} + +.closingDashboard { + display: flex; + width: 100%; + align-items: center; + justify-content: space-between; + gap: 2.5rem; + border: 1px solid rgb(255 255 255 / 0.3); + border-radius: 1.25rem; + background: rgb(255 255 255 / 0.12); + padding: 2rem 2rem 2rem 2.5rem; + color: inherit; +} + +.closingDashboardText { + display: flex; + flex-direction: column; + gap: 0.6rem; +} + +.closingEyebrow { + font-size: 0.95rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + opacity: 0.8; +} + +.closingMain { + font-size: 2.1rem; + font-weight: 700; + line-height: 1.2; +} + +.closingHint { + font-size: 1.05rem; + opacity: 0.75; +} + +.closingQr { + width: 15rem; + height: 15rem; + flex-shrink: 0; + border-radius: 0.75rem; + background: white; + padding: 0.5rem; +} + +.closingContacts { + display: grid; + width: 100%; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.9rem 1.25rem; +} + +.closingContact { + display: flex; + align-items: center; + gap: 0.9rem; + border: 1px solid rgb(255 255 255 / 0.15); + border-radius: 1rem; + background: rgb(255 255 255 / 0.08); + padding: 0.7rem 1.1rem; + color: inherit; + font-size: 1.05rem; + font-weight: 500; +} + +.closingContactIcon { + display: flex; + height: 2.5rem; + width: 2.5rem; + flex-shrink: 0; + align-items: center; + justify-content: center; + border-radius: 9999px; + background: white; + color: var(--pe-teal); +} + +/* What PolicyEngine is */ +.whatBody { + display: flex; + flex: 1; + flex-direction: column; + justify-content: center; + gap: 3rem; + padding-bottom: 2rem; +} + +.whatFlow { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 0; +} + +.whatStepWrap { + display: flex; + align-items: stretch; +} + +.whatStep { + display: flex; + flex: 1; + flex-direction: column; + border: 1px solid var(--color-gray-200); + border-top: 5px solid var(--pe-teal); + border-radius: 1rem; + background: white; + padding: 2.5rem 2.25rem 2.75rem; +} + +.whatIcon { + display: flex; + height: 4.5rem; + width: 4.5rem; + align-items: center; + justify-content: center; + border-radius: 9999px; + background: var(--pe-teal); + color: white; +} + +.whatStepTitle { + margin-top: 1.75rem; + font-size: 2.25rem; + font-weight: 700; + color: var(--pe-dark); +} + +.whatStepText { + margin-top: 0.9rem; + font-size: 1.6rem; + line-height: 1.4; + color: var(--color-gray-600); +} + +.whatArrow { + flex-shrink: 0; + align-self: center; + margin: 0 1rem; + color: var(--pe-teal); +} + +.whatCode { + display: inline-flex; + align-items: center; + gap: 0.9rem; + align-self: flex-start; + font-size: 1.5rem; + color: var(--color-gray-700); +} + +.whatCode svg { + color: var(--pe-teal); +} + +/* Title slide: keep the logo, speakers and date clear of each other on laptops. */ +@media (max-height: 760px) { + .titleCover { + padding-top: 6rem !important; + } + + .titleCover > :global(*) { + margin-bottom: 1.25rem !important; + } + + .titleCover > :global(:first-child) { + display: none; + } + + .titleCover h1 { + font-size: 2.25rem; + } + + .titleCover :global(.w-28) { + width: 5rem; + height: 5rem; + } +} + +/* Keep the shared slide template legible on a laptop during the meeting. */ +@media (max-height: 850px) { + .deck > :global(.absolute.inset-0) { + padding-top: 3rem; + } + + .deck :global(.mb-10) { + margin-bottom: 1.5rem; + } + + .deck h1 { + font-size: 2.625rem; + } + + .deck :global(.mt-12) { + margin-top: 2rem; + } + + .deck :global(.mt-10), + .deck :global(.mt-9) { + margin-top: 1.5rem; + } + + .deck :global(.mt-8), + .deck :global(.mt-7) { + margin-top: 1.25rem; + } + + .deck :global(.mt-6) { + margin-top: 0.5rem; + } + + .deck th, + .deck td { + padding-top: 0.625rem; + padding-bottom: 0.625rem; + } + + .deck :global(.space-y-6) > :not(:last-child) { + margin-bottom: 1rem; + } + + .deck :global(.space-y-4) > :not(:last-child) { + margin-bottom: 0.5rem; + } + + .deck :global(.pb-5) { + padding-bottom: 1rem; + } + + .deck :global(.pb-3) { + padding-bottom: 0.5rem; + } + + .deck :global(.space-y-5) > :not(:last-child) { + margin-bottom: 0.75rem; + } + + .deck :global(.space-y-3) > :not(:last-child) { + margin-bottom: 0.5rem; + } +} + +/* Safari on a laptop leaves less than 760px for the slide. */ +@media (max-height: 760px) { + .deck > :global(.absolute.inset-0) { + padding-top: 2rem; + } + + .deck :global(.mb-10) { + margin-bottom: 1rem; + } + + .deck h1 { + font-size: 2.25rem; + } + + .deck :global(.text-xl) { + font-size: 1.05rem; + line-height: 1.45rem; + } + + .deck :global(.text-2xl) { + font-size: 1.25rem; + line-height: 1.7rem; + } + + .deck :global(.text-lg) { + font-size: 0.95rem; + line-height: 1.35rem; + } + + .deck :global(.text-base) { + font-size: 0.85rem; + line-height: 1.2rem; + } + + .deck th, + .deck td { + padding-top: 0.35rem; + padding-bottom: 0.35rem; + } + + .deck :global(.pb-4) { + padding-bottom: 0.5rem; + } + + .deck :global(.space-y-5) > :not(:last-child) { + margin-bottom: 0.5rem; + } + + .deck :global(.pt-5) { + padding-top: 0.75rem; + } + + .deck :global(.mt-6) { + margin-top: 0.75rem; + } + + .deck :global(.p-4) { + padding: 0.6rem 0.75rem; + } + + .shot { + max-height: 46vh; + } +} + +@media (max-height: 850px) { + .prepCard { + padding: 0.9rem 1.25rem; + } + + .prepCard h2 { + font-size: 1.35rem; + } + + .prepCard p:last-child { + font-size: 1rem; + } + + .eventHead, + .eventRow { + padding: 0.4rem 0; + font-size: 1.05rem; + } + + .shot { + max-height: 32vh; + } +} + +@media (max-height: 760px) { + .subtitle { + font-size: 1.1rem; + } +} + +/* What PolicyEngine is and the close, on a laptop screen */ +@media (max-height: 850px) { + .whatBody { + gap: 2rem; + padding-bottom: 1rem; + } + + .whatStep { + padding: 1.6rem 1.5rem 1.8rem; + } + + .whatIcon { + height: 3.25rem; + width: 3.25rem; + } + + .whatIcon svg { + width: 28px; + height: 28px; + } + + .whatStepTitle { + margin-top: 1.1rem; + font-size: 1.6rem; + } + + .whatStepText { + margin-top: 0.6rem; + font-size: 1.2rem; + } + + .whatArrow { + width: 32px; + height: 32px; + margin: 0 0.6rem; + } + + .whatCode { + font-size: 1.15rem; + } + + .closing { + padding-top: 5.5rem; + gap: 1.25rem; + } + + .closingTitle { + font-size: 2.5rem; + } + + .closingDashboard { + padding: 1.1rem 1.1rem 1.1rem 1.75rem; + } + + .closingMain { + font-size: 1.5rem; + } + + .closingHint { + font-size: 0.95rem; + } + + .closingQr { + width: 10rem; + height: 10rem; + } + + .closingContact { + padding: 0.5rem 0.9rem; + font-size: 0.95rem; + } + + .closingContactIcon { + height: 2rem; + width: 2rem; + } +} + +/* The analysis: live dashboard */ +.liveBody { + display: flex; + width: 100%; + max-width: 72rem; + flex-direction: column; + gap: 1.75rem; + margin: 1.5rem auto 0; +} + +.liveCard { + display: flex; + width: 100%; + align-items: center; + justify-content: space-between; + gap: 3rem; + border-radius: 1.5rem; + padding: 2.75rem 2.75rem 2.75rem 3.25rem; + color: white; + box-shadow: 0 1.5rem 3rem -1.5rem rgb(0 0 0 / 0.35); + transition: transform 0.15s ease, box-shadow 0.15s ease; +} + +.liveCard:hover, +.liveCard:focus-visible { + transform: translateY(-2px); + box-shadow: 0 1.75rem 3.5rem -1.5rem rgb(0 0 0 / 0.45); +} + +.liveCard:focus-visible { + outline: 3px solid var(--pe-amber); + outline-offset: 4px; +} + +.liveMain { + font-size: 2.6rem; + font-weight: 700; + line-height: 1.15; +} + +.liveTabs { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1rem; +} + +.liveTab { + display: flex; + align-items: center; + gap: 0.75rem; + border: 1px solid var(--color-gray-200); + border-radius: 1rem; + background: var(--pe-light); + padding: 1rem 1.25rem; + color: var(--pe-dark); + font-size: 1.15rem; + font-weight: 600; +} + +.liveTab svg:first-child { + color: var(--pe-teal); +} + +.liveTab svg:last-child { + margin-left: auto; + color: var(--pe-teal); +} + +.liveTab:hover, +.liveTab:focus-visible { + border-color: var(--pe-teal); +} + +@media (max-height: 850px) { + .liveBody { + gap: 1.25rem; + margin-top: 0.75rem; + } + + .liveCard { + padding: 2rem 2rem 2rem 2.5rem; + } + + .liveMain { + font-size: 2.1rem; + } + + .liveCard .closingQr { + width: 12rem; + height: 12rem; + } +} diff --git a/slideshows/introduction-2026/slides/index.tsx b/slideshows/introduction-2026/slides/index.tsx new file mode 100644 index 0000000..4fd1513 --- /dev/null +++ b/slideshows/introduction-2026/slides/index.tsx @@ -0,0 +1,345 @@ +import type { ReactNode } from "react"; +import { + IconArrowRight, + IconBrandGithub, + IconBrandLinkedin, + IconChartBar, + IconCircleCheck, + IconClockHour4, + IconFileCode, + IconHome, + IconInfoCircle, + IconMail, + IconTrendingUp, + IconUsers, + IconWorld, +} from "@tabler/icons-react"; +import Image from "@/components/core/BasePathImage"; +import Slide from "@/components/core/Slide"; +import CoverSlide from "@/components/layout/CoverSlide"; +import SlideHeader from "@/components/layout/SlideHeader"; +import SlideTitle from "@/components/layout/SlideTitle"; +import { speakers } from "@/lib/speakers"; +import { + pastEvents, + preparation, + sources, + steps, + type Source, +} from "../content"; +import styles from "./deck.module.css"; + +const sections = { + intro: "PolicyEngine", + budget: "Autumn Budget 2026", + analysis: "The analysis", +}; + +function ExternalLink({ + children, + href, + className = "", +}: { + children: ReactNode; + href: string; + className?: string; +}) { + return ( + event.stopPropagation()} + className={`pointer-events-auto hover:underline ${className}`} + > + {children} + + ); +} + +function SourceLine({ items }: { items: Source[] }) { + return ( +
+ Sources + {items.map((item) => ( + + {item.label} + + ))} +
+ ); +} + +function Frame({ + section, + title, + subtitle, + children, + references = [], + label, +}: { + section?: string; + title: string; + subtitle?: ReactNode; + children: ReactNode; + references?: Source[]; + /** A one-line status note under the subtitle, such as the candidate label. */ + label?: string; +}) { + return ( + +
+ + {section &&

{section}

} + {title} + {subtitle &&

{subtitle}

} + {label && ( +

+

+ )} +
+
{children}
+
+ {references.length > 0 && } +
+ ); +} + +export function TitleSlide() { + return ( + + ); +} + +const stepIcons = [IconFileCode, IconHome, IconChartBar]; + +// The Good Growth Foundation deck's merged "What PolicyEngine is" slide. +export function WhatSlide() { + return ( + +
+
+ {steps.map((step, index) => { + const Icon = stepIcons[index]; + return ( +
+
+ + +

{step.title}

+

{step.text}

+
+ {index < steps.length - 1 && ( +
+ ); + })} +
+ + +
+ + ); +} + +export function PreparationSlide() { + return ( + +
+ {preparation.map((item) => { + const done = item.status === "Done"; + const Icon = done ? IconCircleCheck : IconClockHour4; + return ( +
+

+

+

{item.title}

+

{item.text}

+
+ ); + })} +
+ + ); +} + +export function PastBudgetsSlide() { + return ( + +
+
+

Six fiscal events since 2023, each on its own page

+
+
+ Event + Measures modelled +
+ {pastEvents.map((row) => ( +
+ {row.event} + {row.measures} +
+ ))} +
+

+ Revenue and income-decile charts and the OBR comparison for each + event; every measure not modelled is listed with its reason. In + review, to publish after 28 October. +

+
+ + Autumn Budget 2025 in review: timeline, scores and household calculator tabs +

+ Autumn Budget 2025 in review:{" "}163 publications on + one timeline, each score beside the Budget's and + PolicyEngine's, and the published household examples + replicated. +

+
+
+ + ); +} + +const tabs = [ + { label: "Population impact", tab: "dashboard", Icon: IconUsers }, + { label: "Household impact", tab: "household", Icon: IconHome }, + { label: "Living standards", tab: "living", Icon: IconTrendingUp }, +]; + +// The analysis is presented live: one card opens the dashboard. +export function DashboardSlide() { + return ( + +
+ + + Open the dashboard + uk-autumn-budget-2026.vercel.app + + Population impact, household impact and the living standards outlook + + + QR code for the Autumn Budget 2026 dashboard + +
+ {tabs.map(({ label, tab, Icon }) => ( + + + ))} +
+
+ + ); +} + +const contacts = [ + { label: "policyengine.org/uk", url: sources.home.href, Icon: IconWorld }, + { label: "hello@policyengine.org", url: "mailto:hello@policyengine.org", Icon: IconMail }, + { label: "github.com/PolicyEngine", url: "https://github.com/PolicyEngine", Icon: IconBrandGithub }, + { + label: "linkedin.com/company/thepolicyengine", + url: "https://www.linkedin.com/company/thepolicyengine", + Icon: IconBrandLinkedin, + }, +]; + +export function ClosingSlide() { + return ( + +
+

Thank you

+ + + Explore the dashboard + uk-autumn-budget-2026.vercel.app + Scan the code to open it on your phone + + QR code for the Autumn Budget 2026 dashboard + +
+ {contacts.map(({ label, url, Icon }) => ( + + + + {label} + + ))} +
+
+
+ ); +}