diff --git a/dashboard/app/layout.jsx b/dashboard/app/layout.jsx
index 8e1ff68..2cf406f 100644
--- a/dashboard/app/layout.jsx
+++ b/dashboard/app/layout.jsx
@@ -1,3 +1,6 @@
+import PolicyEngineFooter from "../src/components/PolicyEngineFooter";
+import PolicyEngineHeader from "../src/components/PolicyEngineHeader";
+
import "./globals.css";
export const metadata = {
@@ -9,7 +12,11 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
-
{children}
+
+
+ {children}
+
+
);
}
diff --git a/dashboard/public/assets/logos/policyengine-white.svg b/dashboard/public/assets/logos/policyengine-white.svg
new file mode 100644
index 0000000..253c046
--- /dev/null
+++ b/dashboard/public/assets/logos/policyengine-white.svg
@@ -0,0 +1,18 @@
+
\ No newline at end of file
diff --git a/dashboard/src/components/PolicyEngineFooter.jsx b/dashboard/src/components/PolicyEngineFooter.jsx
new file mode 100644
index 0000000..bc27f5c
--- /dev/null
+++ b/dashboard/src/components/PolicyEngineFooter.jsx
@@ -0,0 +1,60 @@
+const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
+
+// PolicyEngine site footer, rendered by the dashboard itself. Multizone
+// rewrites proxy this app under policyengine.org/uk/bus-fare-cap but do
+// not inject the parent site shell, so the footer links mirror the
+// policyengine.org site footer.
+const FOOTER_LINKS = [
+ { label: "About us", href: "https://policyengine.org/uk/team" },
+ { label: "Donate", href: "https://policyengine.org/uk/donate" },
+ { label: "Developer tools", href: "https://policyengine.org/uk/dev-tools" },
+ { label: "Privacy policy", href: "https://policyengine.org/uk/privacy" },
+ {
+ label: "Terms and conditions",
+ href: "https://policyengine.org/uk/terms",
+ },
+];
+
+export default function PolicyEngineFooter() {
+ return (
+
+ );
+}
diff --git a/dashboard/src/components/PolicyEngineHeader.jsx b/dashboard/src/components/PolicyEngineHeader.jsx
new file mode 100644
index 0000000..798c15d
--- /dev/null
+++ b/dashboard/src/components/PolicyEngineHeader.jsx
@@ -0,0 +1,54 @@
+const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
+
+// PolicyEngine site header, rendered by the dashboard itself. Multizone
+// rewrites proxy this app under policyengine.org/uk/bus-fare-cap but do not
+// inject the parent site shell, so — like the other published dashboards —
+// we render the header/nav here. Links point at the UK site so the tool sits
+// inside the PolicyEngine UK experience. Static (not sticky) so the tool's
+// own sticky title row keeps the top of the viewport while scrolling.
+const NAV_LINKS = [
+ { label: "Research", href: "https://policyengine.org/uk/research" },
+ { label: "Model", href: "https://policyengine.org/uk/model" },
+ { label: "API", href: "https://policyengine.org/uk/api" },
+ { label: "About", href: "https://policyengine.org/uk/about" },
+ { label: "Donate", href: "https://policyengine.org/uk/donate" },
+];
+
+export default function PolicyEngineHeader() {
+ return (
+
+ );
+}
diff --git a/pyproject.toml b/pyproject.toml
index 111e9f7..5d539b1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,10 +22,10 @@ dependencies = [
"pandas>=2.0",
"tables>=3.9",
"huggingface_hub>=0.20",
- # The policyengine.py wrapper; the [uk] extra exact-pins policyengine-uk, so
- # the bundle version alone identifies the whole simulation stack. The Populace
- # UK dataset is loaded via policyengine.tax_benefit_models.uk.
- "policyengine[uk]>=4.17.10",
+ # The policyengine.py wrapper. Its [uk] extra exact-pins policyengine-uk
+ # (==2.89.2 as of bundle 5.0.1), which conflicts with the >=2.89.3 floor
+ # below, so policyengine-uk is installed directly instead of via the extra.
+ "policyengine>=4.17.10",
# person_bus_fare_spending and gov.dft.bus.fare_allocation_weight_by_age,
# which this analysis reads instead of allocating fares itself.
"policyengine-uk>=2.89.3",