root = Card([header, quarterSwitch, healthSummary, activeProjects, overdueMilestones, budgetSection, utilizationSection, risksSection, deadlinesSection, deliveryPace, blockedWork, actions])
header = CardHeader("Project Portfolio Review", "Q3 2025 · PMO")
quarterSwitch = Tabs([q2Tab, q3Tab, q4Tab])
q2Tab = TabItem("q2", "Q2 2025", [q2Note])
q2Note = TextContent("Showing Q2 2025 data. Switch to Q3 for the current review.", "small")
q3Tab = TabItem("q3", "Q3 2025", [q3Note])
q3Note = TextContent("Current quarter — all data below reflects Q3 2025.", "small")
q4Tab = TabItem("q4", "Q4 2025", [q4Note])
q4Note = TextContent("Q4 2025 is planned. Estimates only.", "small")
healthSummary = Callout("success", "Portfolio health: On track", "12 of 15 projects are green. Two are at risk and one is critical — focus on Atlas and Nova.")
activeProjects = Card([activeHeading, activeTable])
activeHeading = Heading("Active Projects", "h2")
activeTable = Table([projectCol, ownerCol, deadlineCol, healthCol])
projectCol = Col("Project", ["Atlas", "Nova", "Orion", "Pulse", "Vertex"])
ownerCol = Col("Owner", ["M. Chen", "A. Patel", "S. Okafor", "L. Reyes", "J. Kim"])
deadlineCol = Col("Deadline", ["2025-08-22", "2025-08-15", "2025-09-05", "2025-08-30", "2025-09-12"])
healthCol = Col("Health", ["Critical", "At risk", "On track", "On track", "On track"])
overdueMilestones = Card([overdueHeading, overdueList])
overdueHeading = Heading("Overdue Milestones", "h2")
overdueList = ListBlock([overdue1, overdue2, overdue3], "number")
overdue1 = ListItem("Atlas — Data migration", "Due 2025-07-28 · 14 days late", null, "Review")
overdue2 = ListItem("Nova — API integration", "Due 2025-08-01 · 10 days late", null, "Review")
overdue3 = ListItem("Orion — QA sign-off", "Due 2025-08-05 · 6 days late", null, "Review")
budgetSection = Card([budgetHeading, budgetChart])
budgetHeading = Heading("Budget Spent vs Allocation", "h2")
budgetChart = HorizontalBarChart(["Atlas", "Nova", "Orion", "Pulse", "Vertex"], [allocSeries, spentSeries], "grouped", "USD", "Project")
allocSeries = Series("Allocated", [120000, 85000, 150000, 60000, 95000])
spentSeries = Series("Spent", [118500, 82000, 91000, 54000, 88000])
utilizationSection = Card([utilHeading, utilChart])
utilHeading = Heading("Team Utilization", "h2")
utilChart = BarChart(["Design", "Engineering", "QA", "Product", "Ops"], [utilSeries], "grouped", "Team", "Utilization %")
utilSeries = Series("Utilization", [78, 92, 85, 71, 64])
risksSection = Card([risksHeading, risksTable])
risksHeading = Heading("Risks", "h2")
risksTable = Table([riskCol, severityCol, ownerCol2])
riskCol = Col("Risk", ["Atlas data loss", "Nova scope creep", "Orion vendor delay", "Pulse key-person dependency"])
severityCol = Col("Severity", ["Critical", "High", "Medium", "Low"])
ownerCol2 = Col("Owner", ["M. Chen", "A. Patel", "S. Okafor", "L. Reyes"])
deadlinesSection = Card([deadlinesHeading, deadlinesList])
deadlinesHeading = Heading("Deadlines — Next Two Weeks", "h2")
deadlinesList = ListBlock([deadline1, deadline2, deadline3], "number")
deadline1 = ListItem("Nova — Beta release", "Due 2025-08-15 (6 days)")
deadline2 = ListItem("Atlas — Milestone 4", "Due 2025-08-18 (9 days)")
deadline3 = ListItem("Pulse — UAT complete", "Due 2025-08-22 (13 days)")
deliveryPace = Card([paceHeading, paceChart])
paceHeading = Heading("Delivery Pace — Past Six Sprints", "h2")
paceChart = LineChart(["Sprint 1", "Sprint 2", "Sprint 3", "Sprint 4", "Sprint 5", "Sprint 6"], [committedSeries, deliveredSeries], "linear", "Sprint", "Story Points")
committedSeries = Series("Committed", [120, 130, 125, 140, 135, 150])
deliveredSeries = Series("Delivered", [110, 125, 118, 132, 128, 141])
blockedWork = Card([blockedHeading, blockedList])
blockedHeading = Heading("Blocked Work Items", "h2")
blockedList = ListBlock([blocked1, blocked2, blocked3, blocked4], "number")
blocked1 = ListItem("Atlas — ETL pipeline", "Blocked on vendor API · 5 days")
blocked2 = ListItem("Nova — Auth service", "Blocked on security review · 3 days")
blocked3 = ListItem("Orion — Test environment", "Blocked on infra · 2 days")
blocked4 = ListItem("Pulse — Analytics module", "Blocked on data access · 1 day")
actions = Card([actionsHeading, actionButtons])
actionsHeading = Heading("Actions", "h2")
actionButtons = Buttons([exportBtn, staffBtn, archiveBtn], "row")
exportBtn = Button("Export Review")
staffBtn = Button("Request More People", null, "secondary")
archiveBtn = Button("Archive Finished Project", null, "tertiary")