From f9d014fd65aaec5a2e752c827eca6b5123f06a31 Mon Sep 17 00:00:00 2001 From: mfonseca Date: Sat, 13 Jun 2026 10:55:58 -0600 Subject: [PATCH 1/8] Add Porto Alegre civic engagement source --- .../IMPLEMENTATION_PLAN.md | 8 +- .../civic-climate-action/SPEC.md | 2 +- .../civic-climate-action/app/README.md | 11 +- .../app/src/app/components/TakeAction.tsx | 142 +++++++++++ .../app/src/app/data/localEngagement.ts | 233 ++++++++++++++++++ 5 files changed, 393 insertions(+), 3 deletions(-) create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localEngagement.ts diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md b/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md index ecc909b..4d775a6 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md @@ -31,6 +31,7 @@ app/src/app/ cities.ts 15 cities: coords, LOCODE, summary, highlights, emissions, risk, provenance stories.ts 15 sourced success stories + images actions.ts 7 universal civic action pathways, tagged by cause + localEngagement.ts Porto Alegre-specific civic recommendations and source links for the demo ``` ## 3. Data model (the important part) @@ -42,6 +43,9 @@ app/src/app/ - **`Risk`** — `topHazards[]` (`hazard`, `keyImpact?`, `level`, `score?`), `summary?`, `source`, `sourceUrl`. - **`Story`** — city, coords, `title`, `category`, `whatCitizensDid`, `outcome`, `year`, `sourceName/Url`, `image?` (`url`, `credit`, `license`, `sourcePageUrl`). +- **`LocalEngagementRecommendation`** — Porto Alegre demo cards with `title`, `priority`, `theme`, + `whyItMatters`, `firstActions[]`, and `sources[]`. This is the bridge from CityCatalyst risk / + emissions data to actual civic pathways and source links. The provenance badge keys off `dataProvenance`; the UI renders sector **bars** when `sectors` exist, else a "largest source" line. Honest caveats live in `emissions.note`. @@ -69,6 +73,7 @@ Base: `https://api.citycatalyst.io`. Cities are keyed by UN/LOCODE (e.g. `BR SAO - All 4 sections built and verified; production build clean; 15 story images load and are licensed. - Live CityCatalyst emissions + CCRA risk baked in for São Paulo, Rio, Curitiba, Porto Alegre. - Verified external inventories + risk for the 11 other cities, each with a source link. +- Porto Alegre "Take Action" demo layer added with official/community engagement sources. **Next (in priority order)** 1. **Widen emissions coverage** — sum more GPC sectors / add scope-2 so the breakdown stops being @@ -76,7 +81,8 @@ Base: `https://api.citycatalyst.io`. Cities are keyed by UN/LOCODE (e.g. `BR SAO 2. **"My city" entry** — geolocation or a typeahead over the live CCRA city list (5,570 BR cities). 3. **Live fetch at runtime** — replace baked-in numbers with on-demand API calls + caching, so data refreshes without a rebuild (add a small route handler or server action). -4. **Real local "Act" data** — per-hero-city community groups, public-comment windows, council agendas. +4. **Real local "Act" data** — expand the Porto Alegre model to the other hero cities: + community groups, public-comment windows, council agendas. 5. **Participation loop** — let residents log an action → produce the measurable co-benefit metric. ## 6. Gotchas diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md b/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md index e951232..5db55b5 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md @@ -9,7 +9,7 @@ ## 0. Open product questions — investigate before building more - **Localization & "my city" entry point.** A citizen should land on *their* city, not a global list. Is the right next move geolocation + a typeahead over the full CityCatalyst city catalogue, or staying with a curated, high-quality seed set? What breaks (data coverage, map clutter) if we go to thousands of cities? -- **The "Act" gap.** The Take Action step is currently *generic* (universal pathways). The real value is **local** next steps — the actual community group, the actual open public-comment window, the actual council agenda. Where does that data come from, and can any of it be sourced reliably per-city rather than hand-curated? +- **The "Act" gap.** The Take Action step now has a Porto Alegre-specific source layer, but the pattern is still hand-curated. The real value is scaling this to actual community groups, open public-comment windows, and council agendas for every supported city. Where can that data be sourced reliably per-city rather than maintained manually? - **Emissions honesty.** The Brazilian inventories pulled live are *partial* (no scope-2 grid electricity yet), which overstates transport's share. Should we (a) sum more datasources for fuller coverage, (b) show a clear "partial" framing (current approach), or (c) switch to a per-capita / sector-relative view that's less sensitive to coverage gaps? - **Citizen feedback loop.** Should residents be able to *report back* (pledged an action, joined a group) so the module produces the participation metrics funders want — closing the loop from engagement to measurable co-benefit? diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md index 504aaac..5276c4d 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md @@ -28,6 +28,9 @@ The interface is deliberately minimalist and plain-language: there are shaping local climate action, and what you could do in your own. 3. **Inspiration** — a gallery of **real, independently sourced** success stories where citizens changed their cities, filterable by action type. Every card links to its source. +4. **Take Action** — universal civic pathways plus a Porto Alegre demo layer with real local + sources such as Defesa Civil, Orçamento Participativo, municipal councils, POA+Drena + Resiliente, AGAPAN, MobiRio, and Bike Anjo. ## Revenue Connection @@ -93,11 +96,17 @@ npm run dev - **Story images** are from Wikimedia Commons under reuse-permitting licenses (CC0 / CC BY / CC BY-SA); photographer credit + license are shown on each image and link to the file page. - **Cities** are the 15 places featured in the success stories, each tagged with its UN/LOCODE. +- **Porto Alegre local engagement source** (`src/app/data/localEngagement.ts`) turns the + data-mapping track into demo-ready cards: flood resilience, landslide prevention, heat and + green infrastructure, residential energy, and active mobility. Each card has first moves and + source links; community sources are included with validation caveats where needed. ## If This Survives the Hackday - [ ] Wire cities by LOCODE to live CityCatalyst Global API data (GHGI / CCRA / HIAP) - [ ] Expand from the seed set to the full CityCatalyst city catalogue + geolocation -- [ ] Real engagement directory per city: community groups, public-comment calendars, council agendas +- [x] Add a Porto Alegre-specific engagement source for the demo +- [ ] Generalize the local engagement source into a real directory per city: community groups, + public-comment calendars, council agendas - [ ] Extend Climate Advisor (AI) to answer "how do I influence my city's climate plan?" - [ ] Participation metrics dashboard for cities/funders (the revenue surface) diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx index 0656912..b895a47 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx @@ -2,6 +2,7 @@ import { useMemo, useState } from "react"; import { actionPathways } from "../data/actions"; +import { portoAlegreEngagementRecommendations } from "../data/localEngagement"; import type { Category } from "../data/types"; import { categoryMeta } from "../data/types"; @@ -18,6 +19,129 @@ export default function TakeAction() { return (
+
+
+
+
Demo city · Porto Alegre
+

+ Local civic actions with real engagement sources +

+

+ These cards turn the Porto Alegre CityCatalyst risk and emissions signals into + specific resident pathways, backed by official city channels and local community + sources. +

+
+ + See Porto Alegre data + +
+ +
+ {portoAlegreEngagementRecommendations.map((item) => ( +
+
+ {item.priority} + {item.theme} +
+
+

{item.title}

+

+ {item.whyItMatters} +

+
+ +
+
+ First moves +
+
    + {item.firstActions.map((action) => ( +
  • + {action.label} + · {action.timeRequired} +
  • + ))} +
+
+ +
+
+ Sources +
+
+ {item.sources.map((source) => ( + + {source.name} ↗ + + ))} +
+
+
+ ))} +
+
+
setCause("All")} /> {categories.map((c) => ( @@ -143,6 +267,24 @@ export default function TakeAction() { ); } +function Badge({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} + function Chip({ label, color, diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localEngagement.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localEngagement.ts new file mode 100644 index 0000000..c659a31 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localEngagement.ts @@ -0,0 +1,233 @@ +export type LocalSource = { + id: string; + name: string; + type: "official" | "community"; + url: string; + note: string; +}; + +export type LocalCitizenAction = { + label: string; + timeRequired: string; + impactType: string; +}; + +export type LocalEngagementRecommendation = { + id: string; + cityId: "porto-alegre"; + title: string; + priority: "Very high" | "High" | "Medium"; + theme: "Resilience" | "Greening" | "Energy" | "Mobility"; + whyItMatters: string; + firstActions: LocalCitizenAction[]; + sources: LocalSource[]; +}; + +export const portoAlegreEngagementRecommendations: LocalEngagementRecommendation[] = [ + { + id: "poa-flood-resilience", + cityId: "porto-alegre", + title: "Help shape flood-resilience investments", + priority: "Very high", + theme: "Resilience", + whyItMatters: + "CityCatalyst CCRA marks flooding as a very high risk signal for Porto Alegre's infrastructure and public health. The civic step is not just awareness: residents can use official planning, grievance, and budgeting channels to ask where drainage and recovery investments go first.", + firstActions: [ + { + label: "Use POA+Drena Resiliente materials to track drainage project engagement and accountability.", + timeRequired: "20 min", + impactType: "Project accountability", + }, + { + label: "Bring flood-risk priorities into the participatory budget or a council conversation.", + timeRequired: "1-2 hours", + impactType: "Budget influence", + }, + ], + sources: [ + { + id: "poa-defesa-civil", + name: "Defesa Civil de Porto Alegre", + type: "official", + url: "https://prefeitura.poa.br/defesa-civil", + note: "Official disaster risk and emergency response channel.", + }, + { + id: "poa-drena-resiliente-pepi", + name: "POA+Drena Resiliente stakeholder engagement plan", + type: "official", + url: "https://prefeitura.poa.br/sites/default/files/usu_doc/sites/smpg/PEPI-Arroio%20Moinho_rev.03.26.pdf", + note: "Stakeholder engagement plan for resilient urban drainage investments.", + }, + { + id: "poa-op", + name: "Orcamento Participativo", + type: "official", + url: "https://prefeitura.poa.br/smgov/orcamento-participativo", + note: "Participatory budgeting pathway for regional and thematic priorities.", + }, + ], + }, + { + id: "poa-landslide-prevention", + cityId: "porto-alegre", + title: "Support landslide prevention in exposed areas", + priority: "Very high", + theme: "Resilience", + whyItMatters: + "CityCatalyst CCRA also identifies landslides as a very high risk for infrastructure and public health. Residents need a clear route from risk maps and local observations to prevention decisions.", + firstActions: [ + { + label: "Report slope instability, drainage blockages, or risk conditions through official channels.", + timeRequired: "10-20 min", + impactType: "Risk reduction", + }, + { + label: "Ask planning bodies how landslide prevention maps and investments are prioritized.", + timeRequired: "30-60 min", + impactType: "Transparency", + }, + ], + sources: [ + { + id: "poa-defesa-civil", + name: "Defesa Civil de Porto Alegre", + type: "official", + url: "https://prefeitura.poa.br/defesa-civil", + note: "Official channel for disaster risk and civil defense guidance.", + }, + { + id: "poa-cmdua", + name: "Conselho Municipal de Desenvolvimento Urbano Ambiental", + type: "official", + url: "https://prefeitura.poa.br/smamus/planejamento-urbano/cmdua", + note: "Urban-environmental council linked to planning and land-use decisions.", + }, + ], + }, + { + id: "poa-heat-green-infrastructure", + cityId: "porto-alegre", + title: "Expand shade, trees, and cooling spaces", + priority: "High", + theme: "Greening", + whyItMatters: + "Heatwave risk appears in Porto Alegre's CCRA profile, and green infrastructure is one of the clearest places where local knowledge matters. Residents can nominate hot spots, defend tree care, and push for shade where it is most needed.", + firstActions: [ + { + label: "Nominate streets, bus stops, schools, or plazas that need shade and cooling.", + timeRequired: "10-15 min", + impactType: "Local knowledge", + }, + { + label: "Use environmental council or community advocacy channels to support equitable tree care.", + timeRequired: "30-60 min", + impactType: "Policy influence", + }, + ], + sources: [ + { + id: "poa-tree-care", + name: "Planning and care for trees", + type: "official", + url: "https://prefeitura.poa.br/smamus/planejamento-e-cuidado-com-arvores", + note: "Official urban tree maintenance and care information.", + }, + { + id: "poa-comam", + name: "Conselho Municipal do Meio Ambiente", + type: "official", + url: "https://prefeitura.poa.br/catalogo-conselhos/comam", + note: "Municipal environment council for environmental policy and oversight.", + }, + { + id: "agapan", + name: "AGAPAN", + type: "community", + url: "https://www.agapan.org.br/", + note: "Environmental advocacy organization in Rio Grande do Sul.", + }, + ], + }, + { + id: "poa-residential-energy", + cityId: "porto-alegre", + title: "Make homes more energy efficient", + priority: "Medium", + theme: "Energy", + whyItMatters: + "The Porto Alegre snapshot includes residential fuel and electricity emissions examples from SEEG and EPE. Efficiency upgrades can connect mitigation to comfort, heat resilience, and affordability.", + firstActions: [ + { + label: "Ask for retrofit incentives that prioritize low-income and heat-exposed households.", + timeRequired: "30-60 min", + impactType: "Equity", + }, + { + label: "Use the climate action plan as a source when advocating for building-efficiency programs.", + timeRequired: "15-30 min", + impactType: "Mitigation", + }, + ], + sources: [ + { + id: "poa-climate-action-plan", + name: "Porto Alegre Climate Action Plan", + type: "official", + url: "https://prefeitura.poa.br/smamus/plano-de-acao-climatica", + note: "Official climate planning source for mitigation and adaptation priorities.", + }, + { + id: "poa-op", + name: "Orcamento Participativo", + type: "official", + url: "https://prefeitura.poa.br/smgov/orcamento-participativo", + note: "Participatory budgeting channel for local investment priorities.", + }, + ], + }, + { + id: "poa-active-mobility", + cityId: "porto-alegre", + title: "Support safer walking, cycling, and public-space access", + priority: "Medium", + theme: "Mobility", + whyItMatters: + "The climate action catalogue includes active mobility as a mitigation pathway. For residents, the concrete route is mobility policy, safe-streets advocacy, and local cycling support.", + firstActions: [ + { + label: "Comment on street redesigns, bike lanes, transit access, and pedestrian safety.", + timeRequired: "15-30 min", + impactType: "Transport policy", + }, + { + label: "Join a local mobility group or cycling support network.", + timeRequired: "Ongoing", + impactType: "Collective action", + }, + ], + sources: [ + { + id: "poa-commu", + name: "Conselho Municipal de Mobilidade Urbana", + type: "official", + url: "https://prefeitura.poa.br/catalogo-conselhos/commu", + note: "Consultative council for urban mobility policy.", + }, + { + id: "poa-mobirio", + name: "MobiRio", + type: "community", + url: "https://www.facebook.com/associacaomobirio/?locale=pt_BR", + note: "Local mobility and cycling advocacy group; current contact details should be validated.", + }, + { + id: "bike-anjo", + name: "Bike Anjo", + type: "community", + url: "https://bikeanjo.org/", + note: "Volunteer cycling network; local chapter/activity should be checked before production use.", + }, + ], + }, +]; From cf55ea9ff4bd918b0f2638e6e43c8209ebcd1bd8 Mon Sep 17 00:00:00 2001 From: mfonseca Date: Sat, 13 Jun 2026 11:04:38 -0600 Subject: [PATCH 2/8] Move Porto Alegre actions into city explorer --- .../IMPLEMENTATION_PLAN.md | 5 +- .../civic-climate-action/SPEC.md | 2 +- .../civic-climate-action/app/README.md | 12 +- .../app/src/app/components/CityExplorer.tsx | 3 + .../app/components/LocalEngagementPanel.tsx | 83 ++++++++++ .../app/src/app/components/TakeAction.tsx | 142 ------------------ 6 files changed, 96 insertions(+), 151 deletions(-) create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md b/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md index 4d775a6..8c19d8e 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/IMPLEMENTATION_PLAN.md @@ -25,7 +25,8 @@ app/src/app/ CityMap.tsx Leaflet map, circle markers, fly-to selection (client, dynamic import, ssr:false) CitySnapshot.tsx emissions bars + risk hazards + provenance badge StoriesGallery.tsx success-story cards with images + category filter (client) - TakeAction.tsx civic action pathways + cause filter + CTA (client) + TakeAction.tsx universal civic action pathways + cause filter + CTA (client) + LocalEngagementPanel.tsx contextual Porto Alegre local-source panel in Explore data/ types.ts City, Story, Emissions, Risk, Hazard, StoryImage, Category, ActionPathway cities.ts 15 cities: coords, LOCODE, summary, highlights, emissions, risk, provenance @@ -73,7 +74,7 @@ Base: `https://api.citycatalyst.io`. Cities are keyed by UN/LOCODE (e.g. `BR SAO - All 4 sections built and verified; production build clean; 15 story images load and are licensed. - Live CityCatalyst emissions + CCRA risk baked in for São Paulo, Rio, Curitiba, Porto Alegre. - Verified external inventories + risk for the 11 other cities, each with a source link. -- Porto Alegre "Take Action" demo layer added with official/community engagement sources. +- Porto Alegre local-source panel added to the selected-city Explore view with official/community engagement sources. **Next (in priority order)** 1. **Widen emissions coverage** — sum more GPC sectors / add scope-2 so the breakdown stops being diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md b/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md index 5db55b5..69f8151 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/SPEC.md @@ -9,7 +9,7 @@ ## 0. Open product questions — investigate before building more - **Localization & "my city" entry point.** A citizen should land on *their* city, not a global list. Is the right next move geolocation + a typeahead over the full CityCatalyst city catalogue, or staying with a curated, high-quality seed set? What breaks (data coverage, map clutter) if we go to thousands of cities? -- **The "Act" gap.** The Take Action step now has a Porto Alegre-specific source layer, but the pattern is still hand-curated. The real value is scaling this to actual community groups, open public-comment windows, and council agendas for every supported city. Where can that data be sourced reliably per-city rather than maintained manually? +- **The "Act" gap.** The Explore step now has a Porto Alegre-specific local-source panel, but the pattern is still hand-curated. The real value is scaling this to actual community groups, open public-comment windows, and council agendas for every supported city. Where can that data be sourced reliably per-city rather than maintained manually? - **Emissions honesty.** The Brazilian inventories pulled live are *partial* (no scope-2 grid electricity yet), which overstates transport's share. Should we (a) sum more datasources for fuller coverage, (b) show a clear "partial" framing (current approach), or (c) switch to a per-capita / sector-relative view that's less sensitive to coverage gaps? - **Citizen feedback loop.** Should residents be able to *report back* (pledged an action, joined a group) so the module produces the participation metrics funders want — closing the loop from engagement to measurable co-benefit? diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md index 5276c4d..7b4f87f 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md @@ -28,9 +28,9 @@ The interface is deliberately minimalist and plain-language: there are shaping local climate action, and what you could do in your own. 3. **Inspiration** — a gallery of **real, independently sourced** success stories where citizens changed their cities, filterable by action type. Every card links to its source. -4. **Take Action** — universal civic pathways plus a Porto Alegre demo layer with real local - sources such as Defesa Civil, Orçamento Participativo, municipal councils, POA+Drena - Resiliente, AGAPAN, MobiRio, and Bike Anjo. +4. **Take Action** — universal civic pathways. Porto Alegre also gets a contextual local-source + panel inside Explore, with real sources such as Defesa Civil, Orçamento Participativo, + municipal councils, POA+Drena Resiliente, AGAPAN, MobiRio, and Bike Anjo. ## Revenue Connection @@ -97,9 +97,9 @@ npm run dev CC BY-SA); photographer credit + license are shown on each image and link to the file page. - **Cities** are the 15 places featured in the success stories, each tagged with its UN/LOCODE. - **Porto Alegre local engagement source** (`src/app/data/localEngagement.ts`) turns the - data-mapping track into demo-ready cards: flood resilience, landslide prevention, heat and - green infrastructure, residential energy, and active mobility. Each card has first moves and - source links; community sources are included with validation caveats where needed. + data-mapping track into contextual Explore content: flood resilience, landslide prevention, + heat and green infrastructure, residential energy, and active mobility. Each item has first + moves and source links; community sources are included with validation caveats where needed. ## If This Survives the Hackday diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx index 43b2671..4ffaec8 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx @@ -5,6 +5,7 @@ import dynamic from "next/dynamic"; import type { City, Story } from "../data/types"; import { categoryMeta } from "../data/types"; import CitySnapshot from "./CitySnapshot"; +import LocalEngagementPanel from "./LocalEngagementPanel"; const CityMap = dynamic(() => import("./CityMap"), { ssr: false, @@ -166,6 +167,8 @@ export default function CityExplorer({ cities, stories }: { cities: City[]; stor
)} + + {selectedStories.length > 0 && (
{selectedStories.map((s) => ( diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx new file mode 100644 index 0000000..adc8d98 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx @@ -0,0 +1,83 @@ +import { portoAlegreEngagementRecommendations } from "../data/localEngagement"; + +export default function LocalEngagementPanel({ cityId }: { cityId: string }) { + if (cityId !== "porto-alegre") return null; + + const topRecommendations = portoAlegreEngagementRecommendations.slice(0, 3); + const sourceMap = new Map( + portoAlegreEngagementRecommendations + .flatMap((recommendation) => recommendation.sources) + .map((source) => [source.id, source]) + ); + const sources = Array.from(sourceMap.values()).slice(0, 8); + + return ( +
+
+ Local action sources +
+

+ A Porto Alegre-specific data layer connects the risk profile above to real engagement + channels residents can use now. +

+ +
+ {topRecommendations.map((recommendation) => ( +
+
+ {recommendation.title} + + {recommendation.priority} + +
+

+ {recommendation.firstActions[0]?.label} +

+
+ ))} +
+ +
+ + View source links + +
+ {sources.map((source) => ( + + {source.name} ↗ + + ))} +
+
+
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx index b895a47..0656912 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx @@ -2,7 +2,6 @@ import { useMemo, useState } from "react"; import { actionPathways } from "../data/actions"; -import { portoAlegreEngagementRecommendations } from "../data/localEngagement"; import type { Category } from "../data/types"; import { categoryMeta } from "../data/types"; @@ -19,129 +18,6 @@ export default function TakeAction() { return (
-
-
-
-
Demo city · Porto Alegre
-

- Local civic actions with real engagement sources -

-

- These cards turn the Porto Alegre CityCatalyst risk and emissions signals into - specific resident pathways, backed by official city channels and local community - sources. -

-
- - See Porto Alegre data - -
- -
- {portoAlegreEngagementRecommendations.map((item) => ( -
-
- {item.priority} - {item.theme} -
-
-

{item.title}

-

- {item.whyItMatters} -

-
- -
-
- First moves -
-
    - {item.firstActions.map((action) => ( -
  • - {action.label} - · {action.timeRequired} -
  • - ))} -
-
- -
-
- Sources -
-
- {item.sources.map((source) => ( - - {source.name} ↗ - - ))} -
-
-
- ))} -
-
-
setCause("All")} /> {categories.map((c) => ( @@ -267,24 +143,6 @@ export default function TakeAction() { ); } -function Badge({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} - function Chip({ label, color, From 4aa910e01e4426392a6d89b725a5ee3faa6695c8 Mon Sep 17 00:00:00 2001 From: Carlos Octavio Graffi Date: Sat, 13 Jun 2026 20:00:38 -0300 Subject: [PATCH 3/8] Add per-city HIAP actions + green LLM localizer with carbon counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part A — per-city actions (baked, no backend): - Bake CityCatalyst's HIAP library (155 actions, EN/ES/PT) via a committed fetch script (climateActions.generated.ts); we prioritize per city ourselves since the per-city ranking endpoints aren't populated in prod. - prioritize.ts + hazardNormalize.ts: rank actions by matching each city's CCRA hazards (adaptation) and dominant GHGI sectors (mitigation), balanced 50/50, with sourceSignals traceability ("why this matters for "). - CityActions/ActionCard render prioritized actions per selected city with an EN/ES/PT toggle; engagement.ts adds curated LATAM-first opportunities (needs_local_validation, adopting the parallel team's schema). Part B — green/cheap LLM localizer + EcoLogits: - llm-service/: FastAPI sidecar, OpenAI-compatible provider abstraction (Scaleway/GreenPT/Salamandra/Aya... env-only swap), EcoLogits carbon wrap, mock mode (no key) so the demo runs offline. - api/localize route proxies to the sidecar with a built-in templated fallback; useLocalize + carbonContext + CarbonCounter show a per-session CO2 total. Adding the route handler means the app now runs via next start (not a pure static export); the data half stays static-compatible. Co-Authored-By: Claude Opus 4.8 --- .../civic-climate-action/app/README.md | 36 +- .../civic-climate-action/app/package.json | 3 +- .../app/scripts/fetch-climate-actions.mjs | 68 + .../app/src/app/api/localize/route.ts | 113 + .../app/src/app/components/ActionCard.tsx | 195 + .../app/src/app/components/CarbonCounter.tsx | 35 + .../app/src/app/components/CityActions.tsx | 143 + .../app/src/app/components/CityExplorer.tsx | 3 + .../src/app/data/climateActions.generated.ts | 7946 +++++++++++++++++ .../app/src/app/data/climateActions.ts | 56 + .../app/src/app/data/engagement.ts | 122 + .../app/src/app/layout.tsx | 9 +- .../app/src/app/lib/carbonContext.tsx | 37 + .../app/src/app/lib/hazardNormalize.ts | 45 + .../app/src/app/lib/prioritize.ts | 166 + .../app/src/app/lib/useLocalize.ts | 51 + .../llm-service/.env.example | 21 + .../llm-service/.gitignore | 4 + .../llm-service/README.md | 51 + .../llm-service/ecolog.py | 64 + .../civic-climate-action/llm-service/main.py | 174 + .../llm-service/providers.py | 46 + .../llm-service/requirements.txt | 7 + .../llm-service/schemas.py | 30 + 24 files changed, 9419 insertions(+), 6 deletions(-) create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/scripts/fetch-climate-actions.mjs create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.generated.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/engagement.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/carbonContext.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.env.example create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.gitignore create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/README.md create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/providers.py create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/requirements.txt create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md index 504aaac..bf95087 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md @@ -47,10 +47,23 @@ visible, measurable participation metrics — the kind MDBs, the IDB, and philan ```bash cd events/2026-06-11-unlock-the-money/civic-climate-action/app npm install -npm run dev +npm run build && npm start # stable; dev (--turbopack) can 500 on stale state # Open http://localhost:3000 ``` +The **AI localizer** (the "Make this concrete for my city" button) calls an optional +green-LLM sidecar; if it isn't running, the app's route handler falls back to a built-in +localizer, so the demo works either way. To run the real sidecar (mock mode, no key): + +```bash +cd ../llm-service +python -m venv .venv && source .venv/bin/activate +pip install fastapi "uvicorn[standard]" pydantic python-dotenv +uvicorn main:app --port 8000 # see llm-service/README.md for live/green providers +``` + +To refresh the baked HIAP action library: `npm run data:actions`. + ## Demo Script (5 min) 1. **The gap** — CityCatalyst is powerful but government-only. Citizens are locked out of @@ -59,10 +72,15 @@ npm run dev Act*. No dashboards to decode. 3. **Explore** — search a city, or click the map. Pick Medellín / Bogotá / a Brazilian city and read, in everyday language, what residents there did and what you could do. -4. **The "aha"** — the Inspiration gallery: real, sourced stories of citizens who cooled their +4. **Prioritized actions** — pick a Brazilian hero city (São Paulo): real CityCatalyst **HIAP** + actions, ranked for *this* city's hazards and emitting sectors, each with a "why this matters + here" trace. Switch EN/ES/PT. Hit **"Make this concrete for my city"** → a cheap, green + open-weight LLM rewrites the action into localized next steps, and the **CO₂ counter** (bottom + right) shows the call's EcoLogits footprint. +5. **The "aha"** — the Inspiration gallery: real, sourced stories of citizens who cooled their streets, bought their power grid, rewrote climate law. Filter by action type; every claim links to its source. -5. **Who pays** — civic engagement is a co-benefit funders already score; this makes it +6. **Who pays** — civic engagement is a co-benefit funders already score; this makes it visible and measurable. B2G, IDB, philanthropy. ## Built With @@ -72,7 +90,12 @@ npm run dev - [Leaflet](https://leafletjs.com/) + react-leaflet, with free OpenStreetMap / CARTO basemap tiles - Cities keyed by **UN/LOCODE** — the same key the [CityCatalyst Global API](https://github.com/Open-Earth-Foundation/CityCatalyst/tree/develop/global-api) - uses — so they can connect to live GHGI / CCRA / HIAP data (`api.citycatalyst.io`) + uses — so they connect to live GHGI / CCRA / HIAP data (`api.citycatalyst.io`) +- **HIAP action library** baked from `GET /api/v0/climate_actions` (155 actions, EN/ES/PT), + prioritized per city in `src/app/lib/prioritize.ts` +- **Green LLM localizer**: a Python/FastAPI sidecar (`../llm-service`) calling an open-weight + model via an OpenAI-compatible API on a low-carbon EU provider, instrumented with + [EcoLogits](https://ecologits.ai/) for per-call carbon; model/provider is an env-only swap ## Data & Sources @@ -92,6 +115,11 @@ npm run dev uncertain figures are described qualitatively. Each card links its source. - **Story images** are from Wikimedia Commons under reuse-permitting licenses (CC0 / CC BY / CC BY-SA); photographer credit + license are shown on each image and link to the file page. +- **Climate actions** (`src/app/data/climateActions.generated.ts`) are CityCatalyst's HIAP + library, fetched once and committed (EN/ES/PT). We compute per-city prioritization ourselves + because the per-city ranking endpoints aren't populated in prod yet. +- **Engagement opportunities** (`src/app/data/engagement.ts`) are curated, LATAM-first, and + flagged `needs_local_validation` until a local partner confirms them. - **Cities** are the 15 places featured in the success stories, each tagged with its UN/LOCODE. ## If This Survives the Hackday diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json b/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json index 0f2d738..6877fdd 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json @@ -5,7 +5,8 @@ "scripts": { "dev": "next dev --turbopack", "build": "next build", - "start": "next start" + "start": "next start", + "data:actions": "node scripts/fetch-climate-actions.mjs" }, "dependencies": { "@types/leaflet": "^1.9.21", diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/scripts/fetch-climate-actions.mjs b/events/2026-06-11-unlock-the-money/civic-climate-action/app/scripts/fetch-climate-actions.mjs new file mode 100644 index 0000000..6c0b15f --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/scripts/fetch-climate-actions.mjs @@ -0,0 +1,68 @@ +// Build-time data pipeline: fetch CityCatalyst's HIAP action library once and +// emit a committed TS module so the app builds offline and reproducibly. +// +// node scripts/fetch-climate-actions.mjs +// +// Source: GET https://api.citycatalyst.io/api/v0/climate_actions?language=all +// (~155 city-agnostic actions, full EN/ES/PT i18n, HIAP schema). We do the +// per-city prioritization ourselves (see src/app/lib/prioritize.ts) because the +// per-city ranking endpoints aren't populated in prod yet. + +import { writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const OUT = join(__dirname, "..", "src", "app", "data", "climateActions.generated.ts"); +const URL = "https://api.citycatalyst.io/api/v0/climate_actions?language=all"; + +const HAZARD_KEYS = [ + "droughts", "heatwaves", "floods", "sea-level-rise", + "landslides", "storms", "wildfires", "diseases", +]; + +const lang = (v) => { + // Normalize a possibly-partial i18n object to {en,es,pt}, falling back to en. + if (v == null) return { en: "", es: "", pt: "" }; + if (typeof v === "string") return { en: v, es: v, pt: v }; + const en = v.en ?? v.es ?? v.pt ?? ""; + return { en, es: v.es ?? en, pt: v.pt ?? en }; +}; +const arr = (v) => (Array.isArray(v) ? v.filter(Boolean) : v ? [v] : []); + +function transform(a) { + const types = arr(a.ActionType); + return { + actionId: a.ActionID, + name: lang(a.ActionName), + description: lang(a.Description), + actionType: types.includes("adaptation") ? "adaptation" : "mitigation", + hazards: arr(a.Hazard).filter((h) => HAZARD_KEYS.includes(h)), + sectors: arr(a.Sector), + coBenefits: a.CoBenefits ?? {}, + ghgReductionPotential: a.GHGReductionPotential ?? {}, + adaptationEffectiveness: a.AdaptationEffectiveness ?? null, + adaptationPerHazard: a.AdaptationEffectivenessPerHazard ?? {}, + cost: a.CostInvestmentNeeded ?? null, + timeline: a.TimelineForImplementation ?? null, + biome: a.biome ?? null, + category: a.ActionCategory ?? null, + keyImpacts: typeof a.KeyImpacts === "string" ? a.KeyImpacts : null, + }; +} + +const res = await fetch(URL); +if (!res.ok) throw new Error(`Fetch failed: ${res.status}`); +const raw = await res.json(); +const actions = raw.map(transform); +const stamp = new Date().toISOString().slice(0, 10); + +const header = `// AUTO-GENERATED by scripts/fetch-climate-actions.mjs — do not edit by hand. +// Source: ${URL} +// Fetched: ${stamp} · ${actions.length} actions (CityCatalyst HIAP library, EN/ES/PT). +import type { ClimateAction } from "./climateActions"; + +export const climateActions: ClimateAction[] = `; + +writeFileSync(OUT, header + JSON.stringify(actions, null, 2) + ";\n"); +console.log(`Wrote ${actions.length} actions to ${OUT}`); diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts new file mode 100644 index 0000000..b3a8816 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts @@ -0,0 +1,113 @@ +// Proxy to the green-LLM sidecar (llm-service). If the sidecar is unreachable, +// fall back to a deterministic templated localization so the demo never breaks. +// Adding this route handler is the one thing that makes the app need a Node +// server (next start) rather than a pure static export. + +import { NextResponse } from "next/server"; + +export const runtime = "nodejs"; + +type Body = { + action: { name: string; description: string; type: "mitigation" | "adaptation" }; + cityContext: { name: string; country: string; topHazards: string[]; topSectors: string[] }; + language: "en" | "es" | "pt"; +}; + +const SERVICE_URL = process.env.LLM_SERVICE_URL ?? "http://localhost:8000"; + +export async function POST(req: Request) { + let body: Body; + try { + body = await req.json(); + } catch { + return NextResponse.json({ error: "invalid body" }, { status: 400 }); + } + + // Try the sidecar first (real or mock-mode EcoLogits measurement). + try { + const res = await fetch(`${SERVICE_URL}/localize`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + signal: AbortSignal.timeout(8000), + }); + if (res.ok) return NextResponse.json(await res.json()); + } catch { + // fall through to local fallback + } + + return NextResponse.json(fallbackLocalize(body)); +} + +// Deterministic templated localization — mirrors the sidecar's mock mode so the +// click-through and CO₂ counter work even with the sidecar down. +function fallbackLocalize(body: Body) { + const { action, cityContext, language } = body; + const city = cityContext.name; + const rawFocus = + action.type === "adaptation" + ? cityContext.topHazards[0] ?? "climate risk" + : cityContext.topSectors[0] ?? "emissions"; + const focus = translateFocus(rawFocus, language); + + const steps = templates(language, city, focus, action.name); + // A modest estimate (no live call): ~0.3 g CO₂e for a small open model call. + return { + localizedSteps: steps, + energyWh: 0.8, + gCO2e: 0.3, + model: "templated-fallback", + provider: "fallback", + mock: true, + }; +} + +// Localize the matched hazard/sector term so templated steps read naturally. +function translateFocus(raw: string, lang: "en" | "es" | "pt"): string { + if (lang === "en") return raw.toLowerCase(); + const s = raw.toLowerCase(); + const map: Record = { + // [es, pt] + heat: ["las olas de calor", "as ondas de calor"], + landslide: ["los deslizamientos", "os deslizamentos"], + flood: ["las inundaciones", "as inundações"], + drought: ["la sequía", "a seca"], + disease: ["las enfermedades", "as doenças"], + "sea-level": ["el aumento del nivel del mar", "a elevação do nível do mar"], + storm: ["las tormentas", "as tempestades"], + wildfire: ["los incendios", "os incêndios"], + transport: ["el transporte", "o transporte"], + energy: ["la energía", "a energia"], + waste: ["los residuos", "os resíduos"], + stationary: ["la energía", "a energia"], + }; + for (const key of Object.keys(map)) { + if (s.includes(key)) return lang === "es" ? map[key][0] : map[key][1]; + } + return s; +} + +function templates(lang: "en" | "es" | "pt", city: string, focus: string, action: string): string[] { + if (lang === "es") { + return [ + `Identifica en ${city} a un grupo vecinal o colectivo que ya trabaje en ${focus}.`, + `Asiste a la próxima sesión del consejo municipal donde se discuta "${action}".`, + `Presenta esta acción como propuesta o comentario público, citando el riesgo local.`, + `Invita a tres vecinos a sumarse y comparte el avance en tu comunidad.`, + ]; + } + if (lang === "pt") { + return [ + `Identifique em ${city} um grupo de bairro ou coletivo que já atue em ${focus}.`, + `Participe da próxima sessão do conselho municipal onde "${action}" for discutida.`, + `Apresente esta ação como proposta ou comentário público, citando o risco local.`, + `Convide três vizinhos para participar e compartilhe o progresso na sua comunidade.`, + ]; + } + return [ + `Find a neighborhood group or collective in ${city} already working on ${focus}.`, + `Attend the next city-council session where "${action}" is on the agenda.`, + `Submit this action as a proposal or public comment, citing the local risk.`, + `Invite three neighbors to join and share progress in your community.`, + ]; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx new file mode 100644 index 0000000..fcc92a3 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx @@ -0,0 +1,195 @@ +"use client"; + +import { useState } from "react"; +import type { Lang } from "../data/climateActions"; +import type { RankedAction } from "../lib/prioritize"; +import { useLocalize } from "../lib/useLocalize"; + +const typeMeta = { + adaptation: { label: { en: "Adaptation", es: "Adaptación", pt: "Adaptação" }, color: "var(--accent)" }, + mitigation: { label: { en: "Mitigation", es: "Mitigación", pt: "Mitigação" }, color: "#d97706" }, +} as const; + +const coBenefitLabel: Record> = { + air_quality: { en: "Air quality", es: "Calidad del aire", pt: "Qualidade do ar" }, + water_quality: { en: "Water", es: "Agua", pt: "Água" }, + habitat: { en: "Habitat", es: "Hábitat", pt: "Habitat" }, + cost_of_living: { en: "Lower costs", es: "Menor costo", pt: "Menor custo" }, + housing: { en: "Housing", es: "Vivienda", pt: "Moradia" }, + mobility: { en: "Mobility", es: "Movilidad", pt: "Mobilidade" }, + stakeholder_engagement: { en: "Civic engagement", es: "Participación", pt: "Participação" }, +}; + +const t = { + why: { en: "Why this matters for", es: "Por qué importa en", pt: "Por que importa em" }, + make: { en: "Make this concrete for my city", es: "Hazlo concreto para mi ciudad", pt: "Torne isto concreto para minha cidade" }, + working: { en: "Generating…", es: "Generando…", pt: "Gerando…" }, + steps: { en: "Your localized next steps", es: "Tus próximos pasos locales", pt: "Seus próximos passos locais" }, + estimated: { en: "estimated", es: "estimado", pt: "estimado" }, +}; + +export default function ActionCard({ + ranked, + cityName, + cityContext, + lang, +}: { + ranked: RankedAction; + cityName: string; + cityContext: { country: string; topHazards: string[]; topSectors: string[] }; + lang: Lang; +}) { + const { action, sourceSignals } = ranked; + const meta = typeMeta[action.actionType]; + const { run, loading, result } = useLocalize(); + + // Deduplicate the "why" signals by what they matched on. + const seen = new Set(); + const signals = sourceSignals.filter((s) => { + if (seen.has(s.matchedOn)) return false; + seen.add(s.matchedOn); + return true; + }); + + const benefits = Object.entries(action.coBenefits) + .filter(([, v]) => (v ?? 0) > 0) + .map(([k]) => coBenefitLabel[k]?.[lang] ?? k); + + const [open, setOpen] = useState(false); + + function localize() { + setOpen(true); + run({ + action: { name: action.name[lang], description: action.description[lang], type: action.actionType }, + cityContext: { name: cityName, ...cityContext }, + language: lang, + }); + } + + return ( +
+
+ + {meta.label[lang]} + + + {action.cost && {action.cost} cost} + {action.timeline && {action.timeline}} + +
+ +

{action.name[lang]}

+

+ {action.description[lang].length > 220 + ? action.description[lang].slice(0, 217).trimEnd() + "…" + : action.description[lang]} +

+ + {signals.length > 0 && ( +
+
+ {t.why[lang]} {cityName} +
+
+ {signals.map((s) => ( + + • {s.cityValue} + + ))} +
+
+ )} + + {benefits.length > 0 && ( +
+ {benefits.map((b) => ( + + + {b} + + ))} +
+ )} + +
+ {!open ? ( + + ) : ( +
+
+ {loading ? t.working[lang] : t.steps[lang]} +
+ {loading &&
} + {result && ( + <> +
    + {result.localizedSteps.map((step, i) => ( +
  1. + {step} +
  2. + ))} +
+
+ ~{result.gCO2e.toFixed(2)} g CO₂e · {result.model} + {result.mock ? ` · ${t.estimated[lang]}` : ""} +
+ + )} +
+ )} +
+
+ ); +} + +function Pill({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} + +const ctaStyle: React.CSSProperties = { + font: "inherit", + fontSize: "0.85rem", + fontWeight: 650, + cursor: "pointer", + color: "var(--accent)", + background: "var(--accent-soft)", + border: "none", + borderRadius: 8, + padding: "0.5rem 0.85rem", + width: "100%", +}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx new file mode 100644 index 0000000..ccd0dd8 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx @@ -0,0 +1,35 @@ +"use client"; + +import { useCarbon } from "../lib/carbonContext"; + +// Persistent per-session footprint of the LLM localizer — the "green AI" story. +export default function CarbonCounter() { + const { totalGramsCO2e, callCount } = useCarbon(); + if (callCount === 0) return null; + + return ( +
+ + {totalGramsCO2e.toFixed(2)} g CO₂e + · {callCount} AI {callCount === 1 ? "call" : "calls"} +
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx new file mode 100644 index 0000000..894b7b0 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx @@ -0,0 +1,143 @@ +"use client"; + +import { useMemo, useState } from "react"; +import type { City } from "../data/types"; +import type { Lang } from "../data/climateActions"; +import { climateActions } from "../data/climateActions"; +import { prioritizeActions } from "../lib/prioritize"; +import { engagementByCity } from "../data/engagement"; +import ActionCard from "./ActionCard"; + +const LANGS: { key: Lang; label: string }[] = [ + { key: "en", label: "EN" }, + { key: "es", label: "ES" }, + { key: "pt", label: "PT" }, +]; + +const defaultLang = (country: string): Lang => { + if (country === "Brazil") return "pt"; + if (["Colombia", "Mexico", "Argentina", "Chile", "Peru"].includes(country)) return "es"; + return "en"; +}; + +const copy = { + heading: { en: "Prioritized actions for", es: "Acciones prioritarias para", pt: "Ações prioritárias para" }, + intro: { + en: "Drawn from CityCatalyst's HIAP library and ranked for this city's top risks and emissions.", + es: "Tomadas de la biblioteca HIAP de CityCatalyst y priorizadas según los riesgos y emisiones de la ciudad.", + pt: "Extraídas da biblioteca HIAP do CityCatalyst e priorizadas pelos riscos e emissões da cidade.", + }, + engage: { en: "Where to engage", es: "Dónde participar", pt: "Onde participar" }, + unverified: { en: "needs local validation", es: "requiere validación local", pt: "requer validação local" }, +}; + +export default function CityActions({ city }: { city: City }) { + const [lang, setLang] = useState(defaultLang(city.country)); + + const ranked = useMemo(() => prioritizeActions(city, climateActions, { topN: 6 }), [city]); + if (ranked.length === 0) return null; + + const cityContext = { + country: city.country, + topHazards: (city.risk?.topHazards ?? []).map((h) => h.hazard), + topSectors: city.emissions?.sectors?.map((s) => s.sector) ?? + (city.emissions?.topSector ? [city.emissions.topSector] : []), + }; + + const engagement = engagementByCity[city.id] ?? []; + + return ( +
+
+
+
{copy.heading[lang]} {city.name}
+

+ {copy.intro[lang]} +

+
+
+ {LANGS.map((l) => ( + + ))} +
+
+ +
+ {ranked.map((r) => ( + + ))} +
+ + {engagement.length > 0 && ( +
+
+ {copy.engage[lang]} +
+
+ {engagement.map((o) => ( +
+
+ {o.title[lang]} + {o.needs_local_validation && ( + + {copy.unverified[lang]} + + )} +
+

+ {o.description[lang]} +

+
+ {o.citizenActions.map((a, i) => ( + + {a.label[lang]} + + ))} +
+
+ ))} +
+
+ )} +
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx index 43b2671..e96b797 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx @@ -5,6 +5,7 @@ import dynamic from "next/dynamic"; import type { City, Story } from "../data/types"; import { categoryMeta } from "../data/types"; import CitySnapshot from "./CitySnapshot"; +import CityActions from "./CityActions"; const CityMap = dynamic(() => import("./CityMap"), { ssr: false, @@ -151,6 +152,8 @@ export default function CityExplorer({ cities, stories }: { cities: City[]; stor + + {selected.highlights.length > 0 && (
diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.generated.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.generated.ts new file mode 100644 index 0000000..8574864 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.generated.ts @@ -0,0 +1,7946 @@ +// AUTO-GENERATED by scripts/fetch-climate-actions.mjs — do not edit by hand. +// Source: https://api.citycatalyst.io/api/v0/climate_actions?language=all +// Fetched: 2026-06-13 · 155 actions (CityCatalyst HIAP library, EN/ES/PT). +import type { ClimateAction } from "./climateActions"; + +export const climateActions: ClimateAction[] = [ + { + "actionId": "c40_0010", + "name": { + "en": "Introduce energy-efficiency standards for new residential buildings", + "es": "Introducir estándares de eficiencia energética para nuevas viviendas residenciales", + "pt": "Introduzir padrões de eficiência energética para novos edifícios residenciais" + }, + "description": { + "en": "The city adopts new energy-efficiency standards for residential construction, ensuring all new buildings incorporate design and performance requirements such as improved thermal insulation, natural ventilation, shading devices, efficient lighting (LED), and solar-ready wiring for PV integration. Standards may also establish region-dependent requirements for cooling demand reduction (e.g., reflective roofs, cross-ventilation) and may also include whole life carbon requirements and promote the use of sustainable materials. Smaller cities can integrate these requirements into basic building codes, while larger cities can introduce advanced certifications or municipal green building standards.", + "es": "La ciudad adopta nuevos estándares de eficiencia energética para la construcción residencial, asegurando que todos los edificios nuevos incorporen requisitos de diseño y desempeño como mejor aislamiento térmico, ventilación natural, dispositivos de sombreado, iluminación eficiente (LED) y cableado preparado para la integración de paneles solares fotovoltaicos. Los estándares también pueden establecer requisitos dependientes de la región para la reducción de la demanda de refrigeración (por ejemplo, techos reflectantes, ventilación cruzada) y pueden incluir requisitos de carbono durante todo el ciclo de vida, así como promover el uso de materiales sostenibles. Las ciudades más pequeñas pueden integrar estos requisitos en los códigos básicos de construcción, mientras que las ciudades más grandes pueden introducir certificaciones avanzadas o estándares municipales de construcción ecológica.", + "pt": "A cidade adota novos padrões de eficiência energética para construções residenciais, garantindo que todos os novos edifícios incorporem requisitos de projeto e desempenho, como isolamento térmico aprimorado, ventilação natural, dispositivos de sombreamento, iluminação eficiente (LED) e fiação preparada para integração de energia solar fotovoltaica. Os padrões também podem estabelecer requisitos dependentes da região para redução da demanda de resfriamento (por exemplo, telhados refletivos, ventilação cruzada) e podem incluir exigências de carbono ao longo de todo o ciclo de vida, além de promover o uso de materiais sustentáveis. Cidades menores podem integrar esses requisitos aos códigos básicos de construção, enquanto cidades maiores podem introduzir certificações avançadas ou padrões municipais de construção verde." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": -1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0012", + "name": { + "en": "Introduce energy-efficiency standards for new institutional buildings", + "es": "Introducir estándares de eficiencia energética para nuevos edificios institucionales", + "pt": "Introduzir padrões de eficiência energética para novos edifícios institucionais" + }, + "description": { + "en": "The city introduces energy-efficient and resource-efficient standards for schools, hospitals, and other public buildings, setting an example for sustainable construction. Standards should mandate efficient HVAC systems with proper zoning, daylighting strategies to reduce artificial lighting, occupancy sensors, reflective roofs, and integration of photovoltaic (PV) systems where feasibleand. They can also include whole life carbon requirements and promote the use of sustainable materials. Requirements may vary depending on regional climate conditions to address specific cooling or thermal comfort needs.", + "es": "La ciudad introduce estándares de eficiencia energética y de recursos para escuelas, hospitales y otros edificios públicos, estableciendo un ejemplo para la construcción sostenible. Los estándares deben exigir sistemas HVAC eficientes con zonificación adecuada, estrategias de iluminación natural para reducir la iluminación artificial, sensores de ocupación, techos reflectantes e integración de sistemas fotovoltaicos (PV) donde sea factible. También pueden incluir requisitos de carbono durante todo el ciclo de vida y promover el uso de materiales sostenibles. Los requisitos pueden variar según las condiciones climáticas regionales para abordar necesidades específicas de refrigeración o confort térmico.", + "pt": "A cidade introduz padrões de eficiência energética e de uso eficiente de recursos para escolas, hospitais e outros edifícios públicos, servindo de exemplo para a construção sustentável. Os padrões devem exigir sistemas HVAC eficientes com zoneamento adequado, estratégias de aproveitamento da luz natural para reduzir a iluminação artificial, sensores de presença, telhados refletivos e integração de sistemas fotovoltaicos (PV) sempre que possível. Eles também podem incluir requisitos de carbono ao longo de todo o ciclo de vida e promover o uso de materiais sustentáveis. As exigências podem variar de acordo com as condições climáticas regionais para atender necessidades específicas de resfriamento ou conforto térmico." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": -1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0013", + "name": { + "en": "Support Implementation of Industrial Building Efficiency Standards.", + "es": "Apoyar la implementación de normas de eficiencia energética en edificios industriales.", + "pt": "Apoiar a implementação de padrões de eficiência energética em edifícios industriais." + }, + "description": { + "en": "\"Support Implementation of Industrial Building Efficiency Standards\" set guidelines for environmentally responsible construction, ensuring that new structures adhere to energy-efficient practices, thereby reducing carbon emissions and promoting sustainable urban development. Standards may also include whole life carbon requirements and promote the use of sustainable materials.", + "es": "Apoyar la implementación de normas de eficiencia en edificios industriales establece directrices para una construcción ambientalmente responsable, asegurando que las nuevas estructuras cumplan con prácticas de eficiencia energética, reduciendo así las emisiones de carbono y promoviendo un desarrollo urbano sostenible. Las normas también pueden incluir requisitos de carbono durante todo el ciclo de vida y fomentar el uso de materiales sostenibles.", + "pt": "Apoiar a implementação de padrões de eficiência em edifícios industriais estabelece diretrizes para uma construção ambientalmente responsável, garantindo que novas estruturas sigam práticas de eficiência energética, reduzindo assim as emissões de carbono e promovendo o desenvolvimento urbano sustentável. Os padrões também podem incluir requisitos de carbono ao longo de todo o ciclo de vida e incentivar o uso de materiais sustentáveis." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": -1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0015", + "name": { + "en": "Retrofit residential buildings for energy efficiency", + "es": "Rehabilitar edificios residenciales para mejorar la eficiencia energética", + "pt": "Reformar edifícios residenciais para eficiência energética" + }, + "description": { + "en": "The city supports retrofitting existing residential buildings to improve energy efficiency and reduce emissions. Key interventions include replacing inefficient refrigerators, air conditioners, and lighting with high-efficiency models (e.g., PROCEL Seal appliances), sealing windows and doors to reduce air leakage, and improving indoor comfort through natural ventilation and shading. Municipalities can facilitate access to financing programs, bulk procurement, and technical assistance for households to adopt upgrades. Retrofits should prioritize passive cooling strategies (shading, ventilation) before installing high-efficiency cooling technologies using low-GWP refrigerants.", + "es": "La ciudad apoya la modernización de edificios residenciales existentes para mejorar la eficiencia energética y reducir las emisiones. Las intervenciones clave incluyen reemplazar refrigeradores, aires acondicionados y sistemas de iluminación ineficientes por modelos de alta eficiencia (por ejemplo, electrodomésticos con Sello PROCEL), sellar ventanas y puertas para reducir fugas de aire, y mejorar el confort interior mediante ventilación natural y sombreado. Los municipios pueden facilitar el acceso a programas de financiamiento, compras en volumen y asistencia técnica para que los hogares adopten estas mejoras. Las modernizaciones deben priorizar estrategias de enfriamiento pasivo (sombreado, ventilación) antes de instalar tecnologías de enfriamiento de alta eficiencia que utilicen refrigerantes de bajo GWP.", + "pt": "A cidade apoia a modernização de edifícios residenciais existentes para melhorar a eficiência energética e reduzir as emissões. As principais intervenções incluem a substituição de geladeiras, aparelhos de ar-condicionado e iluminação ineficientes por modelos de alta eficiência (por exemplo, eletrodomésticos com Selo PROCEL), vedação de janelas e portas para reduzir infiltrações de ar e melhoria do conforto interno por meio de ventilação natural e sombreamento. Os municípios podem facilitar o acesso a programas de financiamento, compras em grande escala e assistência técnica para que as famílias adotem as melhorias. As reformas devem priorizar estratégias de resfriamento passivo (sombreamento, ventilação) antes da instalação de tecnologias de resfriamento de alta eficiência que utilizem refrigerantes de baixo GWP." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": -1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0016", + "name": { + "en": "Retrofit commercial and institutional other non-residential buildings for energy efficiency ", + "es": "Reacondicionar edificios comerciales e institucionales no residenciales para mejorar la eficiencia energética", + "pt": "Reformar edifícios comerciais, institucionais e outros não residenciais para eficiência energética" + }, + "description": { + "en": "The city promotes energy retrofits in commercial and institutional buildings such as offices, shopping centers, universities, and hotels. Measures include upgrading HVAC systems with variable refrigerant flow (VRF) units, replacing fluorescent and halogen lighting with LEDs, implementing building automation and energy management systems, and improving the thermal envelope (insulation, reflective coatings, shading). Region-specific adaptations may also be required to address cooling and comfort needs. Retrofits often deliver short payback periods through lower operating costs and enhanced occupant comfort. Retrofits should prioritize passive cooling strategies (shading, ventilation) before installing high-efficiency cooling technologies using low-GWP refrigerants.", + "es": "La ciudad promueve la modernización energética en edificios comerciales e institucionales como oficinas, centros comerciales, universidades y hoteles. Las medidas incluyen la actualización de los sistemas HVAC con unidades de flujo de refrigerante variable (VRF), el reemplazo de iluminación fluorescente y halógena por LEDs, la implementación de sistemas de automatización y gestión energética de edificios, y la mejora de la envolvente térmica (aislamiento, recubrimientos reflectantes, sombreado). También pueden ser necesarias adaptaciones específicas según la región para abordar las necesidades de enfriamiento y confort. Las modernizaciones suelen ofrecer periodos de recuperación cortos gracias a la reducción de los costos operativos y la mejora del confort de los ocupantes. Las modernizaciones deben priorizar estrategias de enfriamiento pasivo (sombreado, ventilación) antes de instalar tecnologías de enfriamiento de alta eficiencia que utilicen refrigerantes de bajo GWP.", + "pt": "A cidade promove reformas energéticas em edifícios comerciais e institucionais, como escritórios, centros comerciais, universidades e hotéis. As medidas incluem a modernização dos sistemas HVAC com unidades de fluxo de refrigerante variável (VRF), a substituição de iluminação fluorescente e halógena por LEDs, a implementação de sistemas de automação predial e gestão de energia, e a melhoria do envelope térmico (isolamento, revestimentos refletivos, sombreamento). Adaptações específicas para a região também podem ser necessárias para atender às necessidades de resfriamento e conforto. As reformas geralmente proporcionam períodos de retorno curtos devido à redução dos custos operacionais e ao aumento do conforto dos ocupantes. As reformas devem priorizar estratégias de resfriamento passivo (sombreamento, ventilação) antes da instalação de tecnologias de resfriamento de alta eficiência que utilizem refrigerantes de baixo GWP." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": -1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0017", + "name": { + "en": "Retrofit municipal buildings for energy efficiency", + "es": "Reacondicionar los edificios municipales para mejorar la eficiencia energética", + "pt": "Reformar edifícios municipais para eficiência energética" + }, + "description": { + "en": "The city leads by example through energy retrofits in municipal buildings, including schools, health centers, and administrative offices. Interventions include replacing outdated air conditioners with high-efficiency models, upgrading lighting to LEDs with smart controls, improving building envelopes with reflective roofs and shading, and installing energy management systems for real-time monitoring. Adaptations should reflect regional climate conditions to ensure cost-effective energy savings. By prioritizing its own facilities, the city demonstrates leadership, reduces operating expenses, and showcases practical solutions that can be replicated by the private sector. Retrofits should prioritize passive cooling strategies (shading, ventilation) before installing high-efficiency cooling technologies using low-GWP refrigerants.", + "es": "La ciudad lidera con el ejemplo mediante la modernización energética de edificios municipales, incluyendo escuelas, centros de salud y oficinas administrativas. Las intervenciones incluyen reemplazar aires acondicionados obsoletos por modelos de alta eficiencia, actualizar la iluminación a LEDs con controles inteligentes, mejorar la envolvente de los edificios con techos reflectantes y sombreado, e instalar sistemas de gestión energética para monitoreo en tiempo real. Las adaptaciones deben reflejar las condiciones climáticas regionales para asegurar ahorros energéticos rentables. Al priorizar sus propias instalaciones, la ciudad demuestra liderazgo, reduce los gastos operativos y muestra soluciones prácticas que pueden ser replicadas por el sector privado. Las modernizaciones deben priorizar estrategias de enfriamiento pasivo (sombreado, ventilación) antes de instalar tecnologías de enfriamiento de alta eficiencia que utilicen refrigerantes de bajo GWP.", + "pt": "A cidade lidera pelo exemplo por meio de reformas energéticas em prédios municipais, incluindo escolas, centros de saúde e escritórios administrativos. As intervenções incluem a substituição de aparelhos de ar-condicionado antigos por modelos de alta eficiência, a modernização da iluminação para LEDs com controles inteligentes, a melhoria do envelope dos edifícios com telhados refletivos e sombreamento, e a instalação de sistemas de gestão de energia para monitoramento em tempo real. As adaptações devem refletir as condições climáticas regionais para garantir economia de energia de forma custo-efetiva. Ao priorizar suas próprias instalações, a cidade demonstra liderança, reduz despesas operacionais e apresenta soluções práticas que podem ser replicadas pelo setor privado. As reformas devem priorizar estratégias de resfriamento passivo (sombreamento, ventilação) antes da instalação de tecnologias de resfriamento de alta eficiência utilizando refrigerantes de baixo GWP." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": -1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0018", + "name": { + "en": "Optimize energy efficiency and sustainability standards for existing industrial infrastructure", + "es": "Optimizar la eficiencia energética y los estándares de sostenibilidad para la infraestructura industrial existente", + "pt": "Otimizar a eficiência energética e os padrões de sustentabilidade para a infraestrutura industrial existente" + }, + "description": { + "en": "The city will promote the optimization of energy and environmental performance in existing industrial infrastructure, aiming to maximize efficiency, reduce emissions, and lower operational costs. This action focuses on upgrading equipment, improving process efficiency, and retrofitting industrial facilities to meet higher sustainability standards. Municipal roles may include providing incentives for energy audits and retrofits, facilitating partnerships with industry associations and utilities, and adopting regulations or voluntary standards aligned with national efficiency programs. These measures enhance industrial competitiveness, reduce resource intensity, and contribute to the city’s broader decarbonization and circular economy objectives.", + "es": "La ciudad promoverá la optimización del rendimiento energético y ambiental en la infraestructura industrial existente, con el objetivo de maximizar la eficiencia, reducir las emisiones y disminuir los costos operativos. Esta acción se centra en la modernización de equipos, la mejora de la eficiencia de los procesos y la adaptación de las instalaciones industriales para cumplir con estándares de sostenibilidad más altos. Los roles municipales pueden incluir la provisión de incentivos para auditorías energéticas y modernizaciones, la facilitación de alianzas con asociaciones industriales y empresas de servicios públicos, y la adopción de regulaciones o estándares voluntarios alineados con los programas nacionales de eficiencia. Estas medidas mejoran la competitividad industrial, reducen la intensidad en el uso de recursos y contribuyen a los objetivos más amplios de descarbonización y economía circular de la ciudad.", + "pt": "A cidade promoverá a otimização do desempenho energético e ambiental na infraestrutura industrial existente, visando maximizar a eficiência, reduzir as emissões e diminuir os custos operacionais. Esta ação foca na modernização de equipamentos, melhoria da eficiência dos processos e adaptação das instalações industriais para atender a padrões mais elevados de sustentabilidade. Os papéis municipais podem incluir o fornecimento de incentivos para auditorias energéticas e retrofits, facilitação de parcerias com associações industriais e concessionárias, e adoção de regulamentações ou padrões voluntários alinhados com programas nacionais de eficiência. Essas medidas aumentam a competitividade industrial, reduzem a intensidade do uso de recursos e contribuem para os objetivos mais amplos de descarbonização e economia circular da cidade." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": -1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0023", + "name": { + "en": "Adopt zero-emission bus fleets for public transport", + "es": "Adoptar flotas de autobuses de cero emisiones para el transporte público", + "pt": "Adotar frotas de ônibus de emissão zero para o transporte público" + }, + "description": { + "en": "\"Adopt zero-emission bus fleets for public transport\" mitigation focuses on transitioning public transport fleets to zero-emission buses. According to the HIA, this means that the city or transit operator procures only zero-emission buses (from 2020 onwards). This strategy eliminates tailpipe emissions from traditional buses, improves air quality, and supports a sustainable and resilient urban transport system. Eco-driving training and maintenance programs can be implemented in parallel to maximize efficiency gains and emission reductions during the fleet transition.", + "es": "\"Adoptar flotas de autobuses de cero emisiones para el transporte público\" se centra en la mitigación mediante la transición de las flotas de transporte público a autobuses de cero emisiones. Según la HIA, esto significa que la ciudad o el operador de transporte adquiere únicamente autobuses de cero emisiones (a partir de 2020). Esta estrategia elimina las emisiones de escape de los autobuses tradicionales, mejora la calidad del aire y apoya un sistema de transporte urbano sostenible y resiliente. Se pueden implementar programas de formación en eco-conducción y mantenimiento en paralelo para maximizar las ganancias de eficiencia y la reducción de emisiones durante la transición de la flota.", + "pt": "\"Adotar frotas de ônibus de emissão zero para o transporte público\" é uma ação de mitigação que foca na transição das frotas de transporte público para ônibus de emissão zero. De acordo com o HIA, isso significa que a cidade ou o operador de transporte adquire apenas ônibus de emissão zero (a partir de 2020). Essa estratégia elimina as emissões dos escapamentos dos ônibus tradicionais, melhora a qualidade do ar e apoia um sistema de transporte urbano sustentável e resiliente. Programas de treinamento em eco-condução e manutenção podem ser implementados em paralelo para maximizar os ganhos de eficiência e a redução de emissões durante a transição da frota." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "20-39", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0025", + "name": { + "en": "Promote deployment of zero-emission freight fleets (trucks)", + "es": "Promover el despliegue de flotas de transporte de carga de cero emisiones (camiones)", + "pt": "Promover a implementação de frotas de transporte de carga com emissão zero (caminhões)" + }, + "description": { + "en": "\"Promote deployment of zero-emission freight fleets (trucks)\" mitigation involves adopting cleaner fuels and technologies to reduce the environmental impact of freight transportation. This initiative aims to decrease air pollution, promote sustainability, and improve the overall efficiency of urban logistics. Eco-driving training and maintenance programs can be implemented in parallel to maximize efficiency gains and emission reductions during the fleet transition.", + "es": "Promover el despliegue de flotas de transporte de mercancías de cero emisiones (camiones) implica adoptar combustibles y tecnologías más limpias para reducir el impacto ambiental del transporte de carga. Esta iniciativa tiene como objetivo disminuir la contaminación del aire, promover la sostenibilidad y mejorar la eficiencia general de la logística urbana. Se pueden implementar programas de capacitación en conducción ecológica y mantenimiento en paralelo para maximizar las ganancias de eficiencia y la reducción de emisiones durante la transición de la flota.", + "pt": "Promover a implantação de frotas de transporte de carga com emissão zero (caminhões) envolve a adoção de combustíveis e tecnologias mais limpas para reduzir o impacto ambiental do transporte de cargas. Esta iniciativa visa diminuir a poluição do ar, promover a sustentabilidade e melhorar a eficiência geral da logística urbana. Programas de treinamento em condução ecológica e manutenção podem ser implementados em paralelo para maximizar os ganhos de eficiência e a redução de emissões durante a transição da frota." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "0-19", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0029", + "name": { + "en": "Electrify municipal vehicle fleets", + "es": "Electrificar las flotas de vehículos municipales", + "pt": "Eletrificar as frotas de veículos municipais" + }, + "description": { + "en": "The city transitions its municipal vehicle fleets to electric vehicles, beginning with high-impact segments such as buses and garbage trucks. According to HIA guidance, this aligns with the broader objective of implementing key measures to promote transport electrification. Cities can adopt phased strategies, starting with their own fleets, then expanding through incentives for private sector fleets and gradually scaling as charging infrastructure develops. Emphasis should be placed on equity to ensure low-income areas also benefit from cleaner, quieter transport. Eco-driving training and maintenance programs can be implemented in parallel to maximize efficiency gains and emission reductions during the fleet transition.", + "es": "La ciudad está realizando la transición de sus flotas municipales de vehículos hacia vehículos eléctricos, comenzando por los segmentos de mayor impacto como autobuses y camiones de basura. Según la orientación de HIA, esto se alinea con el objetivo más amplio de implementar medidas clave para promover la electrificación del transporte. Las ciudades pueden adoptar estrategias por fases, comenzando con sus propias flotas y luego expandiéndose mediante incentivos para las flotas del sector privado, escalando gradualmente a medida que se desarrolla la infraestructura de carga. Se debe poner énfasis en la equidad para asegurar que las zonas de bajos ingresos también se beneficien de un transporte más limpio y silencioso. Se pueden implementar programas de capacitación en eco-conducción y mantenimiento en paralelo para maximizar las ganancias de eficiencia y la reducción de emisiones durante la transición de la flota.", + "pt": "A cidade está convertendo suas frotas de veículos municipais para veículos elétricos, começando por segmentos de alto impacto, como ônibus e caminhões de lixo. De acordo com a orientação do HIA, isso está alinhado com o objetivo mais amplo de implementar medidas-chave para promover a eletrificação do transporte. As cidades podem adotar estratégias em fases, começando por suas próprias frotas, depois expandindo por meio de incentivos para frotas do setor privado e aumentando gradualmente à medida que a infraestrutura de recarga se desenvolve. Deve-se dar ênfase à equidade para garantir que áreas de baixa renda também se beneficiem de um transporte mais limpo e silencioso. Programas de treinamento em eco-condução e manutenção podem ser implementados em paralelo para maximizar os ganhos de eficiência e a redução de emissões durante a transição da frota." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "40-59", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0034", + "name": { + "en": "Enact and enforce material bans in order to restrict single use and non-recyclable materials", + "es": "Promulgar y hacer cumplir prohibiciones de materiales para restringir el uso de materiales de un solo uso y no reciclables", + "pt": "Promulgar e aplicar proibições de materiais para restringir o uso de materiais descartáveis e não recicláveis" + }, + "description": { + "en": "Impose restrictions on single-use or non-recyclable materials (e.g., single-use plastics, Styrofoam bans) to reduce environmental impact and promote the use of sustainable alternatives, contributing to waste reduction and overall environmental conservation.", + "es": "Imponer restricciones sobre materiales de un solo uso o no reciclables (por ejemplo, prohibiciones de plásticos de un solo uso, Styrofoam) para reducir el impacto ambiental y promover el uso de alternativas sostenibles, contribuyendo a la reducción de residuos y a la conservación ambiental en general.", + "pt": "Impor restrições ao uso de materiais descartáveis ou não recicláveis (por exemplo, proibição de plásticos de uso único, isopor) para reduzir o impacto ambiental e promover o uso de alternativas sustentáveis, contribuindo para a redução de resíduos e a conservação ambiental como um todo." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "0-19", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0035", + "name": { + "en": "Optmize waste management systems ", + "es": "Optimizar los sistemas de gestión de residuos", + "pt": "Otimizar os sistemas de gestão de resíduos" + }, + "description": { + "en": "Improve the efficiency of waste management systems, throught the development ou actualization of municipal planning or strategies and implementation of alterntives to expand the service coverage to more areas of the municipality, increase energy efficiency, segregated collection, adequate treatment, promote sustainable waste disposal practices, improve the monitoring of regular disposal and waste deposits, reduce resource consumption and minimize environmental impact. ", + "es": "Mejorar la eficiencia de los sistemas de gestión de residuos, mediante el desarrollo o actualización de la planificación o estrategias municipales y la implementación de alternativas para ampliar la cobertura del servicio a más áreas del municipio, aumentar la eficiencia energética, la recolección segregada, el tratamiento adecuado, promover prácticas sostenibles de disposición de residuos, mejorar el monitoreo de la disposición regular y los depósitos de residuos, reducir el consumo de recursos y minimizar el impacto ambiental.", + "pt": "Melhorar a eficiência dos sistemas de gestão de resíduos, por meio do desenvolvimento ou atualização do planejamento ou estratégias municipais e implementação de alternativas para expandir a cobertura do serviço para mais áreas do município, aumentar a eficiência energética, coleta seletiva, tratamento adequado, promover práticas sustentáveis de disposição de resíduos, aprimorar o monitoramento do descarte regular e dos depósitos de resíduos, reduzir o consumo de recursos e minimizar o impacto ambiental." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "0-19", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0036", + "name": { + "en": "Upgrade Landfills to Engineered Sanitary Landfills with Gas Capture.", + "es": "Actualizar los vertederos a rellenos sanitarios diseñados con captura de gases.", + "pt": "Atualizar os aterros para aterros sanitários projetados com captura de gás." + }, + "description": { + "en": "\"Upgrade Landfills to Engineered Sanitary Landfills with Gas Capture.\" strategies focus on responsible and sustainable landfill practices to minimize environmental degradation. By adopting effective management techniques, cities aim to reduce the ecological footprint associated with landfill sites and encourage waste reduction.", + "es": "\"Actualizar los vertederos a vertederos sanitarios diseñados con captura de gases.\" Las estrategias se centran en prácticas responsables y sostenibles de gestión de vertederos para minimizar la degradación ambiental. Al adoptar técnicas de gestión eficaces, las ciudades buscan reducir la huella ecológica asociada a los vertederos y fomentar la reducción de residuos.", + "pt": "\"Atualizar Aterros para Aterros Sanitários Engenheirados com Captura de Gases.\" As estratégias focam em práticas responsáveis e sustentáveis de manejo de aterros para minimizar a degradação ambiental. Ao adotar técnicas de gestão eficazes, as cidades buscam reduzir a pegada ecológica associada aos aterros e incentivar a redução de resíduos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "0-19", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0037", + "name": { + "en": "Implement residential and business segregated collection of recyclables, organic, and residual waste", + "es": "Implementar la recolección segregada de residuos reciclables, orgánicos y residuales en viviendas y negocios", + "pt": "Implementar a coleta seletiva residencial e comercial de recicláveis, orgânicos e resíduos residuais" + }, + "description": { + "en": "Establish citywide three-bin waste separation systems-recyclables, organic waste, and residual waste, for households and businesses. Municipal governments play a central role by organizing segregated collection, running awareness campaigns, and providing training and engagement programs to ensure residents and businesses adopt correct waste sorting practices. Clear communication, adequate infrastructure, and continuous monitoring make this action scalable and practical for cities of all sizes, improving recycling rates and reducing landfill dependency. Cities should ensure universal coverage, address underserved areas, and monitor illegal dumping to achieve full implementation of segregated collection. Ensure that both dry and organic materials are collected separately, and strengthen recycling cooperatives as part of the system’s implementation.", + "es": "Establecer sistemas de separación de residuos en tres contenedores a nivel ciudad: reciclables, residuos orgánicos y residuos no reciclables, tanto para hogares como para empresas. Los gobiernos municipales desempeñan un papel central al organizar la recolección segregada, realizar campañas de concienciación y ofrecer programas de formación y participación para asegurar que los residentes y las empresas adopten prácticas correctas de separación de residuos. Una comunicación clara, infraestructura adecuada y monitoreo continuo hacen que esta acción sea escalable y práctica para ciudades de todos los tamaños, mejorando las tasas de reciclaje y reduciendo la dependencia de los vertederos. Las ciudades deben garantizar la cobertura universal, atender las áreas desatendidas y monitorear los vertidos ilegales para lograr la implementación total de la recolección segregada. Asegurar que tanto los materiales secos como los orgánicos se recojan por separado y fortalecer las cooperativas de reciclaje como parte de la implementación del sistema.", + "pt": "Estabelecer sistemas de separação de resíduos em três recipientes em toda a cidade — recicláveis, resíduos orgânicos e resíduos residuais — para residências e empresas. Os governos municipais desempenham um papel central ao organizar a coleta segregada, realizar campanhas de conscientização e oferecer programas de treinamento e engajamento para garantir que moradores e empresas adotem práticas corretas de separação de resíduos. Comunicação clara, infraestrutura adequada e monitoramento contínuo tornam essa ação escalável e prática para cidades de todos os tamanhos, melhorando as taxas de reciclagem e reduzindo a dependência de aterros sanitários. As cidades devem garantir cobertura universal, atender áreas desassistidas e monitorar o descarte ilegal para alcançar a implementação total da coleta segregada. Assegure que tanto os materiais secos quanto os orgânicos sejam coletados separadamente e fortaleça as cooperativas de reciclagem como parte da implementação do sistema." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "0-19", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0040", + "name": { + "en": "Implement Volume-Based Collection policy", + "es": "Implementar la política de recolección basada en volumen", + "pt": "Implementar a política de Coleta Baseada em Volume" + }, + "description": { + "en": "Implement volume based collection fees that reward generators that geneerate less waste and impose higher fees on larger generators. This policy should incentivize waste reduction in the cities.", + "es": "Implementar tarifas de recolección basadas en el volumen que recompensen a los generadores que produzcan menos residuos e impongan tarifas más altas a los generadores más grandes. Esta política debería incentivar la reducción de residuos en las ciudades.", + "pt": "Implementar taxas de coleta baseadas no volume, que recompensem os geradores que produzem menos resíduos e imponham taxas mais altas aos grandes geradores. Essa política deve incentivar a redução de resíduos nas cidades." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "0-19", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0042", + "name": { + "en": "Expand urban and peri-urban green spaces", + "es": "Ampliar los espacios verdes urbanos y periurbanos", + "pt": "Expandir os espaços verdes urbanos e periurbanos" + }, + "description": { + "en": "Expand and connect green spaces in cities and surrounding areas. This could include street tree planting, establishing green corridors, and developing pocket or largescale parks. Such efforts have many significant, long-lasting benefits. Increasing green space will enhance carbon sequestration and biodiversity. Green spaces improve climate resilience by providing shade, reducing the urban heat island effect and managing flood water. They also improve wellbeing, health and access to nature, while reducing noise and helping tackle air pollution. By integrating these measures into urban planning, cities can strengthen ecosystem services, improve resilience, and contribute to mitigation targets.", + "es": "Ampliar y conectar los espacios verdes en las ciudades y sus alrededores. Esto puede incluir la plantación de árboles en las calles, el establecimiento de corredores verdes y el desarrollo de parques de bolsillo o de gran escala. Estos esfuerzos tienen muchos beneficios significativos y duraderos. Aumentar los espacios verdes mejorará la captura de carbono y la biodiversidad. Los espacios verdes mejoran la resiliencia climática al proporcionar sombra, reducir el efecto de isla de calor urbana y gestionar el agua de inundaciones. También mejoran el bienestar, la salud y el acceso a la naturaleza, al tiempo que reducen el ruido y ayudan a combatir la contaminación del aire. Al integrar estas medidas en la planificación urbana, las ciudades pueden fortalecer los servicios ecosistémicos, mejorar la resiliencia y contribuir a los objetivos de mitigación.", + "pt": "Expandir e conectar espaços verdes em cidades e áreas circundantes. Isso pode incluir o plantio de árvores nas ruas, a criação de corredores verdes e o desenvolvimento de parques de pequeno ou grande porte. Esses esforços trazem muitos benefícios significativos e duradouros. O aumento de áreas verdes melhora a captura de carbono e a biodiversidade. Espaços verdes aumentam a resiliência climática ao fornecer sombra, reduzir o efeito de ilha de calor urbana e gerenciar a água de enchentes. Eles também promovem o bem-estar, a saúde e o acesso à natureza, além de reduzir o ruído e ajudar a combater a poluição do ar. Ao integrar essas medidas no planejamento urbano, as cidades podem fortalecer os serviços ecossistêmicos, melhorar a resiliência e contribuir para as metas de mitigação." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0046", + "name": { + "en": "Strengthen coastal protection infrastructure", + "es": "Reforzar la infraestructura de protección costera", + "pt": "Reforçar a infraestrutura de proteção costeira" + }, + "description": { + "en": "Strengthen coastal protection infrastructure strategies include the construction of sea walls and protective structures to mitigate the impact of rising sea levels and coastal erosion. This adaptation measure enhances the resilience of coastal areas and protects communities from the impacts of climate change. Crucially, these interventions must be developed through an integrated coastal management framework, prioritizing nature-based solutions where feasible, to avoid negative downstream effects and ensure equitable protection for all vulnerable communities.", + "es": "Fortalecer las estrategias de infraestructura de protección costera incluye la construcción de muros de contención y estructuras protectoras para mitigar el impacto del aumento del nivel del mar y la erosión costera. Esta medida de adaptación mejora la resiliencia de las zonas costeras y protege a las comunidades de los impactos del cambio climático. Es fundamental que estas intervenciones se desarrollen a través de un marco de gestión costera integrada, priorizando soluciones basadas en la naturaleza cuando sea posible, para evitar efectos negativos aguas abajo y garantizar una protección equitativa para todas las comunidades vulnerables.", + "pt": "Reforçar as estratégias de infraestrutura de proteção costeira inclui a construção de muros de contenção e estruturas protetoras para mitigar o impacto do aumento do nível do mar e da erosão costeira. Esta medida de adaptação aumenta a resiliência das áreas costeiras e protege as comunidades dos impactos das mudanças climáticas. É fundamental que essas intervenções sejam desenvolvidas por meio de um quadro integrado de gestão costeira, priorizando soluções baseadas na natureza sempre que possível, para evitar efeitos negativos a jusante e garantir proteção equitativa para todas as comunidades vulneráveis." + }, + "actionType": "adaptation", + "hazards": [ + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": "high", + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": "coastal_marine", + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0048", + "name": { + "en": "Upgrade urban drainage systems", + "es": "Mejorar los sistemas de drenaje urbano", + "pt": "Atualizar os sistemas de drenagem urbana" + }, + "description": { + "en": "\"Upgrade urban drainage systems\" involves eco-engineering solutions to enhance drainage systems, through capacity upgrade and network expansion. This adaptation measure aims to improve urban resilience by minimizing the impact of extreme weather events such as flooding.", + "es": "\"Mejorar los sistemas de drenaje urbano\" implica soluciones de eco-ingeniería para optimizar los sistemas de drenaje, mediante el aumento de su capacidad y la expansión de la red. Esta medida de adaptación tiene como objetivo mejorar la resiliencia urbana al minimizar el impacto de eventos climáticos extremos como las inundaciones.", + "pt": "\"Atualizar sistemas de drenagem urbana\" envolve soluções de ecoengenharia para aprimorar os sistemas de drenagem, por meio do aumento da capacidade e da expansão da rede. Esta medida de adaptação visa melhorar a resiliência urbana, minimizando o impacto de eventos climáticos extremos, como inundações." + }, + "actionType": "adaptation", + "hazards": [ + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0049", + "name": { + "en": "Build and maintain shelters for critical climate hazards", + "es": "Construir y mantener refugios para peligros climáticos críticos", + "pt": "Construir e manter abrigos para riscos climáticos críticos" + }, + "description": { + "en": "\"Build and maintain shelters for critical climate hazards\" involves building and maintaining shelters in high-risk areas to protect residents during extreme weather events such as floods, cyclones, storms, landslides, extreme heat events or other critical climate hazards. Shelters should meet resilient design standards, including wind- and flood-resistant construction, and be strategically located to maximize accessibility for vulnerable populations. Where possible, shelters can serve multipurpose roles as schools or community centers. Clear funding mechanisms and defined responsibilities for operations and maintenance are essential to ensure long-term reliability and effectiveness.", + "es": "\"Construir y mantener refugios para peligros climáticos críticos\" implica construir y mantener refugios en áreas de alto riesgo para proteger a los residentes durante eventos climáticos extremos como inundaciones, ciclones, tormentas, deslizamientos de tierra, olas de calor extremas u otros peligros climáticos críticos. Los refugios deben cumplir con estándares de diseño resiliente, incluyendo construcciones resistentes al viento y a las inundaciones, y estar ubicados estratégicamente para maximizar la accesibilidad de las poblaciones vulnerables. Cuando sea posible, los refugios pueden tener funciones multipropósito como escuelas o centros comunitarios. Mecanismos de financiamiento claros y responsabilidades definidas para la operación y el mantenimiento son esenciales para garantizar la fiabilidad y efectividad a largo plazo.", + "pt": "\"Construir e manter abrigos para riscos climáticos críticos\" envolve construir e manter abrigos em áreas de alto risco para proteger os residentes durante eventos climáticos extremos, como inundações, ciclones, tempestades, deslizamentos de terra, ondas de calor extremo ou outros riscos climáticos críticos. Os abrigos devem atender a padrões de design resiliente, incluindo construção resistente ao vento e à inundação, e estar estrategicamente localizados para maximizar a acessibilidade para populações vulneráveis. Sempre que possível, os abrigos podem ter funções múltiplas, servindo como escolas ou centros comunitários. Mecanismos claros de financiamento e responsabilidades definidas para operação e manutenção são essenciais para garantir a confiabilidade e a eficácia a longo prazo." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "landslides", + "wildfires", + "floods", + "sea-level-rise", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": "coastal_marine", + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0051", + "name": { + "en": "Provide public shading in heat hotspots", + "es": "Proporcionar sombra pública en puntos críticos de calor", + "pt": "Fornecer sombreamento público em pontos críticos de calor" + }, + "description": { + "en": "\"Provide public shading in heat hotspots\" involves the implementation of shade structures in public spaces, such as shade sails and canopies, and drought-tolerant trees, contributing to eco-engineering efforts. This adaptation measure enhances outdoor comfort, reduces heat stress, and promotes sustainable urban design.", + "es": "\"Proporcionar sombra pública en puntos críticos de calor\" implica la instalación de estructuras de sombra en espacios públicos, como toldos y marquesinas, así como árboles tolerantes a la sequía, contribuyendo a los esfuerzos de eco-ingeniería. Esta medida de adaptación mejora la comodidad al aire libre, reduce el estrés térmico y promueve un diseño urbano sostenible.", + "pt": "\"Fornecer sombreamento público em pontos críticos de calor\" envolve a implementação de estruturas de sombra em espaços públicos, como velas de sombra e coberturas, além de árvores tolerantes à seca, contribuindo para esforços de ecoengenharia. Esta medida de adaptação aumenta o conforto ao ar livre, reduz o estresse térmico e promove o design urbano sustentável." + }, + "actionType": "adaptation", + "hazards": [ + "heatwaves" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "high", + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0052", + "name": { + "en": "Deploy cool pavements and cool roofs on heat‑exposed streets and buildings", + "es": "Implementar pavimentos fríos y techos fríos en calles y edificios expuestos al calor", + "pt": "Implantar pavimentos frios e telhados frios em ruas e edifícios expostos ao calor" + }, + "description": { + "en": "Introduce reflective coatings, light-colored materials, permeable surfaces and cool roofs in street paving and buildings to reduce heat absorption and mitigate the urban heat island effect. Municipal governments can pilot these approaches in the most heat-exposed areas, integrate them into routine street upgrades and public building refrofits, and assess cost–benefit outcomes to guide broader implementation. These measures improve thermal comfort, reduce energy demand for cooling, and enhance urban resilience to rising temperatures.", + "es": "Introducir recubrimientos reflectantes, materiales de colores claros, superficies permeables y techos fríos en el pavimento de calles y edificios para reducir la absorción de calor y mitigar el efecto de isla de calor urbana. Los gobiernos municipales pueden probar estos enfoques en las zonas más expuestas al calor, integrarlos en las mejoras rutinarias de calles y en la rehabilitación de edificios públicos, y evaluar los resultados de costo-beneficio para orientar una implementación más amplia. Estas medidas mejoran el confort térmico, reducen la demanda de energía para refrigeración y aumentan la resiliencia urbana frente al aumento de las temperaturas.", + "pt": "Introduza revestimentos reflexivos, materiais de cores claras, superfícies permeáveis e telhados frios no pavimento das ruas e nos edifícios para reduzir a absorção de calor e mitigar o efeito de ilha de calor urbana. Os governos municipais podem testar essas abordagens nas áreas mais expostas ao calor, integrá-las em reformas rotineiras de ruas e retrofit de edifícios públicos, e avaliar os resultados de custo-benefício para orientar uma implementação mais ampla. Essas medidas melhoram o conforto térmico, reduzem a demanda de energia para resfriamento e aumentam a resiliência urbana às temperaturas em elevação." + }, + "actionType": "adaptation", + "hazards": [ + "heatwaves" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "high", + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0053", + "name": { + "en": "Promote water-saving technologies and practices", + "es": "Promover tecnologías y prácticas de ahorro de agua", + "pt": "Promover tecnologias e práticas de economia de água" + }, + "description": { + "en": "Encourages the adoption of water-saving technologies and practices to conserve water resources and strengthen resilience to climate change. This includes measures such as rainwater harvesting, low-flow appliances, leak detection systems, and municipal incentive programs that support households and businesses in reducing consumption. These actions enhance sustainable water use and complement broader eco-engineering and adaptation efforts.", + "es": "Fomenta la adopción de tecnologías y prácticas de ahorro de agua para conservar los recursos hídricos y fortalecer la resiliencia frente al cambio climático. Esto incluye medidas como la captación de agua de lluvia, electrodomésticos de bajo consumo, sistemas de detección de fugas y programas de incentivos municipales que apoyan a hogares y empresas en la reducción del consumo. Estas acciones mejoran el uso sostenible del agua y complementan los esfuerzos más amplios de eco-ingeniería y adaptación.", + "pt": "Incentiva a adoção de tecnologias e práticas de economia de água para conservar os recursos hídricos e fortalecer a resiliência às mudanças climáticas. Isso inclui medidas como a captação de água da chuva, aparelhos de baixo consumo, sistemas de detecção de vazamentos e programas de incentivo municipal que apoiam residências e empresas na redução do consumo. Essas ações promovem o uso sustentável da água e complementam esforços mais amplos de ecoengenharia e adaptação." + }, + "actionType": "adaptation", + "hazards": [ + "droughts" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 2, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": "high", + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": "medium" + }, + "cost": "low", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0056", + "name": { + "en": "Improve Watershed Protection and Management", + "es": "Mejorar la protección y gestión de las cuencas hidrográficas", + "pt": "Melhorar a Proteção e Gestão das Bacias Hidrográficas" + }, + "description": { + "en": "\"Watershed Protection and Management\" involves the protection and conservation of natural watershed areas to safeguard water quality, biodiversity, and ecosystem services, including measures such as preventing pollution and encrouchment. This initiative aims to ensure sustainable water management and resilience to the impacts of climate change.", + "es": "\"La Protección y Gestión de Cuencas\" implica la protección y conservación de las áreas naturales de cuencas para salvaguardar la calidad del agua, la biodiversidad y los servicios ecosistémicos, incluyendo medidas como la prevención de la contaminación y la ocupación indebida. Esta iniciativa tiene como objetivo garantizar una gestión sostenible del agua y la resiliencia frente a los impactos del cambio climático.", + "pt": "“A Proteção e Gestão de Bacias Hidrográficas” envolve a proteção e conservação de áreas naturais de bacias hidrográficas para salvaguardar a qualidade da água, a biodiversidade e os serviços ecossistêmicos, incluindo medidas como a prevenção da poluição e da ocupação irregular. Esta iniciativa visa garantir a gestão sustentável da água e a resiliência aos impactos das mudanças climáticas." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "c40_0062", + "name": { + "en": "Reform water tariffs to support efficiency and equity", + "es": "Reformar las tarifas de agua para promover la eficiencia y la equidad", + "pt": "Reformar as tarifas de água para promover eficiência e equidade" + }, + "description": { + "en": "\"Reform water tariffs to support efficiency and equity\" involve pricing structures for water use, encouraging conservation and efficient use of water resources. This initiative aims to promote responsible water consumption and contribute to sustainable water management.", + "es": "\"Reformar las tarifas del agua para apoyar la eficiencia y la equidad\" implica estructuras de precios para el uso del agua, fomentando la conservación y el uso eficiente de los recursos hídricos. Esta iniciativa tiene como objetivo promover un consumo responsable del agua y contribuir a una gestión sostenible del recurso hídrico.", + "pt": "\"Reformar as tarifas de água para apoiar a eficiência e a equidade\" envolve estruturas de preços para o uso da água, incentivando a conservação e o uso eficiente dos recursos hídricos. Esta iniciativa visa promover o consumo responsável de água e contribuir para a gestão sustentável da água." + }, + "actionType": "adaptation", + "hazards": [ + "droughts" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "c40_0071", + "name": { + "en": "Promote the phase out the reliance on fossil fuels for cooking (in favour of high-efficiency electric cookstoves such as induction stoves).", + "es": "Promover la eliminación progresiva de la dependencia de los combustibles fósiles para cocinar (a favor de cocinas eléctricas de alta eficiencia, como las cocinas de inducción).", + "pt": "Promover a eliminação gradual da dependência de combustíveis fósseis para cozinhar (em favor de fogões elétricos de alta eficiência, como fogões de indução)." + }, + "description": { + "en": "Promote the phase out the reliance on fossil fuels for cooking encourage environmentally friendly cooking practices, including the use of energy-efficient appliances and sustainable cooking methods. This strategy promotes resource conservation and contributes to overall sustainability in food preparation.", + "es": "Promover la eliminación progresiva de la dependencia de los combustibles fósiles para la cocina, fomentando prácticas de cocina respetuosas con el medio ambiente, incluyendo el uso de electrodomésticos energéticamente eficientes y métodos de cocina sostenibles. Esta estrategia promueve la conservación de los recursos y contribuye a la sostenibilidad general en la preparación de alimentos.", + "pt": "Promover a eliminação gradual da dependência de combustíveis fósseis para cozinhar, incentivando práticas de culinária ambientalmente amigáveis, incluindo o uso de aparelhos eficientes em termos de energia e métodos de cozimento sustentáveis. Essa estratégia promove a conservação de recursos e contribui para a sustentabilidade geral na preparação de alimentos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0001", + "name": { + "en": "Improve heat and energy recovery", + "es": "Mejorar la recuperación de calor y energía", + "pt": "Melhorar a recuperação de calor e energia" + }, + "description": { + "en": "Enhanced energy efficiency in industrial processes by recovering heat and energy from waste streams, improving process coupling, and adopting advanced technologies such as coke dry quenching, black liquor gasification, and top pressure recovery turbines. Includes reducing energy use in comminution, paper drying, and other industrial processes through optimized designs, operational improvements, and material efficiency strategies.", + "es": "Mejora de la eficiencia energética en los procesos industriales mediante la recuperación de calor y energía de corrientes de desecho, el mejor acoplamiento de procesos y la adopción de tecnologías avanzadas como el enfriamiento seco de coque, la gasificación de licor negro y las turbinas de recuperación de presión superior. Incluye la reducción del uso de energía en la conminución, el secado de papel y otros procesos industriales a través de diseños optimizados, mejoras operativas y estrategias de eficiencia en el uso de materiales.", + "pt": "Aumento da eficiência energética em processos industriais por meio da recuperação de calor e energia de fluxos de resíduos, melhoria do acoplamento de processos e adoção de tecnologias avançadas como coke dry quenching, black liquor gasification e top pressure recovery turbines. Inclui a redução do uso de energia na cominuição, secagem de papel e outros processos industriais por meio de projetos otimizados, melhorias operacionais e estratégias de eficiência de materiais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0002", + "name": { + "en": "Promote and expand the use of the Brazilian Energy Labeling Program for Buildings", + "es": "Promover y ampliar el uso del Programa Brasileño de Etiquetado Energético para Edificios", + "pt": "Promover e expandir o uso do Programa Brasileiro de Etiquetagem de Edificações" + }, + "description": { + "en": "The city will encourage the adoption and enforcement of the Brazilian Energy Labeling Program for Buildings to improve energy efficiency and reduce emissions from the building sector. The program evaluates and certifies buildings based on their energy performance, covering aspects such as thermal efficiency, lighting, and HVAC systems. Actions may include incentivizing developers and property owners to seek certification, integrating energy performance criteria into municipal building codes, and raising public awareness of the benefits of energy-efficient construction and renovation. ", + "es": "La ciudad fomentará la adopción y aplicación del Programa Brasileño de Etiquetado Energético para Edificios con el fin de mejorar la eficiencia energética y reducir las emisiones del sector de la construcción. El programa evalúa y certifica los edificios según su desempeño energético, abarcando aspectos como la eficiencia térmica, la iluminación y los sistemas HVAC. Las acciones pueden incluir incentivar a desarrolladores y propietarios a buscar la certificación, integrar criterios de desempeño energético en los códigos de edificación municipales y aumentar la concienciación pública sobre los beneficios de la construcción y renovación energéticamente eficiente.", + "pt": "A cidade irá incentivar a adoção e a aplicação do Programa Brasileiro de Etiquetagem de Edificações para melhorar a eficiência energética e reduzir as emissões do setor de edificações. O programa avalia e certifica edifícios com base em seu desempenho energético, abrangendo aspectos como eficiência térmica, iluminação e sistemas de HVAC. As ações podem incluir o incentivo a incorporadores e proprietários de imóveis para buscar a certificação, a integração de critérios de desempenho energético nos códigos de obras municipais e o aumento da conscientização pública sobre os benefícios da construção e renovação energeticamente eficientes." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0006", + "name": { + "en": "Develop integrated renewable energy planning and solar–battery microgrids for rural and peri-urban areas", + "es": "Desarrollar una planificación integrada de energías renovables y microredes solares con baterías para zonas rurales y periurbanas", + "pt": "Desenvolver planejamento integrado de energias renováveis e microgrids solares com baterias para áreas rurais e periurbanas" + }, + "description": { + "en": "The city will promote integrated regional energy planning to ensure that electricity expansion in rural and peri-urban areas is cost-effective, low-emission, and equitable. This approach combines renewable energy generation (e.g., solar PV and wind) with battery storage and microgrid systems to extend reliable access to electricity where traditional grid expansion is unviable or inefficient. Municipalities can partner with energy utilities, rural cooperatives, and neighboring jurisdictions to identify optimal locations for solar–battery microgrids or distributed renewable infrastructure, especially in areas adjoining urban centers where land availability supports clean energy generation for both city and rural users. Financing mechanisms may include public–private artnerships (PPPs), leasing models, concessional loans, and power purchase agreements (PPAs).", + "es": "La ciudad promoverá la planificación energética regional integrada para garantizar que la expansión eléctrica en áreas rurales y periurbanas sea rentable, de bajas emisiones y equitativa. Este enfoque combina la generación de energía renovable (por ejemplo, energía solar fotovoltaica y eólica) con almacenamiento en baterías y sistemas de microrredes para ampliar el acceso confiable a la electricidad donde la expansión tradicional de la red no es viable o resulta ineficiente. Los municipios pueden asociarse con empresas de servicios públicos de energía, cooperativas rurales y jurisdicciones vecinas para identificar ubicaciones óptimas para microrredes solares con baterías o infraestructura renovable distribuida, especialmente en áreas adyacentes a centros urbanos donde la disponibilidad de tierras favorece la generación de energía limpia tanto para usuarios urbanos como rurales. Los mecanismos de financiamiento pueden incluir asociaciones público-privadas (PPP), modelos de arrendamiento, préstamos concesionales y acuerdos de compra de energía (PPA).", + "pt": "A cidade promoverá o planejamento energético regional integrado para garantir que a expansão da eletricidade em áreas rurais e periurbanas seja econômica, de baixa emissão e equitativa. Essa abordagem combina a geração de energia renovável (por exemplo, solar fotovoltaica e eólica) com armazenamento em baterias e sistemas de microrredes para ampliar o acesso confiável à eletricidade onde a expansão tradicional da rede não é viável ou eficiente. Os municípios podem fazer parcerias com concessionárias de energia, cooperativas rurais e jurisdições vizinhas para identificar locais ideais para microrredes solares com baterias ou infraestrutura renovável distribuída, especialmente em áreas próximas a centros urbanos onde a disponibilidade de terra favorece a geração de energia limpa tanto para usuários urbanos quanto rurais. Os mecanismos de financiamento podem incluir parcerias público-privadas (PPPs), modelos de leasing, empréstimos concessionais e contratos de compra de energia (PPAs)." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 1, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0008", + "name": { + "en": "Enable smart grid integration and distributed energy storage through municipal collaboration and demonstration projects", + "es": "Habilitar la integración de redes inteligentes y el almacenamiento de energía distribuida mediante la colaboración municipal y proyectos de demostración", + "pt": "Permitir a integração de redes inteligentes e o armazenamento distribuído de energia por meio de colaboração municipal e projetos de demonstração" + }, + "description": { + "en": "The city will collaborate with energy utilities, regulators, and technology providers to support the deployment of smart grid infrastructure and distributed energy storage systems that enhance flexibility, reliability, and renewable energy integration. While large-scale grid modernization is typically led by national or regional authorities", + "es": "La ciudad colaborará con empresas de servicios energéticos, organismos reguladores y proveedores de tecnología para apoyar el despliegue de infraestructura de redes inteligentes y sistemas de almacenamiento de energía distribuida que mejoren la flexibilidad, la fiabilidad y la integración de energías renovables. Si bien la modernización de la red a gran escala suele estar liderada por autoridades nacionales o regionales", + "pt": "A cidade irá colaborar com concessionárias de energia, órgãos reguladores e fornecedores de tecnologia para apoiar a implantação de infraestrutura de redes inteligentes e sistemas de armazenamento de energia distribuída que aumentem a flexibilidade, a confiabilidade e a integração de energias renováveis. Embora a modernização em larga escala da rede geralmente seja liderada por autoridades nacionais ou regionais" + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0009", + "name": { + "en": "Deploy cogeneration systems in industries", + "es": "Desplegar sistemas de cogeneración en las industrias", + "pt": "Implantar sistemas de cogeração nas indústrias" + }, + "description": { + "en": "Utilize combined heat and power systems to maximize energy efficiency in industrial processes.", + "es": "Utilizar sistemas de cogeneración para maximizar la eficiencia energética en los procesos industriales.", + "pt": "Utilize sistemas de cogeração para maximizar a eficiência energética em processos industriais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": -1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0010", + "name": { + "en": "Promote Net-Zero and Green Building Certifications", + "es": "Promover certificaciones de edificios Net-Zero y verdes", + "pt": "Promover Certificações Net-Zero e de Edifícios Verdes" + }, + "description": { + "en": "This action focuses on promoting sustainable buildings by supporting net-zero energy goals and encouraging green building certifications such as LEED. It aims to incentivize the construction and renovation of buildings that produce as much energy as they consume, reducing their environmental impact. This initiative also fosters the adoption of sustainable practices and technologies, ensuring long-term energy efficiency and environmental responsibility across residential, commercial, and public infrastructure.", + "es": "Esta acción se centra en promover edificios sostenibles apoyando los objetivos de energía neta cero y fomentando certificaciones de construcción ecológica como LEED. Su objetivo es incentivar la construcción y renovación de edificios que produzcan tanta energía como la que consumen, reduciendo su impacto ambiental. Esta iniciativa también impulsa la adopción de prácticas y tecnologías sostenibles, garantizando la eficiencia energética a largo plazo y la responsabilidad ambiental en infraestructuras residenciales, comerciales y públicas.", + "pt": "Esta ação foca na promoção de edifícios sustentáveis, apoiando metas de energia líquida zero e incentivando certificações de construção verde, como o LEED. O objetivo é incentivar a construção e renovação de edifícios que produzam tanta energia quanto consomem, reduzindo seu impacto ambiental. Esta iniciativa também estimula a adoção de práticas e tecnologias sustentáveis, garantindo eficiência energética a longo prazo e responsabilidade ambiental em infraestruturas residenciais, comerciais e públicas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 2, + "housing": 2, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0012", + "name": { + "en": "Expand solar energy generation on municipal facilities and public assets", + "es": "Ampliar la generación de energía solar en instalaciones municipales y bienes públicos", + "pt": "Expandir a geração de energia solar em instalações municipais e bens públicos" + }, + "description": { + "en": "The city will install and scale up solar photovoltaic (PV) systems on municipal buildings and public assets, including schools, health centers, administrative offices, bus terminals, water treatment plants, and decommissioned landfills. The objective is to increase the share of renewable electricity in municipal operations, lower energy costs, and reduce greenhouse gas emissions. Facilitating pilot and demonstration projects in municipal buildings, neighborhoods, or industrial zones to showcase the benefits of smart meters, automated controls, and local storage systems; Supporting demand-side flexibility programs, such as time-of-use tariffs and smart appliance initiatives; Incorporating grid-readiness and distributed generation planning into local development and zoning strategies; and \nEngaging in integrated resource planning with utilities to ensure that urban and peri-urban energy needs are aligned with regional grid upgrades.", + "es": "La ciudad instalará y ampliará sistemas solares fotovoltaicos (PV) en edificios municipales y bienes públicos, incluyendo escuelas, centros de salud, oficinas administrativas, terminales de autobuses, plantas de tratamiento de agua y vertederos clausurados. El objetivo es aumentar la proporción de electricidad renovable en las operaciones municipales, reducir los costos energéticos y disminuir las emisiones de gases de efecto invernadero. Se facilitarán proyectos piloto y de demostración en edificios municipales, barrios o zonas industriales para mostrar los beneficios de los medidores inteligentes, controles automatizados y sistemas de almacenamiento local; se apoyarán programas de flexibilidad en la demanda, como tarifas por horario de uso e iniciativas de electrodomésticos inteligentes; se incorporará la preparación de la red y la planificación de generación distribuida en las estrategias locales de desarrollo y zonificación; y se participará en la planificación integrada de recursos con las empresas de servicios públicos para asegurar que las necesidades energéticas urbanas y periurbanas estén alineadas con las mejoras regionales de la red.", + "pt": "A cidade irá instalar e expandir sistemas solares fotovoltaicos (PV) em prédios municipais e bens públicos, incluindo escolas, centros de saúde, escritórios administrativos, terminais de ônibus, estações de tratamento de água e aterros desativados. O objetivo é aumentar a participação da eletricidade renovável nas operações municipais, reduzir os custos de energia e diminuir as emissões de gases de efeito estufa. Facilitar projetos-piloto e de demonstração em prédios municipais, bairros ou zonas industriais para mostrar os benefícios de medidores inteligentes, controles automatizados e sistemas de armazenamento local; Apoiar programas de flexibilidade do lado da demanda, como tarifas por horário de uso e iniciativas de eletrodomésticos inteligentes; Incorporar o planejamento de prontidão da rede e geração distribuída nas estratégias locais de desenvolvimento e zoneamento; e Engajar-se no planejamento integrado de recursos com concessionárias para garantir que as necessidades energéticas urbanas e periurbanas estejam alinhadas com as atualizações regionais da rede." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0015", + "name": { + "en": "Promote Mini and Micro-Hydropower and Biomass Energy", + "es": "Promover la energía minihidroeléctrica, microhidroeléctrica y de biomasa", + "pt": "Promover a Mini e Micro-Hidroeletricidade e a Energia de Biomassa" + }, + "description": { + "en": "This action focuses on promoting renewable energy generation by developing mini and micro-hydropower plants and encouraging biomass energy production in agricultural regions. By harnessing the potential of local water resources and organic waste, this initiative aims to diversify the energy mix, improve energy security, and support sustainable agricultural practices, reducing dependence on fossil fuels while promoting environmentally friendly energy solutions.", + "es": "Esta acción se centra en promover la generación de energía renovable mediante el desarrollo de plantas mini y microhidroeléctricas y el fomento de la producción de energía a partir de biomasa en regiones agrícolas. Aprovechando el potencial de los recursos hídricos locales y los residuos orgánicos, esta iniciativa busca diversificar la matriz energética, mejorar la seguridad energética y apoyar prácticas agrícolas sostenibles, reduciendo la dependencia de los combustibles fósiles y promoviendo soluciones energéticas respetuosas con el medio ambiente.", + "pt": "Esta ação foca na promoção da geração de energia renovável por meio do desenvolvimento de mini e microcentrais hidrelétricas e do incentivo à produção de energia a partir de biomassa em regiões agrícolas. Ao aproveitar o potencial dos recursos hídricos locais e dos resíduos orgânicos, esta iniciativa visa diversificar a matriz energética, melhorar a segurança energética e apoiar práticas agrícolas sustentáveis, reduzindo a dependência de combustíveis fósseis e promovendo soluções energéticas ambientalmente amigáveis." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": -1, + "habitat": -1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "60-79", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0016", + "name": { + "en": "Promote solar thermal and heat pump systems for water heating in residential, commercial, and public buildings", + "es": "Promover sistemas solares térmicos y bombas de calor para el calentamiento de agua en edificios residenciales, comerciales y públicos", + "pt": "Promover sistemas solares térmicos e bombas de calor para aquecimento de água em edifícios residenciais, comerciais e públicos" + }, + "description": { + "en": "The city will encourage the adoption of renewable and efficient water heating systems, including solar thermal collectors and heat pumps, across residential, commercial, and public facilities. These systems significantly reduce energy consumption and emissions associated with conventional electric or gas water heating. Municipal actions may include: Installing systems in public buildings (schools, hospitals, sports centers) to demonstrate leadership and reduce operational costs; Providing incentives or financing programs for residential and commercial installations; and Updating building codes or efficiency standards to integrate renewable heating technologies in new and retrofitted constructions.", + "es": "La ciudad fomentará la adopción de sistemas de calentamiento de agua renovables y eficientes, incluyendo colectores solares térmicos y bombas de calor, en instalaciones residenciales, comerciales y públicas. Estos sistemas reducen significativamente el consumo de energía y las emisiones asociadas con el calentamiento de agua convencional mediante electricidad o gas. Las acciones municipales pueden incluir: instalar sistemas en edificios públicos (escuelas, hospitales, centros deportivos) para demostrar liderazgo y reducir los costos operativos; ofrecer incentivos o programas de financiamiento para instalaciones residenciales y comerciales; y actualizar los códigos de construcción o los estándares de eficiencia para integrar tecnologías de calentamiento renovable en construcciones nuevas y remodeladas.", + "pt": "A cidade irá incentivar a adoção de sistemas de aquecimento de água renováveis e eficientes, incluindo coletores solares térmicos e bombas de calor, em instalações residenciais, comerciais e públicas. Esses sistemas reduzem significativamente o consumo de energia e as emissões associadas ao aquecimento de água convencional por eletricidade ou gás. As ações municipais podem incluir: Instalação de sistemas em edifícios públicos (escolas, hospitais, centros esportivos) para demonstrar liderança e reduzir custos operacionais; Oferta de incentivos ou programas de financiamento para instalações residenciais e comerciais; e Atualização de códigos de construção ou padrões de eficiência para integrar tecnologias de aquecimento renovável em construções novas e retrofitadas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0023", + "name": { + "en": "Upgrade and maintain electrical substations", + "es": "Actualizar y mantener subestaciones eléctricas", + "pt": "Atualizar e manter subestações elétricas" + }, + "description": { + "en": "Enhance the reliability and efficiency of the electrical grid by modernizing substation equipment and implementing regular maintenance programs.", + "es": "Mejorar la fiabilidad y eficiencia de la red eléctrica mediante la modernización del equipo de subestaciones e implementación de programas regulares de mantenimiento.", + "pt": "Aumentar a confiabilidade e eficiência da rede elétrica modernizando os equipamentos das subestações e implementando programas regulares de manutenção." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "60-79", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0024", + "name": { + "en": "Integrate renewables into municipal water systems", + "es": "Integrar energías renovables en los sistemas municipales de agua", + "pt": "Integrar fontes renováveis nos sistemas municipais de água" + }, + "description": { + "en": "Implement renewable energy sources, such as solar or wind power, to drive water treatment, pumping, and distribution systems, reducing energy costs and emissions.", + "es": "Implementar fuentes de energía renovable, como la solar o la eólica, para impulsar los sistemas de tratamiento, bombeo y distribución de agua, reduciendo los costos energéticos y las emisiones.", + "pt": "Implementar fontes de energia renovável, como energia solar ou eólica, para impulsionar os sistemas de tratamento, bombeamento e distribuição de água, reduzindo os custos de energia e as emissões." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "80-100", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0025", + "name": { + "en": "Promote energy-efficient and climate-resilient housing for low-income and informal settlements", + "es": "Promover viviendas eficientes en energía y resilientes al clima para asentamientos informales y de bajos ingresos", + "pt": "Promover habitações eficientes em energia e resilientes ao clima para assentamentos de baixa renda e informais" + }, + "description": { + "en": "The city will develop and support housing programs that integrate energy-efficient and climate-resilient design principles, reducing energy costs and improving comfort for low-income households and residents of informal settlements. Measures may include the use of thermal insulation materials, reflective roofing, natural ventilation, and efficient lighting and appliances (such as LEDs and solar water heaters). Municipal actions can involve incentivizing retrofits, integrating efficiency criteria into social housing programs, and offering technical assistance or subsidies for small-scale upgrades. This action can be combined with broader improvement projects that address sanitation, water access, and structural safety, fostering integrated and inclusive neighborhood upgrading. These interventions enhance quality of life, reduce energy poverty, and contribute to urban climate mitigation and adaptation goals.", + "es": "La ciudad desarrollará y apoyará programas de vivienda que integren principios de diseño energéticamente eficiente y resiliente al clima, reduciendo los costos de energía y mejorando el confort para los hogares de bajos ingresos y los residentes de asentamientos informales. Las medidas pueden incluir el uso de materiales de aislamiento térmico, techos reflectantes, ventilación natural y sistemas de iluminación y electrodomésticos eficientes (como LEDs y calentadores solares de agua). Las acciones municipales pueden involucrar incentivos para la rehabilitación, la integración de criterios de eficiencia en los programas de vivienda social y la oferta de asistencia técnica o subsidios para mejoras a pequeña escala. Esta acción puede combinarse con proyectos de mejora más amplios que aborden el saneamiento, el acceso al agua y la seguridad estructural, fomentando la mejora integral e inclusiva de los barrios. Estas intervenciones mejoran la calidad de vida, reducen la pobreza energética y contribuyen a los objetivos urbanos de mitigación y adaptación al clima.", + "pt": "A cidade irá desenvolver e apoiar programas habitacionais que integrem princípios de design eficiente em energia e resiliente ao clima, reduzindo os custos de energia e melhorando o conforto para famílias de baixa renda e moradores de assentamentos informais. As medidas podem incluir o uso de materiais de isolamento térmico, telhados refletivos, ventilação natural e iluminação e eletrodomésticos eficientes (como LEDs e aquecedores solares de água). As ações municipais podem envolver o incentivo à requalificação de edificações, a integração de critérios de eficiência em programas de habitação social e a oferta de assistência técnica ou subsídios para pequenas melhorias. Esta ação pode ser combinada com projetos de melhoria mais amplos que abordem saneamento, acesso à água e segurança estrutural, promovendo a requalificação integrada e inclusiva de bairros. Essas intervenções melhoram a qualidade de vida, reduzem a pobreza energética e contribuem para as metas urbanas de mitigação e adaptação às mudanças climáticas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 2, + "housing": 2, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "60-79", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0026", + "name": { + "en": "Implement time-of-use electricity tariffs to enhance demand-side flexibility and efficiency", + "es": "Implementar tarifas eléctricas según el horario de uso para mejorar la flexibilidad y eficiencia del lado de la demanda", + "pt": "Implementar tarifas de eletricidade por horário de uso para aumentar a flexibilidade e eficiência do lado da demanda" + }, + "description": { + "en": "The city will work with energy regulators and utilities to introduce time-of-use (TOU) electricity tariffs that incentivize consumers to shift energy use toward off-peak hours. By encouraging demand-side flexibility, this measure helps to balance grid demand, ensure grid stability, and lower energy costs for consumers, particularly when combined with energy-efficient appliances and smart metering technologies. Municipal roles may include advocating for regulatory approval, piloting TOU programs in public facilities, and raising awareness among residential, commercial, and industrial users. This action supports the city’s broader energy efficiency and resilience objectives, helping to integrate renewable energy more effectively and reduce peak load pressures.", + "es": "La ciudad trabajará con los reguladores energéticos y las empresas de servicios públicos para introducir tarifas eléctricas por horario de uso (TOU) que incentiven a los consumidores a desplazar el consumo de energía hacia las horas de menor demanda. Al fomentar la flexibilidad del lado de la demanda, esta medida ayuda a equilibrar la demanda en la red, garantizar la estabilidad de la red y reducir los costos de energía para los consumidores, especialmente cuando se combina con electrodomésticos eficientes y tecnologías de medición inteligente. Los roles municipales pueden incluir abogar por la aprobación regulatoria, implementar programas piloto de TOU en instalaciones públicas y aumentar la concienciación entre usuarios residenciales, comerciales e industriales. Esta acción respalda los objetivos más amplios de eficiencia energética y resiliencia de la ciudad, ayudando a integrar de manera más efectiva la energía renovable y reducir las presiones de carga máxima.", + "pt": "A cidade trabalhará com reguladores de energia e concessionárias para introduzir tarifas de eletricidade por horário de uso (TOU) que incentivem os consumidores a transferir o consumo de energia para horários fora do pico. Ao estimular a flexibilidade do lado da demanda, essa medida ajuda a equilibrar a demanda na rede, garantir a estabilidade do sistema e reduzir os custos de energia para os consumidores, especialmente quando combinada com aparelhos eficientes em energia e tecnologias de medição inteligente. Os papéis do município podem incluir a defesa da aprovação regulatória, a implementação de programas-piloto de TOU em instalações públicas e a conscientização entre usuários residenciais, comerciais e industriais. Essa ação apoia os objetivos mais amplos da cidade em eficiência energética e resiliência, ajudando a integrar energias renováveis de forma mais eficaz e a reduzir pressões de carga nos horários de pico." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0027", + "name": { + "en": "Create financing programs for local renewable energy projects", + "es": "Crear programas de financiamiento para proyectos locales de energía renovable", + "pt": "Criar programas de financiamento para projetos locais de energia renovável" + }, + "description": { + "en": "Establish funding mechanisms, such as grants and low-interest loans, to support the development of small-scale renewable energy initiatives in communities. These programs can also support community renewable energy farms and cooperatives, enabling shared access to clean power and strengthening local ownership models.", + "es": "Establecer mecanismos de financiación, como subvenciones y préstamos a bajo interés, para apoyar el desarrollo de iniciativas de energía renovable a pequeña escala en las comunidades. Estos programas también pueden apoyar granjas y cooperativas de energía renovable comunitaria, permitiendo el acceso compartido a energía limpia y fortaleciendo los modelos de propiedad local.", + "pt": "Estabelecer mecanismos de financiamento, como subsídios e empréstimos a juros baixos, para apoiar o desenvolvimento de iniciativas de energia renovável em pequena escala nas comunidades. Esses programas também podem apoiar fazendas e cooperativas de energia renovável comunitária, possibilitando o acesso compartilhado à energia limpa e fortalecendo modelos de propriedade local." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 2, + "housing": 2, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "60-79", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0028", + "name": { + "en": "Promote passive cooling through natural shading and ventilation in residential, commercial, and public buildings", + "es": "Promover la refrigeración pasiva mediante sombreado natural y ventilación en edificios residenciales, comerciales y públicos", + "pt": "Promover o resfriamento passivo por meio de sombreamento natural e ventilação em edifícios residenciais, comerciais e públicos" + }, + "description": { + "en": "The city will require or encourage passive cooling design features—including shaded facades, green roofs, natural ventilation, reflective surfaces, and cross-ventilation layouts—to reduce dependence on mechanical air conditioning in residential, commercial, and public buildings. These measures improve indoor comfort, lower energy demand, and enhance urban resilience to heat stress. Implementation can include updating building codes, incentivizing retrofits, and providing design guidance for new developments and renovations. This action complements other green building initiatives and supports long-term climate adaptation through energy efficiency and thermal comfort.", + "es": "La ciudad requerirá o fomentará características de diseño de enfriamiento pasivo, incluyendo fachadas sombreadas, techos verdes, ventilación natural, superficies reflectantes y distribuciones que permitan la ventilación cruzada, para reducir la dependencia del aire acondicionado mecánico en edificios residenciales, comerciales y públicos. Estas medidas mejoran el confort interior, disminuyen la demanda energética y aumentan la resiliencia urbana frente al estrés térmico. La implementación puede incluir la actualización de los códigos de construcción, incentivos para la rehabilitación y la provisión de orientación de diseño para nuevos desarrollos y renovaciones. Esta acción complementa otras iniciativas de construcción sostenible y apoya la adaptación climática a largo plazo mediante la eficiencia energética y el confort térmico.", + "pt": "A cidade exigirá ou incentivará a adoção de elementos de design para resfriamento passivo — incluindo fachadas sombreadas, telhados verdes, ventilação natural, superfícies refletivas e layouts que favoreçam a ventilação cruzada — para reduzir a dependência de ar-condicionado mecânico em edifícios residenciais, comerciais e públicos. Essas medidas melhoram o conforto interno, reduzem a demanda de energia e aumentam a resiliência urbana ao estresse térmico. A implementação pode incluir a atualização dos códigos de construção, o incentivo à modernização de edifícios existentes e a oferta de orientações de design para novos empreendimentos e reformas. Essa ação complementa outras iniciativas de construção sustentável e apoia a adaptação climática de longo prazo por meio da eficiência energética e do conforto térmico." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0031", + "name": { + "en": "Capture & Use Biogas at Wastewater Treatment Plants'", + "es": "Captura y uso de biogás en plantas de tratamiento de aguas residuales", + "pt": "Captura e uso de biogás em estações de tratamento de águas residuais" + }, + "description": { + "en": "Install biogas systems in wastewater treatment facilities to produce renewable energy from organic sludge, reducing emissions and operational costs. Technologies may include sludge digestion, CHP for plant loads, and upgrading to biomethane for vehicles. This action can be financed by development banks and can be scaled by regionalization.", + "es": "Instalar sistemas de biogás en plantas de tratamiento de aguas residuales para producir energía renovable a partir de lodos orgánicos, reduciendo emisiones y costos operativos. Las tecnologías pueden incluir digestión de lodos, cogeneración (CHP) para las cargas de la planta y actualización a biometano para vehículos. Esta acción puede ser financiada por bancos de desarrollo y puede escalarse mediante la regionalización.", + "pt": "Instalar sistemas de biogás em instalações de tratamento de águas residuais para produzir energia renovável a partir de lodo orgânico, reduzindo emissões e custos operacionais. As tecnologias podem incluir digestão de lodo, cogeração (CHP) para cargas da planta e atualização para biometano para veículos. Esta ação pode ser financiada por bancos de desenvolvimento e pode ser ampliada por meio da regionalização." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "60-79", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0033", + "name": { + "en": "Install biodigesters in rural properties", + "es": "Instalar biodigestores en propiedades rurales", + "pt": "Instalar biodigestores em propriedades rurais" + }, + "description": { + "en": "Equip rural farms and properties with biodigesters to convert organic waste into biogas and nutrient-rich fertilizers, providing a sustainable energy source.", + "es": "Equipar las granjas y propiedades rurales con biodigestores para convertir los residuos orgánicos en biogás y fertilizantes ricos en nutrientes, proporcionando una fuente de energía sostenible.", + "pt": "Equipar fazendas e propriedades rurais com biodigestores para converter resíduos orgânicos em biogás e fertilizantes ricos em nutrientes, proporcionando uma fonte de energia sustentável." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0034", + "name": { + "en": "Improve Fuel Supply Systems for Industrial Heating", + "es": "Mejorar los sistemas de suministro de combustible para la calefacción industrial", + "pt": "Melhorar os Sistemas de Abastecimento de Combustível para Aquecimento Industrial" + }, + "description": { + "en": "Enhancing fuel delivery systems in the steel production process by implementing technologies such as pulverized coal injection, improving furnace designs and process controls, and optimizing fuel combustion for heating. Includes energy efficiency measures to reduce emissions from coal and coke used in conventional iron-making, and the potential adoption of alternative reductants like biomass and waste plastics.", + "es": "Mejorar los sistemas de suministro de combustible en el proceso de producción de acero mediante la implementación de tecnologías como la inyección de carbón pulverizado, la mejora de los diseños de hornos y los controles de proceso, y la optimización de la combustión de combustible para calefacción. Incluye medidas de eficiencia energética para reducir las emisiones provenientes del carbón y el coque utilizados en la fabricación convencional de hierro, así como la posible adopción de reductores alternativos como biomasa y plásticos de desecho.", + "pt": "Aprimoramento dos sistemas de fornecimento de combustível no processo de produção de aço por meio da implementação de tecnologias como a injeção de carvão pulverizado, melhoria dos projetos de fornos e dos controles de processo, e otimização da combustão de combustível para aquecimento. Inclui medidas de eficiência energética para reduzir as emissões provenientes do carvão e do coque utilizados na produção convencional de ferro, além da possível adoção de redutores alternativos como biomassa e resíduos plásticos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0035", + "name": { + "en": "Enhance industrial energy efficiency processes", + "es": "Mejorar los procesos de eficiencia energética industrial", + "pt": "Aprimorar os processos de eficiência energética industrial" + }, + "description": { + "en": "Implement advanced technologies and process optimizations in industrial facilities to minimize energy consumption and improve productivity.", + "es": "Implementar tecnologías avanzadas y optimizaciones de procesos en instalaciones industriales para minimizar el consumo de energía y mejorar la productividad.", + "pt": "Implementar tecnologias avançadas e otimizações de processos em instalações industriais para minimizar o consumo de energia e melhorar a produtividade." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": -1, + "habitat": -1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0040", + "name": { + "en": "Deploy energy-efficient and solar-powered street lighting across all neighborhoods", + "es": "Desplegar alumbrado público eficiente en el uso de energía y alimentado por energía solar en todos los vecindarios", + "pt": "Implantar iluminação pública eficiente em termos energéticos e alimentada por energia solar em todos os bairros" + }, + "description": { + "en": "The city will install LED-based (or other low emission technologies), solar-powered streetlights in all neighborhoods, including rural and peri-urban areas, to enhance safety, accessibility, and social inclusion while reducing energy costs and environmental impacts. Where feasible, the action prioritizes solar power generation, especially in areas with limited grid coverage or high carbon intensity. In locations where the electricity grid is already clean, the focus will be on maximizing lighting efficiency through LED retrofits and smart controls. Municipal roles include procuring equipment, establishing public–private financing mechanisms, and contracting long-term maintenance services to ensure system reliability. This action delivers strong co-benefits for communities of all sizes but requires careful planning to address maintenance and operational challenges.", + "es": "La ciudad instalará farolas basadas en tecnología LED (u otras tecnologías de bajas emisiones) alimentadas por energía solar en todos los barrios, incluyendo zonas rurales y periurbanas, para mejorar la seguridad, la accesibilidad y la inclusión social, al tiempo que se reducen los costos energéticos y los impactos ambientales. Cuando sea posible, la acción priorizará la generación de energía solar, especialmente en áreas con cobertura de red limitada o alta intensidad de carbono. En los lugares donde la red eléctrica ya es limpia, el enfoque será maximizar la eficiencia de la iluminación mediante la modernización con LED y controles inteligentes. Las funciones municipales incluyen la adquisición de equipos, el establecimiento de mecanismos de financiación público-privada y la contratación de servicios de mantenimiento a largo plazo para garantizar la fiabilidad del sistema. Esta acción ofrece importantes co-beneficios para comunidades de todos los tamaños, pero requiere una planificación cuidadosa para abordar los desafíos de mantenimiento y operación.", + "pt": "A cidade instalará postes de iluminação pública com tecnologia LED (ou outras tecnologias de baixa emissão), alimentados por energia solar, em todos os bairros, incluindo áreas rurais e periurbanas, para aumentar a segurança, acessibilidade e inclusão social, ao mesmo tempo em que reduz os custos de energia e os impactos ambientais. Sempre que possível, a ação prioriza a geração de energia solar, especialmente em áreas com cobertura limitada da rede elétrica ou alta intensidade de carbono. Nos locais onde a rede elétrica já é limpa, o foco será maximizar a eficiência da iluminação por meio de retrofit com LED e controles inteligentes. As funções municipais incluem a aquisição de equipamentos, o estabelecimento de mecanismos de financiamento público-privado e a contratação de serviços de manutenção de longo prazo para garantir a confiabilidade do sistema. Esta ação oferece fortes co-benefícios para comunidades de todos os tamanhos, mas exige planejamento cuidadoso para enfrentar desafios de manutenção e operação." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0045", + "name": { + "en": "Promote organic, regenerative and agroecological agriculture in rural areas", + "es": "Promover la agricultura orgánica, regenerativa y agroecológica en las zonas rurales", + "pt": "Promover a agricultura orgânica, regenerativa e agroecológica em áreas rurais" + }, + "description": { + "en": "Promote organic, regenerative and agroecological agricultural principles in the rural areas of the city. This can include reducing reliance on chemical pesticides, improving soil health and promoting carbon sequestration in the soil. Actions could include providing technical training and educational programmes for rural producers, using economic instruments to incentivize agroecological conversion, and creating resources or networks for skill sharing. Work cooperatively with rural producers, including engaging with Indigenous practises and skillsets.", + "es": "Promover principios agrícolas orgánicos, regenerativos y agroecológicos en las zonas rurales de la ciudad. Esto puede incluir la reducción de la dependencia de pesticidas químicos, la mejora de la salud del suelo y la promoción de la captura de carbono en el suelo. Las acciones pueden incluir la provisión de capacitación técnica y programas educativos para los productores rurales, el uso de instrumentos económicos para incentivar la conversión agroecológica y la creación de recursos o redes para el intercambio de habilidades. Trabajar de manera cooperativa con los productores rurales, incluyendo la integración de prácticas y conocimientos indígenas.", + "pt": "Promover princípios agrícolas orgânicos, regenerativos e agroecológicos nas áreas rurais da cidade. Isso pode incluir a redução da dependência de pesticidas químicos, a melhoria da saúde do solo e a promoção do sequestro de carbono no solo. As ações podem incluir a oferta de treinamentos técnicos e programas educacionais para produtores rurais, o uso de instrumentos econômicos para incentivar a conversão agroecológica e a criação de recursos ou redes para compartilhamento de habilidades. Trabalhar de forma cooperativa com os produtores rurais, incluindo o engajamento com práticas e conhecimentos indígenas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0049", + "name": { + "en": "Develop regional hubs for renewable energy production", + "es": "Desarrollar centros regionales para la producción de energía renovable", + "pt": "Desenvolver centros regionais para a produção de energia renovável" + }, + "description": { + "en": "Establish strategic centers for large-scale renewable energy generation, supporting local economies and providing reliable, clean energy to surrounding areas.", + "es": "Establecer centros estratégicos para la generación de energía renovable a gran escala, apoyando las economías locales y proporcionando energía limpia y confiable a las áreas circundantes.", + "pt": "Estabelecer centros estratégicos para geração de energia renovável em larga escala, apoiando as economias locais e fornecendo energia limpa e confiável para as áreas ao redor." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0050", + "name": { + "en": "Accelerate the adoption of Agroforestry'", + "es": "Acelerar la adopción de la agroforestería", + "pt": "Acelerar a adoção da Agrofloresta" + }, + "description": { + "en": "Promote agroforestry systems by integrating trees into food cultivation and pasture, increasing biodiversity and carbon sequestration. Agroforestry integrates trees and shrubs with crops and/or livestock to sequester carbon, enhance soil health, reduce soil erosion, improve water quality, and diversify livelihoods. It also offers co-benefits like mitigating regional climates and increasing land productivity while addressing risks like biodiversity and hydrology impacts. Agroforestry systems can include silvopastoral systems, alley cropping, riparian buffer planting. Create financial and technical incentives for integrating agroforestry practices into livestock systems.", + "es": "Promover sistemas agroforestales integrando árboles en el cultivo de alimentos y pastizales, aumentando la biodiversidad y la captura de carbono. La agroforestería integra árboles y arbustos con cultivos y/o ganado para secuestrar carbono, mejorar la salud del suelo, reducir la erosión, mejorar la calidad del agua y diversificar los medios de vida. También ofrece co-beneficios como mitigar los climas regionales y aumentar la productividad de la tierra, al tiempo que aborda riesgos como los impactos en la biodiversidad y la hidrología. Los sistemas agroforestales pueden incluir sistemas silvopastoriles, cultivos en callejones y plantación de barreras ribereñas. Crear incentivos financieros y técnicos para integrar prácticas agroforestales en los sistemas ganaderos.", + "pt": "Promover sistemas agroflorestais integrando árvores ao cultivo de alimentos e pastagens, aumentando a biodiversidade e o sequestro de carbono. A agrofloresta integra árvores e arbustos com culturas e/ou pecuária para sequestrar carbono, melhorar a saúde do solo, reduzir a erosão, melhorar a qualidade da água e diversificar os meios de subsistência. Também oferece co-benefícios como a mitigação de climas regionais e o aumento da produtividade da terra, ao mesmo tempo em que aborda riscos como impactos na biodiversidade e na hidrologia. Os sistemas agroflorestais podem incluir sistemas silvipastoris, cultivo em faixas (alley cropping) e plantio de faixas de proteção ripária. Criar incentivos financeiros e técnicos para integrar práticas agroflorestais em sistemas de pecuária." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "40-59" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0053", + "name": { + "en": "Support cooperatives of voluntary waste collectors to aggregate into small enterprises and expand into organics management", + "es": "Apoyar a las cooperativas de recolectores voluntarios de residuos para que se agrupen en pequeñas empresas y se expandan hacia la gestión de orgánicos", + "pt": "Apoiar cooperativas de catadores voluntários de resíduos para se agruparem em pequenas empresas e expandirem para a gestão de orgânicos" + }, + "description": { + "en": "Measures to aggregate voluntary waste collectors into small enterprises or associtations, improve working conditions and income in the processes of sorting recyclable and organic waste to contribute for GHG emissions reduction and the increase climate risk resilience. It includes mapping individual and groups of voluntary waste collectors, provide training for collectors in waste management and treatement technologies, economics, business management, and conceptual planning for the operation and administration of the Sorting Unit.", + "es": "Medidas para agrupar a los recolectores voluntarios de residuos en pequeñas empresas o asociaciones, mejorar las condiciones laborales y los ingresos en los procesos de clasificación de residuos reciclables y orgánicos para contribuir a la reducción de emisiones de GEI y al aumento de la resiliencia frente al riesgo climático. Incluye el mapeo de recolectores voluntarios individuales y en grupo, la provisión de capacitación para los recolectores en gestión y tratamiento de residuos, economía, gestión empresarial y planificación conceptual para la operación y administración de la Unidad de Clasificación.", + "pt": "Medidas para agregar catadores voluntários de resíduos em pequenas empresas ou associações, melhorar as condições de trabalho e a renda nos processos de triagem de resíduos recicláveis e orgânicos para contribuir para a redução das emissões de GEE e o aumento da resiliência ao risco climático. Inclui o mapeamento de catadores voluntários individuais e em grupo, fornecimento de treinamento para catadores em gestão e tecnologias de tratamento de resíduos, economia, gestão de negócios e planejamento conceitual para a operação e administração da Unidade de Triagem." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 2, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "20-39", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0064", + "name": { + "en": "Develop an organic waste management strategy ", + "es": "Desarrollar una estrategia de gestión de residuos orgánicos", + "pt": "Desenvolver uma estratégia de gestão de resíduos orgânicos" + }, + "description": { + "en": "Development of an organic waste management strategy with near, mid and long term interventions, integrating aquisition and implementation of organic waste treatment technologies and resources to build the adequate infrastructure to treat the collected waste, such as composting, biodigestion and other technologies, in order to reduce the amount sent to landfills and to achieve maximum organics waste diversion", + "es": "Desarrollo de una estrategia de gestión de residuos orgánicos con intervenciones a corto, medio y largo plazo, integrando la adquisición e implementación de tecnologías y recursos para el tratamiento de residuos orgánicos, con el fin de construir la infraestructura adecuada para tratar los residuos recolectados, como el compostaje, la biodigestión y otras tecnologías, con el objetivo de reducir la cantidad enviada a los vertederos y lograr la máxima desviación de residuos orgánicos.", + "pt": "Desenvolvimento de uma estratégia de gestão de resíduos orgânicos com intervenções de curto, médio e longo prazo, integrando a aquisição e implementação de tecnologias e recursos para o tratamento de resíduos orgânicos, a fim de construir a infraestrutura adequada para tratar os resíduos coletados, como compostagem, biodigestão e outras tecnologias, visando reduzir a quantidade enviada para aterros sanitários e alcançar o máximo desvio de resíduos orgânicos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "20-39", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0069", + "name": { + "en": "Complete ecological and agroclimatic mapping", + "es": "Completar el mapeo ecológico y agroclimático", + "pt": "Concluir o mapeamento ecológico e agroclimático" + }, + "description": { + "en": "Use zoning and mapping tools to identify areas best suited for sustainable agriculture and those that require environmental preservation. Incorporate findings into planning or zoning regulations, Economic Plans, Climate Action Plans and associated strategic work or policy design. Include mappings of local Indigenous and smallholder-linked land, public spaces, socio-economic data and other priorities. This will help inform plans to accelerate agroecological production locally and preserve ecologically important areas, and can be a useful tool for engaging stakeholders.", + "es": "Utilice herramientas de zonificación y mapeo para identificar las áreas más adecuadas para la agricultura sostenible y aquellas que requieren preservación ambiental. Incorpore los hallazgos en la planificación o regulaciones de zonificación, planes económicos, planes de acción climática y el diseño de políticas o trabajos estratégicos asociados. Incluya mapeos de tierras vinculadas a comunidades indígenas y pequeños productores locales, espacios públicos, datos socioeconómicos y otras prioridades. Esto ayudará a informar los planes para acelerar la producción agroecológica a nivel local y preservar áreas ecológicamente importantes, y puede ser una herramienta útil para involucrar a las partes interesadas.", + "pt": "Utilize ferramentas de zoneamento e mapeamento para identificar áreas mais adequadas para agricultura sustentável e aquelas que requerem preservação ambiental. Incorpore os resultados nos regulamentos de planejamento ou zoneamento, Planos Econômicos, Planos de Ação Climática e trabalhos estratégicos ou elaboração de políticas associadas. Inclua mapeamentos de terras locais ligadas a povos indígenas e pequenos produtores, espaços públicos, dados socioeconômicos e outras prioridades. Isso ajudará a informar planos para acelerar a produção agroecológica localmente e preservar áreas ecologicamente importantes, além de ser uma ferramenta útil para engajar as partes interessadas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Data, Tools & Planning Projects", + "keyImpacts": null + }, + { + "actionId": "icare_0071", + "name": { + "en": "Increase efficiency of industrial furnaces and kilns", + "es": "Aumentar la eficiencia de los hornos y calderas industriales", + "pt": "Aumentar a eficiência de fornos e fornalhas industriais" + }, + "description": { + "en": "Enhancing the design and operation of furnaces and kilns to improve energy efficiency and reduce emissions. Includes technologies such as improved heat and energy recovery from process gases, advanced process controls, and better furnace designs to minimize temperature cycles and optimize fuel usage.", + "es": "Mejorar el diseño y la operación de hornos y calderas para aumentar la eficiencia energética y reducir las emisiones. Incluye tecnologías como la recuperación mejorada de calor y energía de los gases de proceso, controles avanzados de procesos y mejores diseños de hornos para minimizar los ciclos de temperatura y optimizar el uso de combustible.", + "pt": "Aprimorar o design e a operação de fornos e fornalhas para melhorar a eficiência energética e reduzir as emissões. Inclui tecnologias como recuperação aprimorada de calor e energia dos gases do processo, controles avançados de processo e melhores projetos de fornos para minimizar ciclos de temperatura e otimizar o uso de combustível." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "0-19", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0072", + "name": { + "en": "Improve Heat Recovery and Reuse through Heat Exchanger Networks or Heat Pumps", + "es": "Mejorar la recuperación y reutilización de calor mediante redes de intercambiadores de calor o bombas de calor", + "pt": "Melhorar a Recuperação e Reutilização de Calor por meio de Redes de Trocadores de Calor ou Bombas de Calor" + }, + "description": { + "en": "This action involves improving heat-use energy efficiency by utilizing heat exchanger networks and high-temperature heat pumps to recover and reuse waste heat in industrial processes. Techniques include reducing heat needs via thermal insulation, reusing waste heat at various temperature grades, and recycling waste heat for power generation through technologies such as mechanical vapor recompression and thermoelectric conversion.", + "es": "Esta acción consiste en mejorar la eficiencia energética en el uso del calor mediante la utilización de redes de intercambiadores de calor y bombas de calor de alta temperatura para recuperar y reutilizar el calor residual en los procesos industriales. Las técnicas incluyen reducir las necesidades de calor mediante aislamiento térmico, reutilizar el calor residual en diferentes rangos de temperatura y reciclar el calor residual para la generación de energía a través de tecnologías como la recomprensión mecánica de vapor y la conversión termoeléctrica.", + "pt": "Esta ação envolve a melhoria da eficiência energética no uso do calor por meio da utilização de redes de trocadores de calor e bombas de calor de alta temperatura para recuperar e reutilizar o calor residual em processos industriais. As técnicas incluem a redução da necessidade de calor por meio de isolamento térmico, a reutilização do calor residual em diferentes faixas de temperatura e a reciclagem do calor residual para geração de energia através de tecnologias como recompressão mecânica de vapor e conversão termoelétrica." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "0-19", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0074", + "name": { + "en": "Adopt industrial energy efficiency technologies", + "es": "Adoptar tecnologías de eficiencia energética industrial", + "pt": "Adotar tecnologias de eficiência energética industrial" + }, + "description": { + "en": "Implementation of energy-efficient technologies in mining processes, particularly in comminution, by upgrading ore concentration methods, using efficient grinding and crushing technologies, and optimizing particle size feed. Other opportunities include improving separation, drying, and materials handling processes.", + "es": "Implementación de tecnologías energéticamente eficientes en los procesos mineros, particularmente en la conminución, mediante la modernización de los métodos de concentración de mineral, el uso de tecnologías eficientes de molienda y trituración, y la optimización del tamaño de partícula de alimentación. Otras oportunidades incluyen la mejora de los procesos de separación, secado y manejo de materiales.", + "pt": "Implementação de tecnologias energeticamente eficientes nos processos de mineração, especialmente na cominuição, por meio da modernização dos métodos de concentração de minério, uso de tecnologias eficientes de moagem e britagem, e otimização do tamanho das partículas alimentadas. Outras oportunidades incluem a melhoria dos processos de separação, secagem e manuseio de materiais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "0-19", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0076", + "name": { + "en": "Electrify Industrial Processes (with Renewable Power)", + "es": "Electrificar los procesos industriales (con energía renovable)", + "pt": "Eletrificar Processos Industriais (com Energia Renovável)" + }, + "description": { + "en": "Transitioning steel production processes to electrified methods such as molten oxide electrolysis, advanced direct reduction, and other methods powered by low-carbon electricity to reduce emissions and improve energy efficiency.", + "es": "Transición de los procesos de producción de acero hacia métodos electrificados como la electrólisis de óxidos fundidos, la reducción directa avanzada y otros métodos impulsados por electricidad de bajo carbono para reducir las emisiones y mejorar la eficiencia energética.", + "pt": "Transição dos processos de produção de aço para métodos eletrificados, como eletrólise de óxidos fundidos, redução direta avançada e outros métodos alimentados por eletricidade de baixo carbono para reduzir as emissões e melhorar a eficiência energética." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0078", + "name": { + "en": "Decarbonize industrial feedstocks", + "es": "Descarbonizar las materias primas industriales", + "pt": "Descarbonizar matérias-primas industriais" + }, + "description": { + "en": "Decarbonising feedstocks for industrial processes through Carbon Capture and Storage (CCS), Carbon Capture and Utilisation (CCU), and integration with low-carbon energy sources. This includes capturing carbon from various industrial emissions and reusing or storing it to reduce greenhouse gas emissions. Applications include creating synthetic fuels, chemicals, and materials while using renewable energy or biogenic carbon sources.", + "es": "Descarbonizar las materias primas para los procesos industriales mediante Captura y Almacenamiento de Carbono (CCS), Captura y Utilización de Carbono (CCU) e integración con fuentes de energía de bajas emisiones de carbono. Esto incluye capturar carbono de diversas emisiones industriales y reutilizarlo o almacenarlo para reducir las emisiones de gases de efecto invernadero. Las aplicaciones incluyen la creación de combustibles sintéticos, productos químicos y materiales, utilizando energía renovable o fuentes de carbono biogénico.", + "pt": "Descarbonização de matérias-primas para processos industriais por meio de Captura e Armazenamento de Carbono (CCS), Captura e Utilização de Carbono (CCU) e integração com fontes de energia de baixo carbono. Isso inclui capturar carbono de diversas emissões industriais e reutilizá-lo ou armazená-lo para reduzir as emissões de gases de efeito estufa. As aplicações incluem a criação de combustíveis sintéticos, produtos químicos e materiais, utilizando energia renovável ou fontes de carbono biogênico." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 2, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "0-19", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0079", + "name": { + "en": "Implement carbon capture and utilization (CCU)", + "es": "Implementar la captura y utilización de carbono (CCU)", + "pt": "Implementar captura e utilização de carbono (CCU)" + }, + "description": { + "en": "Capturing CO₂ from industrial processes or combustion gases and reusing it for producing fuels, chemicals, and building materials, reducing emissions from the initial source and substituting new fossil/biogenic feedstocks. Prioritize CCU for residual emissions and for end-uses with robust MRV and, where possible, durable carbon retention; do not displace higher-priority efficiency and material circularity measures.", + "es": "Capturar CO₂ de procesos industriales o gases de combustión y reutilizarlo para producir combustibles, productos químicos y materiales de construcción, reduciendo las emisiones de la fuente inicial y sustituyendo nuevas materias primas fósiles o biogénicas. Priorizar la utilización de CO₂ (CCU) para emisiones residuales y para usos finales con sistemas sólidos de monitoreo, reporte y verificación (MRV) y, cuando sea posible, con retención de carbono duradera; no desplazar medidas de eficiencia y circularidad de materiales de mayor prioridad.", + "pt": "Capturar CO₂ de processos industriais ou gases de combustão e reutilizá-lo para produzir combustíveis, produtos químicos e materiais de construção, reduzindo as emissões na fonte inicial e substituindo novas matérias-primas fósseis/biogênicas. Priorizar o CCU para emissões residuais e para usos finais com MRV robusto e, quando possível, retenção durável de carbono; não substituir medidas de eficiência e circularidade de materiais de maior prioridade." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0082", + "name": { + "en": "Implement carbon capture and storage (CCS)", + "es": "Implementar la captura y almacenamiento de carbono (CCS)", + "pt": "Implementar captura e armazenamento de carbono (CCS)" + }, + "description": { + "en": "Carbon Capture and Storage (CCS) involves capturing CO₂ from industrial processes, energy generation, or the atmosphere and storing it in geological formations for millennia. CCS can enable near-zero or negative emissions when combined with sustainably sourced biofuels or direct air capture. Apply CCS primarily to residual/process emissions (e.g., calcination) after efficiency, circularity, and electrification have been pursued where feasible.", + "es": "La Captura y Almacenamiento de Carbono (CCS) consiste en capturar CO₂ de procesos industriales, generación de energía o de la atmósfera y almacenarlo en formaciones geológicas durante milenios. La CCS puede permitir emisiones casi nulas o negativas cuando se combina con biocombustibles de origen sostenible o captura directa del aire. Aplicar la CCS principalmente a emisiones residuales o de proceso (por ejemplo, calcinación) después de haber implementado medidas de eficiencia, circularidad y electrificación donde sea factible.", + "pt": "A Captura e Armazenamento de Carbono (CCS) envolve capturar CO₂ de processos industriais, geração de energia ou da atmosfera e armazená-lo em formações geológicas por milênios. A CCS pode possibilitar emissões quase zero ou negativas quando combinada com biocombustíveis de origem sustentável ou captura direta do ar. Aplique a CCS principalmente às emissões residuais/de processo (por exemplo, calcinação) após a busca por eficiência, circularidade e eletrificação, quando viável." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0099", + "name": { + "en": "Increase local participation in Agroecological Certification Programmes", + "es": "Aumentar la participación local en los Programas de Certificación Agroecológica", + "pt": "Aumentar a participação local em Programas de Certificação Agroecológica" + }, + "description": { + "en": "Agroecological product certifications confirm products meet sustainability criteria and have low environmental impact. Certifications may help rural producers to understand sustainable practices, improve their use of sustainable practices, and increase demand for their products. Actions include creating a dedicated local programme, starting a partnership with an existing certification programme, or raising awareness of certification options and routes to compliance among local producers.", + "es": "Las certificaciones de productos agroecológicos confirman que los productos cumplen con criterios de sostenibilidad y tienen un bajo impacto ambiental. Las certificaciones pueden ayudar a los productores rurales a comprender las prácticas sostenibles, mejorar su uso de prácticas sostenibles e incrementar la demanda de sus productos. Las acciones incluyen crear un programa local dedicado, iniciar una alianza con un programa de certificación existente o aumentar la concienciación sobre las opciones de certificación y las vías de cumplimiento entre los productores locales.", + "pt": "Certificações de produtos agroecológicos confirmam que os produtos atendem a critérios de sustentabilidade e têm baixo impacto ambiental. As certificações podem ajudar os produtores rurais a compreender práticas sustentáveis, aprimorar o uso dessas práticas e aumentar a demanda por seus produtos. As ações incluem criar um programa local dedicado, iniciar uma parceria com um programa de certificação já existente ou aumentar a conscientização sobre as opções de certificação e caminhos para conformidade entre os produtores locais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0101", + "name": { + "en": "Accelerate the adoption of Zero Emission Agricultural Machinery", + "es": "Acelerar la adopción de maquinaria agrícola de cero emisiones", + "pt": "Acelerar a adoção de Máquinas Agrícolas de Emissão Zero" + }, + "description": { + "en": "Support the transition to zero-emission agricultural machinery, such as tractors and equipment powered by renewable electricity or solar energy. These technologies eliminate greenhouse gas emissions, reduce harmful air pollution and noise, and offer opportunities to modernize and improve agricultural tools and practices. Cities and regions can take multiple actions to accelerate this transition, including:\n- Replacing existing municipal machinery with zero-emission alternatives.\n- Establishing equipment leasing or sharing schemes to increase accessibility.\n- Launching local awareness campaigns through training, education, and communication channels.\n- Creating financial incentive or loan programs to encourage adoption.\n- Partnering with manufacturers and organizing fairs or demonstrations to showcase zero-emission technologies and other sustainable agricultural solutions to local producers.", + "es": "Apoyar la transición hacia maquinaria agrícola de cero emisiones, como tractores y equipos impulsados por electricidad renovable o energía solar. Estas tecnologías eliminan las emisiones de gases de efecto invernadero, reducen la contaminación atmosférica y acústica perjudicial, y ofrecen oportunidades para modernizar y mejorar las herramientas y prácticas agrícolas. Las ciudades y regiones pueden tomar múltiples acciones para acelerar esta transición, incluyendo:\n- Reemplazar la maquinaria municipal existente por alternativas de cero emisiones.\n- Establecer esquemas de arrendamiento o compartición de equipos para aumentar la accesibilidad.\n- Lanzar campañas locales de concienciación a través de formación, educación y canales de comunicación.\n- Crear programas de incentivos financieros o préstamos para fomentar la adopción.\n- Colaborar con fabricantes y organizar ferias o demostraciones para mostrar tecnologías de cero emisiones y otras soluciones agrícolas sostenibles a los productores locales.", + "pt": "Apoiar a transição para máquinas agrícolas de zero emissões, como tratores e equipamentos movidos por eletricidade renovável ou energia solar. Essas tecnologias eliminam as emissões de gases de efeito estufa, reduzem a poluição do ar e o ruído prejudiciais, e oferecem oportunidades para modernizar e aprimorar ferramentas e práticas agrícolas. Cidades e regiões podem tomar diversas ações para acelerar essa transição, incluindo:\n- Substituir as máquinas municipais existentes por alternativas de zero emissões.\n- Estabelecer esquemas de aluguel ou compartilhamento de equipamentos para aumentar a acessibilidade.\n- Lançar campanhas locais de conscientização por meio de treinamentos, educação e canais de comunicação.\n- Criar programas de incentivos financeiros ou empréstimos para incentivar a adoção.\n- Fazer parcerias com fabricantes e organizar feiras ou demonstrações para apresentar tecnologias de zero emissões e outras soluções agrícolas sustentáveis aos produtores locais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "0-19" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0104", + "name": { + "en": "Adopt hybrid renewable energy systems (solar-wind)", + "es": "Adoptar sistemas híbridos de energía renovable (solar-eólica)", + "pt": "Adotar sistemas híbridos de energia renovável (solar-eólica)" + }, + "description": { + "en": "Combine solar and wind energy technologies to create reliable, diversified renewable energy systems suitable for various environmental conditions.", + "es": "Combinar tecnologías de energía solar y eólica para crear sistemas de energía renovable fiables y diversificados, adecuados para diversas condiciones ambientales.", + "pt": "Combine tecnologias de energia solar e eólica para criar sistemas de energia renovável confiáveis e diversificados, adequados para diversas condições ambientais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0105", + "name": { + "en": "Reduce technical losses in energy distribution networks", + "es": "Reducir las pérdidas técnicas en las redes de distribución de energía", + "pt": "Reduzir as perdas técnicas nas redes de distribuição de energia" + }, + "description": { + "en": "Upgrade and maintain electrical infrastructure to minimize energy lost during transmission and distribution, improving overall grid efficiency.", + "es": "Actualizar y mantener la infraestructura eléctrica para minimizar la energía perdida durante la transmisión y distribución, mejorando la eficiencia general de la red.", + "pt": "Atualizar e manter a infraestrutura elétrica para minimizar a perda de energia durante a transmissão e distribuição, melhorando a eficiência geral da rede." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "0-19", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0110", + "name": { + "en": "Regulate Construction and Demolition Waste Management to improve deconstruction, segregation at source, reutilization and recycling", + "es": "Regular la gestión de residuos de construcción y demolición para mejorar la deconstrucción, la segregación en origen, la reutilización y el reciclaje", + "pt": "Regulamentar a Gestão de Resíduos da Construção e Demolição para melhorar a desconstrução, a segregação na origem, a reutilização e a reciclagem" + }, + "description": { + "en": "Establish comprehensive guidelines for the sustainable management of construction and demolition waste (CDW) to promote efficiency, circularity, and environmental responsibility across the construction sector. The action aims to reduce waste generation at the source, encourage selective deconstruction instead of conventional demolition, and foster material segregation, reuse, and recycling.\n\nThese guidelines should define technical standards, responsibilities, and incentives for all stakeholders involved — including contractors, developers, and waste operators — to ensure that valuable materials such as concrete, metals, wood, and aggregates are recovered and reintegrated into new construction cycles. The framework should also establish procedures for safe handling, transportation, and disposal of non-recyclable materials, ensuring compliance with environmental regulations and minimizing landfill use.", + "es": "Establecer directrices integrales para la gestión sostenible de los residuos de construcción y demolición (RCD) con el fin de promover la eficiencia, la circularidad y la responsabilidad ambiental en todo el sector de la construcción. La acción tiene como objetivo reducir la generación de residuos en origen, fomentar la deconstrucción selectiva en lugar de la demolición convencional y promover la segregación, reutilización y reciclaje de materiales.\n\nEstas directrices deben definir estándares técnicos, responsabilidades e incentivos para todas las partes interesadas involucradas —incluidos contratistas, desarrolladores y operadores de residuos— para asegurar que materiales valiosos como hormigón, metales, madera y áridos sean recuperados y reintegrados en nuevos ciclos de construcción. El marco también debe establecer procedimientos para la manipulación, el transporte y la disposición segura de materiales no reciclables, garantizando el cumplimiento de las normativas ambientales y minimizando el uso de vertederos.", + "pt": "Estabelecer diretrizes abrangentes para a gestão sustentável de resíduos de construção e demolição (RCD) a fim de promover eficiência, circularidade e responsabilidade ambiental em todo o setor da construção. A ação visa reduzir a geração de resíduos na origem, incentivar a desconstrução seletiva em vez da demolição convencional e promover a segregação, reutilização e reciclagem de materiais.\n\nEssas diretrizes devem definir padrões técnicos, responsabilidades e incentivos para todas as partes interessadas envolvidas — incluindo empreiteiros, incorporadores e operadores de resíduos — para garantir que materiais valiosos como concreto, metais, madeira e agregados sejam recuperados e reintegrados em novos ciclos de construção. O marco regulatório também deve estabelecer procedimentos para o manuseio, transporte e descarte seguro de materiais não recicláveis, assegurando o cumprimento das normas ambientais e minimizando o uso de aterros sanitários." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "20-39", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0111", + "name": { + "en": "Strengthen Extended Producer Responsibility (EPR) Systems", + "es": "Fortalecer los sistemas de Responsabilidad Extendida del Productor (EPR)", + "pt": "Fortalecer os Sistemas de Responsabilidade Estendida do Produtor (EPR)" + }, + "description": { + "en": "Enhance processes for returning products to the production cycle, encouraging collection, reuse, and recycling.", + "es": "Mejorar los procesos para devolver productos al ciclo de producción, fomentando la recolección, la reutilización y el reciclaje.", + "pt": "Aprimorar os processos de retorno de produtos ao ciclo de produção, incentivando a coleta, o reúso e a reciclagem." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "20-39", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0117", + "name": { + "en": "Improve public transport systems to promote modal shift", + "es": "Mejorar los sistemas de transporte público para promover el cambio modal", + "pt": "Melhorar os sistemas de transporte público para promover a mudança modal" + }, + "description": { + "en": "Implements measures to enhance the coverage, frequency, capacity, speed, reliability, accessibility, resilience, safety, affordability, comfort, and convenience of public transport systems (e.g., buses, BRT, informal transport, intra-city rail). Specific actions include expanding routes, improving service frequency and reliability, integrating ticketing systems, and ensuring universal accessibility. These improvements encourage passengers to shift from private motorized transport to public transport, reducing emissions and supporting more sustainable mobility.", + "es": "Implementa medidas para mejorar la cobertura, frecuencia, capacidad, velocidad, fiabilidad, accesibilidad, resiliencia, seguridad, asequibilidad, comodidad y conveniencia de los sistemas de transporte público (por ejemplo, autobuses, BRT, transporte informal, trenes urbanos). Las acciones específicas incluyen la expansión de rutas, la mejora de la frecuencia y fiabilidad del servicio, la integración de sistemas de boletaje y la garantía de accesibilidad universal. Estas mejoras incentivan a los pasajeros a cambiar del transporte motorizado privado al transporte público, reduciendo las emisiones y apoyando una movilidad más sostenible.", + "pt": "Implementa medidas para aumentar a cobertura, frequência, capacidade, velocidade, confiabilidade, acessibilidade, resiliência, segurança, acessibilidade econômica, conforto e conveniência dos sistemas de transporte público (por exemplo, ônibus, BRT, transporte informal, trem intraurbano). As ações específicas incluem a expansão de rotas, melhoria da frequência e confiabilidade do serviço, integração dos sistemas de bilhetagem e garantia de acessibilidade universal. Essas melhorias incentivam os passageiros a migrarem do transporte motorizado privado para o transporte público, reduzindo as emissões e promovendo uma mobilidade mais sustentável." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 2, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "20-39", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0120", + "name": { + "en": "Implement energy efficiency criteria and indicators in the procurement of goods, services, or works by the municipal public administration.", + "es": "Implementar criterios e indicadores de eficiencia energética en la adquisición de bienes, servicios u obras por parte de la administración pública municipal.", + "pt": "Implementar critérios e indicadores de eficiência energética na aquisição de bens, serviços ou obras pela administração pública municipal." + }, + "description": { + "en": "The architectural projects for all renovations and constructions contracted must be designed to minimize the use of artificial lighting and internal cooling, allowing for the use of natural light and cross ventilation. It sould include all energy end-uses in municipal buildings, promote the use of sustainable materials, and adoption of passive design principles.", + "es": "Los proyectos arquitectónicos para todas las renovaciones y construcciones contratadas deben ser diseñados para minimizar el uso de iluminación artificial y enfriamiento interno, permitiendo el uso de luz natural y ventilación cruzada. Deben incluir todos los usos finales de energía en los edificios municipales, promover el uso de materiales sostenibles y la adopción de principios de diseño pasivo.", + "pt": "Os projetos arquitetônicos para todas as reformas e construções contratadas devem ser elaborados para minimizar o uso de iluminação artificial e resfriamento interno, permitindo o aproveitamento da luz natural e da ventilação cruzada. Devem incluir todos os usos finais de energia em edifícios municipais, promover o uso de materiais sustentáveis e a adoção de princípios de design passivo." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0121", + "name": { + "en": "Incentive to create bike-sharing programs in urban areas, with a focus on electric bikes.", + "es": "Incentivo para crear programas de bicicletas compartidas en áreas urbanas, con un enfoque en bicicletas eléctricas.", + "pt": "Incentivo à criação de programas de compartilhamento de bicicletas em áreas urbanas, com foco em bicicletas elétricas." + }, + "description": { + "en": "This action encourages the establishment of bike-sharing systems in cities, specifically promoting the use of electric bicycles. These systems allow residents to rent electric bikes for short trips, reducing the dependence on cars for urban transportation. By integrating electric bikes, cities can further reduce greenhouse gas emissions, alleviate traffic congestion, and promote a healthier and more sustainable mode of transportation for both urban and rural areas. This initiative also supports mobility equality, as it makes bikes more accessible to a wider range of people.", + "es": "Esta acción fomenta el establecimiento de sistemas de bicicletas compartidas en las ciudades, promoviendo específicamente el uso de bicicletas eléctricas. Estos sistemas permiten a los residentes alquilar bicicletas eléctricas para trayectos cortos, reduciendo la dependencia de los automóviles para el transporte urbano. Al integrar bicicletas eléctricas, las ciudades pueden reducir aún más las emisiones de gases de efecto invernadero, aliviar la congestión del tráfico y promover un modo de transporte más saludable y sostenible tanto para áreas urbanas como rurales. Esta iniciativa también apoya la igualdad en la movilidad, ya que hace que las bicicletas sean más accesibles para un mayor número de personas.", + "pt": "Esta ação incentiva o estabelecimento de sistemas de compartilhamento de bicicletas nas cidades, promovendo especificamente o uso de bicicletas elétricas. Esses sistemas permitem que os moradores aluguem bicicletas elétricas para trajetos curtos, reduzindo a dependência de carros para o transporte urbano. Ao integrar bicicletas elétricas, as cidades podem reduzir ainda mais as emissões de gases de efeito estufa, aliviar a congestão do trânsito e promover um modo de transporte mais saudável e sustentável tanto para áreas urbanas quanto rurais. Esta iniciativa também apoia a igualdade de mobilidade, tornando as bicicletas mais acessíveis para um público mais amplo." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 2, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "20-39", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0122", + "name": { + "en": "Establish eco-parks.", + "es": "Establecer eco-parques.", + "pt": "Estabelecer eco-parques." + }, + "description": { + "en": "An eco-park is a facility for the mechanical and biological treatment of urban solid waste, integrating different technologies for the segregation and treatment of various fractions within the waste. This treatment aims to maximize the recovery of dry and organic waste and reduce the volume of waste to be sent for final disposal in landfills, using technologies such as energy generation, composting, recycling recovery, proper disposal of residual waste, and other existing treatment methods available in the market. By integrating these processes , eco-parks operate as multi-technology hubs for waste management, fostering synergies between waste reduction, energy recovery, and environmental protection for the cities. They also contribute to green job creation, climate change mitigation, and urban sustainability.", + "es": "Un eco-parque es una instalación para el tratamiento mecánico y biológico de residuos sólidos urbanos, que integra diferentes tecnologías para la segregación y tratamiento de varias fracciones dentro de los residuos. Este tratamiento tiene como objetivo maximizar la recuperación de residuos secos y orgánicos y reducir el volumen de residuos que se envían a disposición final en vertederos, utilizando tecnologías como la generación de energía, el compostaje, la recuperación de materiales reciclables, la disposición adecuada de residuos residuales y otros métodos de tratamiento existentes en el mercado. Al integrar estos procesos, los eco-parques operan como centros multi-tecnológicos para la gestión de residuos, fomentando sinergias entre la reducción de residuos, la recuperación de energía y la protección ambiental para las ciudades. También contribuyen a la creación de empleos verdes, la mitigación del cambio climático y la sostenibilidad urbana.", + "pt": "Um eco-parque é uma instalação para o tratamento mecânico e biológico de resíduos sólidos urbanos, integrando diferentes tecnologias para a segregação e tratamento de várias frações dentro dos resíduos. Esse tratamento visa maximizar a recuperação de resíduos secos e orgânicos e reduzir o volume de resíduos a serem enviados para disposição final em aterros sanitários, utilizando tecnologias como geração de energia, compostagem, recuperação para reciclagem, destinação adequada dos resíduos residuais e outros métodos de tratamento existentes no mercado. Ao integrar esses processos, os eco-parques operam como polos multi-tecnológicos para a gestão de resíduos, promovendo sinergias entre a redução de resíduos, recuperação de energia e proteção ambiental para as cidades. Eles também contribuem para a criação de empregos verdes, mitigação das mudanças climáticas e sustentabilidade urbana." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "waste" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 2, + "cost_of_living": 0, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": "20-39", + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0127", + "name": { + "en": "Improve Accelerate Environmental Regularization of Rural Properties", + "es": "Mejorar y acelerar la regularización ambiental de las propiedades rurales", + "pt": "Aprimorar e Acelerar a Regularização Ambiental de Propriedades Rurais" + }, + "description": { + "en": "Implement programs to register properties in the Rural Environmental Registry (CAR) and adhere to environmental restoration commitments.", + "es": "Implementar programas para registrar propiedades en el Registro Ambiental Rural (CAR) y cumplir con los compromisos de restauración ambiental.", + "pt": "Implementar programas para registrar propriedades no Cadastro Ambiental Rural (CAR) e aderir aos compromissos de restauração ambiental." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0128", + "name": { + "en": "Establish Municipal Programs for Payment for Environmental Services and other ecological financial incentives", + "es": "Establecer programas municipales de pago por servicios ambientales y otros incentivos financieros ecológicos", + "pt": "Estabelecer Programas Municipais de Pagamento por Serviços Ambientais e outros incentivos financeiros ecológicos" + }, + "description": { + "en": "Financial incentives such as loans, taxes, grants and rebates can be effective ways to promote ecological conservation and more sustainable practices. Municipalities can initiate schemes or help implement regional or national programmes. Payment for Environmental Services involves paying landowners for maintaining or improving environmental conditions on their properties.", + "es": "Los incentivos financieros como préstamos, impuestos, subvenciones y reembolsos pueden ser formas efectivas de promover la conservación ecológica y prácticas más sostenibles. Los municipios pueden iniciar esquemas o ayudar a implementar programas regionales o nacionales. El Pago por Servicios Ambientales implica pagar a los propietarios de tierras por mantener o mejorar las condiciones ambientales en sus propiedades.", + "pt": "Incentivos financeiros, como empréstimos, impostos, subsídios e reembolsos, podem ser formas eficazes de promover a conservação ecológica e práticas mais sustentáveis. Os municípios podem iniciar esquemas ou ajudar a implementar programas regionais ou nacionais. Pagamento por Serviços Ambientais envolve pagar proprietários de terras por manterem ou melhorarem as condições ambientais em suas propriedades." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0131", + "name": { + "en": "Prioritize Procurement of Locally Produced Agroecological Products in Public Purchases", + "es": "Priorizar la adquisición de productos agroecológicos de producción local en las compras públicas", + "pt": "Priorizar a aquisição de produtos agroecológicos produzidos localmente nas compras públicas" + }, + "description": { + "en": "Focus on buying sustainable, locally produced food for public institutions. Additional actions could include identifying reliable local suppliers, partnering with producers and allocating funding to wider sustainable procurement programs and establishing monitoring systems to ensure compliance with sustainability goals", + "es": "Centrarse en la compra de alimentos sostenibles y producidos localmente para las instituciones públicas. Acciones adicionales podrían incluir la identificación de proveedores locales confiables, la colaboración con productores y la asignación de fondos a programas más amplios de adquisiciones sostenibles, así como el establecimiento de sistemas de monitoreo para garantizar el cumplimiento de los objetivos de sostenibilidad.", + "pt": "Focar na compra de alimentos sustentáveis e produzidos localmente para instituições públicas. Ações adicionais podem incluir a identificação de fornecedores locais confiáveis, parcerias com produtores e alocação de recursos para programas mais amplos de compras sustentáveis, além do estabelecimento de sistemas de monitoramento para garantir o cumprimento das metas de sustentabilidade." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0132", + "name": { + "en": "Encourage Local Agroecological Production and Short Supply Chains", + "es": "Fomentar la producción agroecológica local y las cadenas de suministro cortas", + "pt": "Incentivar a produção agroecológica local e cadeias curtas de abastecimento" + }, + "description": { + "en": "Support local, sustainable agricultural practices and reduce emissions associated with food transport. Actions could include incentives for local food distribution networks, partnerships with producers and investment in infrastructure to support local markets and policies to prioritize low-emission transportation methods. These should be underpinned by other programmes to encourage local sustainable agriculture methods.", + "es": "Apoyar prácticas agrícolas locales y sostenibles y reducir las emisiones asociadas al transporte de alimentos. Las acciones pueden incluir incentivos para redes locales de distribución de alimentos, asociaciones con productores e inversión en infraestructura para apoyar los mercados locales y políticas que prioricen métodos de transporte de bajas emisiones. Estas acciones deben estar respaldadas por otros programas que fomenten métodos de agricultura sostenible local.", + "pt": "Apoiar práticas agrícolas locais e sustentáveis e reduzir as emissões associadas ao transporte de alimentos. As ações podem incluir incentivos para redes locais de distribuição de alimentos, parcerias com produtores e investimento em infraestrutura para apoiar mercados locais e políticas que priorizem métodos de transporte de baixa emissão. Essas medidas devem ser complementadas por outros programas que incentivem métodos locais de agricultura sustentável." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0137", + "name": { + "en": "Replace Inefficient Lighting with LED Technology in Public Spaces", + "es": "Reemplazar la iluminación ineficiente por tecnología LED en espacios públicos", + "pt": "Substituir Iluminação Ineficiente por Tecnologia LED em Espaços Públicos" + }, + "description": { + "en": "This action focuses on replacing outdated and inefficient lighting systems in public spaces with energy-efficient LED technology. The objective is to enhance energy efficiency, reduce operational costs, and lower carbon emissions, contributing to a more sustainable and environmentally-friendly municipal infrastructure.", + "es": "Esta acción se centra en reemplazar los sistemas de iluminación obsoletos e ineficientes en los espacios públicos por tecnología LED de bajo consumo energético. El objetivo es mejorar la eficiencia energética, reducir los costos operativos y disminuir las emisiones de carbono, contribuyendo a una infraestructura municipal más sostenible y respetuosa con el medio ambiente.", + "pt": "Esta ação foca na substituição de sistemas de iluminação antigos e ineficientes em espaços públicos por tecnologia LED eficiente em termos energéticos. O objetivo é aumentar a eficiência energética, reduzir os custos operacionais e diminuir as emissões de carbono, contribuindo para uma infraestrutura municipal mais sustentável e ambientalmente amigável." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0139", + "name": { + "en": "Implement congestion pricing and restrictions on high-polluting vehicles", + "es": "Implementar tarifas de congestión y restricciones a los vehículos altamente contaminantes", + "pt": "Implementar cobrança de pedágio urbano e restrições a veículos altamente poluentes" + }, + "description": { + "en": "The city introduces congestion pricing and related restrictions (such as tolls, charges, or bans) on high-polluting vehicles that cover significant parts of the city. To ensure equity and social acceptance, design measures may include exemptions or discounts for low-income drivers, reinvestment of revenues into public transport and active mobility, and strong communication campaigns. While congestion pricing can deliver major emission reductions, it requires substantial governance capacity and is best suited for larger metropolitan areas.", + "es": "La ciudad introduce un sistema de tarificación por congestión y restricciones relacionadas (como peajes, cargos o prohibiciones) para vehículos altamente contaminantes que cubren partes significativas de la ciudad. Para garantizar la equidad y la aceptación social, las medidas de diseño pueden incluir exenciones o descuentos para conductores de bajos ingresos, reinversión de los ingresos en el transporte público y la movilidad activa, y campañas de comunicación sólidas. Si bien la tarificación por congestión puede lograr reducciones importantes de emisiones, requiere una capacidad de gobernanza sustancial y es más adecuada para áreas metropolitanas grandes.", + "pt": "A cidade introduz a cobrança de pedágio urbano e restrições relacionadas (como taxas, cobranças ou proibições) para veículos altamente poluentes que circulam por áreas significativas da cidade. Para garantir equidade e aceitação social, as medidas de design podem incluir isenções ou descontos para motoristas de baixa renda, reinvestimento das receitas em transporte público e mobilidade ativa, além de fortes campanhas de comunicação. Embora a cobrança de pedágio urbano possa proporcionar grandes reduções de emissões, ela exige uma capacidade substancial de governança e é mais adequada para grandes áreas metropolitanas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 0, + "cost_of_living": -1, + "housing": 0, + "mobility": 2, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "20-39", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0144", + "name": { + "en": "Establish a financial support program for extreme weather events", + "es": "Establecer un programa de apoyo financiero para eventos climáticos extremos", + "pt": "Estabelecer um programa de apoio financeiro para eventos climáticos extremos" + }, + "description": { + "en": "Creation of a program to mitigate the effects of climate tragedies, including financial assistance to affected families, efforts to increase access to affordable hazard insurance, and efforts to secure additional resources for recovery and reconstruction, including partnerships with state and federal government bodies. Recovery and reconstruction measures should include adaptive measures with the emphasis on build back better to withstand future hazards and helping residents retrofit buildings.", + "es": "Creación de un programa para mitigar los efectos de tragedias climáticas, incluyendo asistencia financiera a las familias afectadas, esfuerzos para aumentar el acceso a seguros contra riesgos asequibles y gestiones para asegurar recursos adicionales para la recuperación y reconstrucción, incluyendo alianzas con organismos gubernamentales estatales y federales. Las medidas de recuperación y reconstrucción deben incluir acciones adaptativas con énfasis en reconstruir mejor para resistir futuros riesgos y ayudar a los residentes a adaptar sus edificios.", + "pt": "Criação de um programa para mitigar os efeitos de tragédias climáticas, incluindo assistência financeira às famílias afetadas, esforços para aumentar o acesso a seguros contra riscos a preços acessíveis e iniciativas para garantir recursos adicionais para recuperação e reconstrução, incluindo parcerias com órgãos governamentais estaduais e federais. As medidas de recuperação e reconstrução devem incluir ações adaptativas com ênfase em reconstruir melhor para resistir a riscos futuros e ajudar os moradores a adaptar edificações." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "diseases", + "landslides", + "wildfires", + "floods", + "sea-level-rise", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": -1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": "medium", + "floods": "medium", + "sea-level-rise": "medium", + "landslides": "medium", + "storms": "medium", + "wildfires": "medium", + "diseases": "medium" + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0145", + "name": { + "en": "Strengthen the healthcare system to respond effectively to extreme events", + "es": "Fortalecer el sistema de salud para responder eficazmente a eventos extremos", + "pt": "Fortalecer o sistema de saúde para responder de forma eficaz a eventos extremos" + }, + "description": { + "en": "Improve the infrastructure of healthcare units to assist people who require medical care due to impacts associated with climate risks (climate victims), such as those affected by heat waves or floods, especially in more vulnerable areas. Develop action plans to prepare the healthcare network for extreme climate-related situations.", + "es": "Mejorar la infraestructura de las unidades de salud para asistir a las personas que requieren atención médica debido a impactos asociados con riesgos climáticos (víctimas del clima), como aquellas afectadas por olas de calor o inundaciones, especialmente en las áreas más vulnerables. Desarrollar planes de acción para preparar la red de salud ante situaciones extremas relacionadas con el clima.", + "pt": "Melhorar a infraestrutura das unidades de saúde para atender pessoas que necessitam de cuidados médicos devido a impactos associados a riscos climáticos (vítimas do clima), como aquelas afetadas por ondas de calor ou inundações, especialmente em áreas mais vulneráveis. Desenvolver planos de ação para preparar a rede de saúde para situações extremas relacionadas ao clima." + }, + "actionType": "adaptation", + "hazards": [ + "heatwaves", + "diseases", + "landslides", + "floods", + "storms", + "droughts" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": "high", + "floods": "high", + "sea-level-rise": null, + "landslides": "medium", + "storms": "high", + "wildfires": null, + "diseases": "medium" + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0154", + "name": { + "en": "Clean and unclog drainage channels and install eco-barriers", + "es": "Limpiar y desobstruir los canales de drenaje e instalar eco-barreras", + "pt": "Limpar e desobstruir canais de drenagem e instalar eco-barreiras" + }, + "description": { + "en": "Cleaning and unclogging channels in the city to reduce the risk of flooding caused by extreme rainfall events. Installation of eco-barriers to assist in cleaning efforts and raise awareness about solid waste.", + "es": "Limpieza y desobstrucción de canales en la ciudad para reducir el riesgo de inundaciones causadas por eventos de lluvias extremas. Instalación de eco-barreras para apoyar los esfuerzos de limpieza y sensibilizar sobre los residuos sólidos.", + "pt": "Limpeza e desobstrução de canais na cidade para reduzir o risco de inundações causadas por eventos de chuvas extremas. Instalação de eco-barreiras para auxiliar nos esforços de limpeza e conscientizar sobre resíduos sólidos." + }, + "actionType": "adaptation", + "hazards": [ + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 1, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "medium", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0156", + "name": { + "en": "Improve Implementation of urban gardens", + "es": "Mejorar la implementación de huertos urbanos", + "pt": "Melhorar a implementação de hortas urbanas" + }, + "description": { + "en": "Identify and assess the feasibility of suitable areas for the installation of urban gardens and ensure that the sites chosen meet the expectations of the community.", + "es": "Identificar y evaluar la viabilidad de áreas adecuadas para la instalación de huertos urbanos y asegurar que los sitios elegidos cumplan con las expectativas de la comunidad.", + "pt": "Identificar e avaliar a viabilidade de áreas adequadas para a instalação de hortas urbanas e garantir que os locais escolhidos atendam às expectativas da comunidade." + }, + "actionType": "adaptation", + "hazards": [ + "heatwaves", + "landslides", + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 1, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "high", + "floods": "medium", + "sea-level-rise": null, + "landslides": "low", + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0160", + "name": { + "en": "Establish mechanisms for intersectoral coordination and public participation in climate policy", + "es": "Establecer mecanismos para la coordinación intersectorial y la participación pública en la política climática", + "pt": "Estabelecer mecanismos de coordenação intersetorial e participação pública na política climática" + }, + "description": { + "en": "Establish more mechanisms that enable better intersectoral coordination and public participation in climate policy, including the creation of working groups with neighboring municipalities to discuss a common climate agenda.", + "es": "Establecer más mecanismos que permitan una mejor coordinación intersectorial y la participación pública en la política climática, incluyendo la creación de grupos de trabajo con municipios vecinos para discutir una agenda climática común.", + "pt": "Estabelecer mais mecanismos que possibilitem uma melhor coordenação intersetorial e participação pública na política climática, incluindo a criação de grupos de trabalho com municípios vizinhos para discutir uma agenda climática comum." + }, + "actionType": "adaptation", + "hazards": [ + "storms", + "sea-level-rise", + "wildfires", + "floods", + "landslides", + "diseases", + "heatwaves", + "droughts" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": "medium", + "floods": "low", + "sea-level-rise": "low", + "landslides": "low", + "storms": "low", + "wildfires": "low", + "diseases": "medium" + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0162", + "name": { + "en": "Strengthen programs for control and conservation of protected areas", + "es": "Fortalecer los programas de control y conservación de áreas protegidas", + "pt": "Fortalecer programas de controle e conservação de áreas protegidas" + }, + "description": { + "en": "This action focuses on implementing a series of integrated strategies to enhance environmental conservation and maximize its benefits, such as expanding protected areas, developing management plans for conservation units, and training ecotourism guides to strengthen sustainable tourism.", + "es": "Esta acción se centra en implementar una serie de estrategias integradas para mejorar la conservación ambiental y maximizar sus beneficios, como la ampliación de áreas protegidas, el desarrollo de planes de manejo para unidades de conservación y la capacitación de guías de ecoturismo para fortalecer el turismo sostenible.", + "pt": "Esta ação foca na implementação de uma série de estratégias integradas para aprimorar a conservação ambiental e maximizar seus benefícios, como a ampliação de áreas protegidas, o desenvolvimento de planos de manejo para unidades de conservação e a capacitação de guias de ecoturismo para fortalecer o turismo sustentável." + }, + "actionType": "adaptation", + "hazards": [ + "floods", + "landslides", + "heatwaves", + "diseases" + ], + "sectors": [], + "coBenefits": { + "air_quality": 2, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "medium", + "floods": "high", + "sea-level-rise": null, + "landslides": "high", + "storms": null, + "wildfires": null, + "diseases": "medium" + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0163", + "name": { + "en": "Establish a first‑response firefighting brigade", + "es": "Establecer una brigada de primera respuesta contra incendios", + "pt": "Estabelecer uma brigada de combate a incêndios de primeira resposta" + }, + "description": { + "en": "Creation of a First Response Brigade in rural communities to provide them with training and equipment for fire prevention and firefighting.", + "es": "Creación de una Brigada de Primera Respuesta en comunidades rurales para proporcionarles capacitación y equipo para la prevención y combate de incendios.", + "pt": "Criação de uma Brigada de Primeira Resposta em comunidades rurais para fornecer treinamento e equipamentos para prevenção e combate a incêndios." + }, + "actionType": "adaptation", + "hazards": [ + "wildfires" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 2, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": "medium", + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0164", + "name": { + "en": "Improve Hydrological Monitoring System with Telemetry Stations", + "es": "Mejorar el sistema de monitoreo hidrológico con estaciones de telemetría", + "pt": "Aprimorar o Sistema de Monitoramento Hidrológico com Estações de Telemetria" + }, + "description": { + "en": "Implementation of a hydrological monitoring system with telemetry stations to monitor rainfall, water levels, and meteorological variables in real-time.", + "es": "Implementación de un sistema de monitoreo hidrológico con estaciones de telemetría para monitorear en tiempo real la precipitación, los niveles de agua y las variables meteorológicas.", + "pt": "Implementação de um sistema de monitoramento hidrológico com estações de telemetria para monitorar em tempo real a precipitação, os níveis de água e as variáveis meteorológicas." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "floods", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Data, Tools & Planning Projects", + "keyImpacts": null + }, + { + "actionId": "icare_0165", + "name": { + "en": "Develop an Environmental Education Plan", + "es": "Desarrollar un Plan de Educación Ambiental", + "pt": "Desenvolver um Plano de Educação Ambiental" + }, + "description": { + "en": "Design and implement a comprehensive environmental education plan that fosters climate literacy and awareness across schools, communities, and the media. Municipal governments can organize workshops, awareness campaigns, and nature-based activities such as tree planting to reconnect residents with their environment. The plan should integrate themes of climate change, adaptation, mitigation, and climate justice, with particular attention to youth, women, and vulnerable groups. By embedding equity and inclusion, cities can strengthen long-term engagement and empower communities to take part in climate action.", + "es": "Diseñar e implementar un plan integral de educación ambiental que fomente la alfabetización y la conciencia climática en escuelas, comunidades y medios de comunicación. Los gobiernos municipales pueden organizar talleres, campañas de sensibilización y actividades basadas en la naturaleza, como la plantación de árboles, para reconectar a los residentes con su entorno. El plan debe integrar temas de cambio climático, adaptación, mitigación y justicia climática, con especial atención a la juventud, las mujeres y los grupos vulnerables. Al incorporar la equidad y la inclusión, las ciudades pueden fortalecer el compromiso a largo plazo y empoderar a las comunidades para que participen en la acción climática.", + "pt": "Desenvolver e implementar um plano abrangente de educação ambiental que promova a alfabetização e a conscientização climática em escolas, comunidades e na mídia. Os governos municipais podem organizar oficinas, campanhas de conscientização e atividades baseadas na natureza, como o plantio de árvores, para reconectar os moradores com o meio ambiente. O plano deve integrar temas de mudança climática, adaptação, mitigação e justiça climática, com atenção especial para jovens, mulheres e grupos vulneráveis. Ao incorporar equidade e inclusão, as cidades podem fortalecer o engajamento a longo prazo e capacitar as comunidades a participarem da ação climática." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "diseases", + "landslides", + "floods", + "wildfires", + "sea-level-rise", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": "medium", + "floods": "medium", + "sea-level-rise": "medium", + "landslides": "medium", + "storms": "medium", + "wildfires": "medium", + "diseases": "medium" + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0169", + "name": { + "en": "Establish a Plan for Preparation and Emergency Response Measures in the event of extreme weather events", + "es": "Establecer un Plan de Preparación y Medidas de Respuesta ante Emergencias en caso de eventos climáticos extremos", + "pt": "Estabelecer um Plano de Preparação e Medidas de Resposta a Emergências em caso de eventos climáticos extremos" + }, + "description": { + "en": "This action focuses on preparing the municipality to respond to extreme events, aiming to provide a rapid response that minimizes the impacts on the population.", + "es": "Esta acción se centra en preparar al municipio para responder a eventos extremos, con el objetivo de proporcionar una respuesta rápida que minimice los impactos en la población.", + "pt": "Esta ação foca em preparar o município para responder a eventos extremos, visando fornecer uma resposta rápida que minimize os impactos sobre a população." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "diseases", + "landslides", + "floods", + "wildfires", + "sea-level-rise", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": "medium", + "floods": "high", + "sea-level-rise": "high", + "landslides": "high", + "storms": "high", + "wildfires": "high", + "diseases": "medium" + }, + "cost": "high", + "timeline": "5-10 years", + "biome": "coastal_marine", + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0170", + "name": { + "en": "Build safe housing and implement urban rehabilitation projects for populations living in high-risk areas", + "es": "Construir viviendas seguras e implementar proyectos de rehabilitación urbana para las poblaciones que viven en zonas de alto riesgo", + "pt": "Construir habitações seguras e implementar projetos de reabilitação urbana para populações que vivem em áreas de alto risco" + }, + "description": { + "en": "The priority of this action is to build safe housing and implement urban rehabilitation projects for the population living in areas prone to landslides and flooding, as the housing deficit is one of the main factors related to these threats. This will be implemented through the construction of new housing units in safe locations for family resettlement, and infrastructure upgrades like slope stabilization and improved drainage systems within vulnerable communities.", + "es": "La prioridad de esta acción es construir viviendas seguras e implementar proyectos de rehabilitación urbana para la población que vive en zonas propensas a deslizamientos e inundaciones, ya que el déficit habitacional es uno de los principales factores relacionados con estas amenazas. Esto se llevará a cabo mediante la construcción de nuevas unidades habitacionales en lugares seguros para el reasentamiento de familias, y mejoras en la infraestructura como la estabilización de taludes y la optimización de los sistemas de drenaje dentro de las comunidades vulnerables.", + "pt": "A prioridade desta ação é construir habitações seguras e implementar projetos de reabilitação urbana para a população que vive em áreas propensas a deslizamentos de terra e inundações, já que o déficit habitacional é um dos principais fatores relacionados a essas ameaças. Isso será implementado por meio da construção de novas unidades habitacionais em locais seguros para o reassentamento de famílias e de melhorias de infraestrutura, como estabilização de encostas e aprimoramento dos sistemas de drenagem dentro das comunidades vulneráveis." + }, + "actionType": "adaptation", + "hazards": [ + "storms", + "floods", + "landslides", + "heatwaves" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": -1, + "housing": 2, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "medium", + "floods": "high", + "sea-level-rise": null, + "landslides": "high", + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0171", + "name": { + "en": "Improve the hydrometeorological forecasting, monitoring, and alert system for climate risks", + "es": "Mejorar el sistema de pronóstico, monitoreo y alerta hidrometeorológica para riesgos climáticos", + "pt": "Aprimorar o sistema de previsão, monitoramento e alerta hidrometeorológico para riscos climáticos" + }, + "description": { + "en": "This action aims to expand the procedures related to the existing climate risk forecasting, monitoring, and alert system in the municipality.", + "es": "Esta acción tiene como objetivo ampliar los procedimientos relacionados con el sistema existente de pronóstico, monitoreo y alerta de riesgos climáticos en el municipio.", + "pt": "Esta ação tem como objetivo expandir os procedimentos relacionados ao sistema existente de previsão, monitoramento e alerta de riscos climáticos no município." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "landslides", + "floods", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "low", + "heatwaves": "high", + "floods": "high", + "sea-level-rise": null, + "landslides": "medium", + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Data, Tools & Planning Projects", + "keyImpacts": null + }, + { + "actionId": "icare_0172", + "name": { + "en": "Develop and implement the Municipal Risk Reduction Plan (PMRR) and identify population groups vulnerable to climate risks.", + "es": "Desarrollar e implementar el Plan Municipal de Reducción de Riesgos (PMRR) e identificar los grupos poblacionales vulnerables a los riesgos climáticos.", + "pt": "Desenvolver e implementar o Plano Municipal de Redução de Riscos (PMRR) e identificar grupos populacionais vulneráveis aos riscos climáticos." + }, + "description": { + "en": "This action aims to strengthen the development of the Municipal Risk Reduction Plan (PMRR) in the municipality, as it is a highly relevant tool for managing climate risks, especially river floods and landslides.", + "es": "Esta acción tiene como objetivo fortalecer el desarrollo del Plan Municipal de Reducción de Riesgos (PMRR) en el municipio, ya que es una herramienta de gran relevancia para la gestión de riesgos climáticos, especialmente inundaciones fluviales y deslizamientos de tierra.", + "pt": "Esta ação tem como objetivo fortalecer o desenvolvimento do Plano Municipal de Redução de Riscos (PMRR) no município, pois é uma ferramenta de grande relevância para a gestão de riscos climáticos, especialmente inundações de rios e deslizamentos de terra." + }, + "actionType": "adaptation", + "hazards": [ + "landslides", + "floods", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": "high", + "storms": "medium", + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0173", + "name": { + "en": "Preventive maintenance of drainage systems", + "es": "Mantenimiento preventivo de los sistemas de drenaje", + "pt": "Manutenção preventiva dos sistemas de drenagem" + }, + "description": { + "en": "Regular upkeep and cleaning of urban drainage systems, including storm drains, sewers, and retention basins, to ensure efficient water flow and prevent blockages that can lead to flooding during heavy rainfall events.", + "es": "Mantenimiento regular y limpieza de los sistemas de drenaje urbano, incluyendo alcantarillas pluviales, redes de alcantarillado y estanques de retención, para asegurar un flujo de agua eficiente y prevenir obstrucciones que puedan causar inundaciones durante eventos de lluvias intensas.", + "pt": "Manutenção regular e limpeza dos sistemas de drenagem urbana, incluindo bueiros, esgotos e bacias de retenção, para garantir o fluxo eficiente da água e prevenir obstruções que podem causar inundações durante eventos de chuvas intensas." + }, + "actionType": "adaptation", + "hazards": [ + "floods", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": "medium", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0176", + "name": { + "en": "Develop a Climate Action Plan", + "es": "Desarrollar un Plan de Acción Climática", + "pt": "Desenvolver um Plano de Ação Climática" + }, + "description": { + "en": "A comprehensive plan outlining a city's strategies and actions to mitigate greenhouse gas emissions and adapt to the impacts of climate change which typically includes an assessment of the city's climate risks and vulnerabilities, setting emission reduction targets, and implementation of actions across various sectors such as energy, transportation, waste management, and urban planning.", + "es": "Un plan integral que describe las estrategias y acciones de una ciudad para mitigar las emisiones de gases de efecto invernadero y adaptarse a los impactos del cambio climático, que normalmente incluye una evaluación de los riesgos y vulnerabilidades climáticas de la ciudad, el establecimiento de objetivos de reducción de emisiones y la implementación de acciones en diversos sectores como energía, transporte, gestión de residuos y planificación urbana.", + "pt": "Um plano abrangente que descreve as estratégias e ações de uma cidade para mitigar as emissões de gases de efeito estufa e se adaptar aos impactos das mudanças climáticas, que normalmente inclui uma avaliação dos riscos e vulnerabilidades climáticas da cidade, definição de metas de redução de emissões e implementação de ações em diversos setores, como energia, transporte, gestão de resíduos e planejamento urbano." + }, + "actionType": "adaptation", + "hazards": [ + "storms", + "sea-level-rise", + "wildfires", + "floods", + "landslides", + "diseases", + "heatwaves", + "droughts" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": "medium", + "floods": "medium", + "sea-level-rise": "medium", + "landslides": "medium", + "storms": "medium", + "wildfires": "medium", + "diseases": "medium" + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0178", + "name": { + "en": "Redirect urban development through climate‑risk spatial planning", + "es": "Redirigir el desarrollo urbano mediante la planificación espacial basada en el riesgo climático", + "pt": "Redirecionar o desenvolvimento urbano por meio do planejamento espacial baseado em riscos climáticos" + }, + "description": { + "en": "Mapping of critical flood-prone areas with the aim of revising and harmonizing legislation related to land use, given the intensification of the impacts of extreme weather events.", + "es": "Mapeo de las áreas críticas propensas a inundaciones con el objetivo de revisar y armonizar la legislación relacionada con el uso del suelo, dado el aumento de la intensidad de los impactos de eventos meteorológicos extremos.", + "pt": "Mapeamento de áreas críticas sujeitas a inundações com o objetivo de revisar e harmonizar a legislação relacionada ao uso do solo, diante da intensificação dos impactos de eventos climáticos extremos." + }, + "actionType": "adaptation", + "hazards": [ + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": -2, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "medium", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0180", + "name": { + "en": "Expand urban green-blue networks and corridors", + "es": "Ampliar las redes y corredores verdes-azules urbanos", + "pt": "Expandir redes e corredores verdes-azuis urbanos" + }, + "description": { + "en": "Expand and connect urban green spaces and blue-green infrastructure (BGI) in the public realm. Actions include street tree planting, establishing green corridors/greenways, pocket and large parks, and green-blue features (bioswales, rain gardens, permeable surfaces) to manage stormwater, reduce urban heat, enhance biodiversity, and support carbon sequestration. Embedding these measures in urban planning strengthens ecosystem services, resilience, and livability.", + "es": "Ampliar y conectar los espacios verdes urbanos y la infraestructura azul-verde (BGI) en el ámbito público. Las acciones incluyen la plantación de árboles en las calles, el establecimiento de corredores verdes/vías verdes, parques pequeños y grandes, y elementos verde-azules (bioswales, jardines de lluvia, superficies permeables) para gestionar las aguas pluviales, reducir el calor urbano, mejorar la biodiversidad y apoyar la captura de carbono. Integrar estas medidas en la planificación urbana fortalece los servicios ecosistémicos, la resiliencia y la habitabilidad.", + "pt": "Expandir e conectar espaços verdes urbanos e infraestrutura verde-azul (BGI) no espaço público. As ações incluem o plantio de árvores nas ruas, estabelecimento de corredores/caminhos verdes, parques de pequeno e grande porte e elementos verde-azuis (valas de biossistemas, jardins de chuva, superfícies permeáveis) para gerenciar águas pluviais, reduzir o calor urbano, aumentar a biodiversidade e apoiar a captura de carbono. Incorporar essas medidas no planejamento urbano fortalece os serviços ecossistêmicos, a resiliência e a qualidade de vida." + }, + "actionType": "adaptation", + "hazards": [ + "floods", + "landslides", + "heatwaves" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "medium", + "floods": "high", + "sea-level-rise": null, + "landslides": "medium", + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0181", + "name": { + "en": "Restore in Vulnerable Areas", + "es": "Restaurar en áreas vulnerables", + "pt": "Restaurar em Áreas Vulneráveis" + }, + "description": { + "en": "A comprehensive project addressing the socio-environmental vulnerability of an informal settlement. It includes relocating residents from flood-prone areas, restoring the environment, and providing infrastructure and social services.", + "es": "Un proyecto integral que aborda la vulnerabilidad socioambiental de un asentamiento informal. Incluye la reubicación de los residentes de zonas propensas a inundaciones, la restauración del entorno y la provisión de infraestructura y servicios sociales.", + "pt": "Um projeto abrangente que aborda a vulnerabilidade socioambiental de uma comunidade informal. Inclui a realocação de moradores de áreas sujeitas a inundações, a restauração do meio ambiente e o fornecimento de infraestrutura e serviços sociais." + }, + "actionType": "adaptation", + "hazards": [ + "landslides", + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 2, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": "high", + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0182", + "name": { + "en": "Develop an Urban Afforestation Plan", + "es": "Desarrollar un Plan de Forestación Urbana", + "pt": "Desenvolver um Plano de Aflorestamento Urbano" + }, + "description": { + "en": "This action focuses on expanding green areas in the city through urban afforestation. This includes planting trees in sidewalks, squares, public buildings, and schools, as well as creating ecological parks to revitalize watercourses and/or restore forests.", + "es": "Esta acción se centra en ampliar las áreas verdes en la ciudad mediante la forestación urbana. Esto incluye la plantación de árboles en aceras, plazas, edificios públicos y escuelas, así como la creación de parques ecológicos para revitalizar cursos de agua y/o restaurar bosques.", + "pt": "Esta ação foca na expansão de áreas verdes na cidade por meio da arborização urbana. Isso inclui o plantio de árvores em calçadas, praças, prédios públicos e escolas, além da criação de parques ecológicos para revitalizar cursos d'água e/ou restaurar florestas." + }, + "actionType": "adaptation", + "hazards": [ + "heatwaves" + ], + "sectors": [], + "coBenefits": { + "air_quality": 2, + "water_quality": 1, + "habitat": 2, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "high", + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0183", + "name": { + "en": "Implement Multi-hazard Early Warning Systems (MH-EWS)", + "es": "Implementar Sistemas de Alerta Temprana Multirriesgo (MH-EWS)", + "pt": "Implementar Sistemas de Alerta Precoce Multirriscos (MH-EWS)" + }, + "description": { + "en": "Early Warning systems involve the timely detection and communication of potential climate-related hazards, enabling proactive responses to mitigate risks and enhancing community preparedness. This includes intense rains and landslides, using a network of telemetry stations to monitor rainfall and other weather conditions, with clear trigger thresholds to issue public alerts (sirens/alarms, SMS/cell broadcast, radio/PA) in case of potential flooding or landslides.", + "es": "Los sistemas de alerta temprana implican la detección oportuna y la comunicación de posibles peligros relacionados con el clima, lo que permite respuestas proactivas para mitigar riesgos y mejorar la preparación de la comunidad. Esto incluye lluvias intensas y deslizamientos de tierra, utilizando una red de estaciones de telemetría para monitorear la precipitación y otras condiciones meteorológicas, con umbrales de activación claros para emitir alertas públicas (sirenas/alarmas, SMS/difusión celular, radio/megafonía) en caso de posibles inundaciones o deslizamientos de tierra.", + "pt": "Sistemas de Alerta Precoce envolvem a detecção e comunicação em tempo hábil de potenciais perigos relacionados ao clima, permitindo respostas proativas para mitigar riscos e aumentar a preparação das comunidades. Isso inclui chuvas intensas e deslizamentos de terra, utilizando uma rede de estações de telemetria para monitorar a precipitação e outras condições meteorológicas, com limiares de acionamento claros para emitir alertas públicos (sirenes/alarmes, SMS/cell broadcast, rádio/alto-falante) em caso de possíveis inundações ou deslizamentos de terra." + }, + "actionType": "adaptation", + "hazards": [ + "landslides", + "storms" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": "high", + "storms": "medium", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0184", + "name": { + "en": "Upgrade Slope stabilization and drainage", + "es": "Mejorar la estabilización de taludes y el drenaje", + "pt": "Atualizar a estabilização de encostas e drenagem" + }, + "description": { + "en": "This action involves stabilizing slopes and maintaining or restoring drainage systems in hillside areas. This helps to prevent landslides and erosion, reducing the risk of disasters.", + "es": "Esta acción consiste en estabilizar laderas y mantener o restaurar los sistemas de drenaje en zonas de colinas. Esto ayuda a prevenir deslizamientos de tierra y erosión, reduciendo el riesgo de desastres.", + "pt": "Esta ação envolve estabilizar encostas e manter ou restaurar sistemas de drenagem em áreas de morro. Isso ajuda a prevenir deslizamentos de terra e erosão, reduzindo o risco de desastres." + }, + "actionType": "adaptation", + "hazards": [ + "landslides" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": "medium", + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "icare_0185", + "name": { + "en": "Improve Creation of An Epidemiological Intelligence Center", + "es": "Mejorar la creación de un Centro de Inteligencia Epidemiológica", + "pt": "Melhorar a Criação de um Centro de Inteligência Epidemiológica" + }, + "description": { + "en": "This action focuses on establishing an epidemiological intelligence center to monitor public health indicators and provide accessible information to the population. This helps in making informed decisions and protecting public health, particularly in relation to climate-sensitive diseases.", + "es": "Esta acción se centra en establecer un centro de inteligencia epidemiológica para monitorear los indicadores de salud pública y proporcionar información accesible a la población. Esto ayuda a tomar decisiones informadas y a proteger la salud pública, especialmente en relación con enfermedades sensibles al clima.", + "pt": "Esta ação foca na criação de um centro de inteligência epidemiológica para monitorar indicadores de saúde pública e fornecer informações acessíveis à população. Isso auxilia na tomada de decisões informadas e na proteção da saúde pública, especialmente em relação a doenças sensíveis ao clima." + }, + "actionType": "adaptation", + "hazards": [ + "diseases" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": "medium" + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Data, Tools & Planning Projects", + "keyImpacts": null + }, + { + "actionId": "icare_0186", + "name": { + "en": "Implement integrated coastal zone management", + "es": "Implementar la gestión integrada de zonas costeras", + "pt": "Implementar a gestão integrada da zona costeira" + }, + "description": { + "en": "This action describes the implementation of an integrated coastal zone management plan to promote sustainable development and address the impacts of climate change in coastal areas. It includes measures to mitigate the impacts of sea-level rise and coastal erosion.", + "es": "Esta acción describe la implementación de un plan de gestión integrada de zonas costeras para promover el desarrollo sostenible y abordar los impactos del cambio climático en las áreas costeras. Incluye medidas para mitigar los impactos del aumento del nivel del mar y la erosión costera.", + "pt": "Esta ação descreve a implementação de um plano integrado de gestão da zona costeira para promover o desenvolvimento sustentável e enfrentar os impactos das mudanças climáticas em áreas costeiras. Inclui medidas para mitigar os impactos da elevação do nível do mar e da erosão costeira." + }, + "actionType": "adaptation", + "hazards": [ + "sea-level-rise" + ], + "sectors": [], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "medium", + "floods": "high", + "sea-level-rise": "high", + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": "coastal_marine", + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "icare_0188", + "name": { + "en": "Create an Environmental Health Surveillance Program related to Populations Exposed to Air Pollution, Noise Pollution, Water Pollution, and Soil Pollution.", + "es": "Crear un Programa de Vigilancia de la Salud Ambiental relacionado con Poblaciones Expuestas a la Contaminación del Aire, Contaminación Acústica, Contaminación del Agua y Contaminación del Suelo.", + "pt": "Criar um Programa de Vigilância em Saúde Ambiental relacionado a Populações Expostas à Poluição do Ar, Poluição Sonora, Poluição da Água e Poluição do Solo." + }, + "description": { + "en": "Develop actions aimed at promoting the health of the population exposed to environmental factors related to atmospheric, noise, and sanitation pollutants. Identify and evaluate the acute and chronic risks and effects of exposure to fixed and mobile sources of air, noise, water, and soil pollution, and act in the surveillance of diseases derived from these pollutants through physical units and work groups, especially among the most vulnerable people.", + "es": "Desarrollar acciones orientadas a promover la salud de la población expuesta a factores ambientales relacionados con contaminantes atmosféricos, acústicos y de saneamiento. Identificar y evaluar los riesgos y efectos agudos y crónicos de la exposición a fuentes fijas y móviles de contaminación del aire, ruido, agua y suelo, y actuar en la vigilancia de enfermedades derivadas de estos contaminantes a través de unidades físicas y grupos de trabajo, especialmente entre las personas más vulnerables.", + "pt": "Desenvolver ações voltadas para a promoção da saúde da população exposta a fatores ambientais relacionados a poluentes atmosféricos, sonoros e de saneamento. Identificar e avaliar os riscos e efeitos agudos e crônicos da exposição a fontes fixas e móveis de poluição do ar, ruído, água e solo, e atuar na vigilância de doenças derivadas desses poluentes por meio de unidades físicas e grupos de trabalho, especialmente entre as pessoas mais vulneráveis." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "diseases", + "floods" + ], + "sectors": [], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": "low", + "heatwaves": "medium", + "floods": "low", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": "high" + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Data, Tools & Planning Projects", + "keyImpacts": null + }, + { + "actionId": "ipcc_0001", + "name": { + "en": "Promote compact urban form and transit-oriented development", + "es": "Promover un desarrollo urbano compacto y orientado al transporte público", + "pt": "Promover a forma urbana compacta e o desenvolvimento orientado para o transporte coletivo" + }, + "description": { + "en": "Encourages compact and mixed-use urban development to reduce travel distances, car dependency, and related GHG emissions. Measures include transit-oriented development (TOD), zoning reforms, densification around transport corridors, and integration of land use and mobility planning. Particularly suited for larger cities with the capacity to update master plans and invest in transit infrastructure.", + "es": "Fomenta el desarrollo urbano compacto y de uso mixto para reducir las distancias de viaje, la dependencia del automóvil y las emisiones de GEI asociadas. Las medidas incluyen el desarrollo orientado al transporte público (TOD), reformas de zonificación, densificación alrededor de los corredores de transporte e integración de la planificación del uso del suelo y la movilidad. Especialmente adecuado para ciudades grandes con capacidad para actualizar planes maestros e invertir en infraestructura de transporte público.", + "pt": "Incentiva o desenvolvimento urbano compacto e de uso misto para reduzir distâncias de deslocamento, dependência de carros e as emissões de GEE associadas. As medidas incluem desenvolvimento orientado ao transporte público (TOD), reformas de zoneamento, adensamento ao longo de corredores de transporte e integração do planejamento do uso do solo e da mobilidade. Especialmente adequado para cidades maiores com capacidade de atualizar planos diretores e investir em infraestrutura de transporte coletivo." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 1, + "mobility": 2, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "0-19", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0023", + "name": { + "en": "Design products with lightweight materials", + "es": "Diseñar productos con materiales ligeros", + "pt": "Projetar produtos com materiais leves" + }, + "description": { + "en": "This action involves improving material efficiency by designing lighter products, optimizing material usage to maintain functionality, and incorporating circular economy principles such as reusability, repairability, and recyclability. It spans the entire product lifecycle, from design to end-of-life management.", + "es": "Esta acción implica mejorar la eficiencia de los materiales mediante el diseño de productos más ligeros, la optimización del uso de materiales para mantener la funcionalidad e incorporar principios de economía circular como la reutilización, la reparabilidad y la reciclabilidad. Abarca todo el ciclo de vida del producto, desde el diseño hasta la gestión al final de su vida útil.", + "pt": "Esta ação envolve melhorar a eficiência dos materiais por meio do design de produtos mais leves, otimizando o uso de materiais para manter a funcionalidade e incorporando princípios da economia circular, como reutilização, reparabilidade e reciclabilidade. Ela abrange todo o ciclo de vida do produto, desde o design até a gestão do fim de vida." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0024", + "name": { + "en": "Improve material utilization efficiency in production", + "es": "Mejorar la eficiencia en la utilización de materiales en la producción", + "pt": "Melhorar a eficiência da utilização de materiais na produção" + }, + "description": { + "en": "This action focuses on enhancing material efficiency by adopting near-net shape casting and similar innovative manufacturing techniques. These methods reduce material wastage during production, improve yield from raw materials, and enhance energy efficiency by minimizing reprocessing. Strategies include optimizing product design, lightweighting, and improving recycling and reuse processes.", + "es": "Esta acción se centra en mejorar la eficiencia de los materiales mediante la adopción de técnicas innovadoras de fabricación como la fundición de forma casi neta y métodos similares. Estos métodos reducen el desperdicio de material durante la producción, mejoran el rendimiento de las materias primas y aumentan la eficiencia energética al minimizar el reprocesamiento. Las estrategias incluyen la optimización del diseño de productos, la reducción de peso y la mejora de los procesos de reciclaje y reutilización.", + "pt": "Esta ação foca em aumentar a eficiência do uso de materiais por meio da adoção de técnicas inovadoras de fabricação, como a fundição near-net shape e similares. Esses métodos reduzem o desperdício de material durante a produção, melhoram o aproveitamento das matérias-primas e aumentam a eficiência energética ao minimizar o retrabalho. As estratégias incluem a otimização do design dos produtos, redução de peso e aprimoramento dos processos de reciclagem e reutilização." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0025", + "name": { + "en": "Design for Recovery, Reuse, or Repurposing", + "es": "Diseñar para la recuperación, reutilización o revalorización", + "pt": "Projetar para Recuperação, Reutilização ou Reaproveitamento" + }, + "description": { + "en": "This action involves designing products to enable circular principles such as extended product life, reusability, repairability, and ease of recycling. It emphasizes lightweighting, material optimization, and improved recovery of materials at the end of their lifecycle through reuse, remanufacturing, or recycling.", + "es": "Esta acción implica diseñar productos para permitir principios circulares como la extensión de la vida útil del producto, la reutilización, la reparabilidad y la facilidad de reciclaje. Se enfatiza la reducción de peso, la optimización de materiales y la mejora en la recuperación de materiales al final de su ciclo de vida mediante la reutilización, la remanufactura o el reciclaje.", + "pt": "Esta ação envolve o design de produtos para possibilitar princípios circulares, como vida útil prolongada, reutilização, reparabilidade e facilidade de reciclagem. Ela enfatiza a redução de peso, a otimização de materiais e a melhoria na recuperação de materiais ao final de seu ciclo de vida por meio de reutilização, remanufatura ou reciclagem." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0026", + "name": { + "en": "Adopt alternative feedstocks in industrial production", + "es": "Adoptar materias primas alternativas en la producción industrial", + "pt": "Adotar matérias-primas alternativas na produção industrial" + }, + "description": { + "en": "Utilizing alternative feedstocks, such as blast furnace slag, fly ash, and pozzolans, to reduce the clinker-to-cement ratio in cement production. These alternatives lower emissions associated with calcination and energy-intensive processes. Improved material efficiency through high-strength concretes and innovative placement methods further reduces material usage.", + "es": "Utilizar materias primas alternativas, como escoria de alto horno, cenizas volantes y puzolanas, para reducir la proporción de clínker en la producción de cemento. Estas alternativas disminuyen las emisiones asociadas con la calcinación y los procesos de alta demanda energética. Una mayor eficiencia en el uso de materiales mediante concretos de alta resistencia y métodos innovadores de colocación reduce aún más el consumo de materiales.", + "pt": "Utilizar matérias-primas alternativas, como escória de alto-forno, cinzas volantes e pozolanas, para reduzir a proporção de clínquer no cimento durante a produção. Essas alternativas diminuem as emissões associadas à calcinação e aos processos de alta intensidade energética. A eficiência aprimorada dos materiais, por meio de concretos de alta resistência e métodos inovadores de aplicação, reduz ainda mais o uso de materiais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "60-79", + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0028", + "name": { + "en": "Behavioral Changes for Reduced Waste (e.g., Food)", + "es": "Cambios de comportamiento para reducir los residuos (por ejemplo, alimentos)", + "pt": "Mudanças de comportamento para redução de resíduos (por exemplo, alimentos)" + }, + "description": { + "en": "Encouraging behavioral changes to reduce waste in industrial processes and consumer habits, particularly in food production and consumption. This includes reducing food waste through better planning, optimizing portion sizes, and improving recycling and reuse practices in production and post-consumption stages.", + "es": "Fomentar cambios de comportamiento para reducir los residuos en los procesos industriales y los hábitos de consumo, especialmente en la producción y el consumo de alimentos. Esto incluye reducir el desperdicio de alimentos mediante una mejor planificación, la optimización de los tamaños de las porciones y la mejora de las prácticas de reciclaje y reutilización en las etapas de producción y postconsumo.", + "pt": "Incentivar mudanças de comportamento para reduzir o desperdício nos processos industriais e nos hábitos de consumo, especialmente na produção e no consumo de alimentos. Isso inclui a redução do desperdício de alimentos por meio de um melhor planejamento, otimização do tamanho das porções e aprimoramento das práticas de reciclagem e reutilização nas etapas de produção e pós-consumo." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0031", + "name": { + "en": "Enhanced product service levels per product (e.g. product sharing)", + "es": "Niveles de servicio de producto mejorados por producto (por ejemplo, compartición de productos)", + "pt": "Níveis de serviço de produto aprimorados por produto (por exemplo, compartilhamento de produtos)" + }, + "description": { + "en": "Promotes more intensive use of durable products by encouraging product sharing, which reduces the demand for new products and the associated GHG emissions from their manufacturing and supply chain.", + "es": "Promueve un uso más intensivo de productos duraderos fomentando el intercambio de productos, lo que reduce la demanda de nuevos productos y las emisiones de GEI asociadas a su fabricación y cadena de suministro.", + "pt": "Promove o uso mais intensivo de produtos duráveis ao incentivar o compartilhamento de produtos, o que reduz a demanda por novos produtos e as emissões de GEE associadas à sua fabricação e cadeia de suprimentos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0033", + "name": { + "en": "Improve product maintenance to extend lifespan", + "es": "Mejorar el mantenimiento de los productos para extender su vida útil", + "pt": "Melhorar a manutenção dos produtos para prolongar a vida útil" + }, + "description": { + "en": "Extending the lifespan of buildings and infrastructure by maintaining their structural integrity through improved product stock maintenance. This involves ensuring concrete structures remain functional for over 200 years.", + "es": "Ampliar la vida útil de los edificios e infraestructuras mediante el mantenimiento de su integridad estructural a través de una mejor gestión del stock de productos. Esto implica asegurar que las estructuras de hormigón permanezcan funcionales durante más de 200 años.", + "pt": "Prolongar a vida útil de edifícios e infraestruturas mantendo sua integridade estrutural por meio de uma melhor manutenção do estoque de produtos. Isso envolve garantir que estruturas de concreto permaneçam funcionais por mais de 200 anos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0034", + "name": { + "en": "Promote consumer behavior focused on sufficiency and reduced consumption", + "es": "Promover un comportamiento del consumidor enfocado en la suficiencia y la reducción del consumo", + "pt": "Promover o comportamento do consumidor focado na suficiência e na redução do consumo" + }, + "description": { + "en": "Promotes behavioral and consumption changes to reduce overall industrial emissions, emphasizing reduced demand for products, reuse and recycling, and more efficient use of resources.", + "es": "Promueve cambios en el comportamiento y el consumo para reducir las emisiones industriales totales, haciendo hincapié en la disminución de la demanda de productos, la reutilización y el reciclaje, y un uso más eficiente de los recursos.", + "pt": "Promove mudanças de comportamento e de consumo para reduzir as emissões industriais totais, enfatizando a diminuição da demanda por produtos, a reutilização e a reciclagem, além do uso mais eficiente dos recursos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0037", + "name": { + "en": "Adopt net-zero-emissions materials and supply chains", + "es": "Adoptar materiales y cadenas de suministro con emisiones netas cero", + "pt": "Adotar materiais e cadeias de suprimentos com emissões líquidas zero" + }, + "description": { + "en": "Transition to net-zero embodied carbon in construction by substituting emissions-intensive materials (e.g., steel, concrete) with engineered timber systems (including mass timber for mid-rise buildings) and by integrating circular practices (reuse, recycling, design for disassembly). Prioritize certified sustainable forestry (e.g., FSC/PEFC), cascading use, and no-deforestation safeguards, ensuring timber use does not conflict with energy feedstocks. Use lifecycle assessment to guide material choices and supply-chain improvements.", + "es": "Transición hacia carbono incorporado neto cero en la construcción mediante la sustitución de materiales con altas emisiones (por ejemplo, acero, hormigón) por sistemas de madera ingenierizada (incluida la madera maciza para edificios de mediana altura) y la integración de prácticas circulares (reutilización, reciclaje, diseño para el desmontaje). Priorizar la silvicultura sostenible certificada (por ejemplo, FSC/PEFC), el uso en cascada y salvaguardas contra la deforestación, asegurando que el uso de la madera no entre en conflicto con los insumos energéticos. Utilizar la evaluación del ciclo de vida para guiar la selección de materiales y las mejoras en la cadena de suministro.", + "pt": "Transição para carbono incorporado líquido zero na construção, substituindo materiais com altas emissões (por exemplo, aço, concreto) por sistemas de madeira engenheirada (incluindo madeira maciça para edifícios de média altura) e integrando práticas circulares (reutilização, reciclagem, design para desmontagem). Priorizar o manejo florestal sustentável certificado (por exemplo, FSC/PEFC), uso em cascata e salvaguardas contra o desmatamento, garantindo que o uso da madeira não entre em conflito com matérias-primas para energia. Utilizar avaliação do ciclo de vida para orientar a escolha de materiais e melhorias na cadeia de suprimentos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0038", + "name": { + "en": "Stimulate solar energy production in industrial facilities", + "es": "Estimular la producción de energía solar en instalaciones industriales", + "pt": "Estimular a produção de energia solar em instalações industriais" + }, + "description": { + "en": "Encourage the installation of solar energy systems in factories to reduce dependence on fossil fuels and minimize associated emissions.", + "es": "Fomentar la instalación de sistemas de energía solar en las fábricas para reducir la dependencia de los combustibles fósiles y minimizar las emisiones asociadas.", + "pt": "Incentivar a instalação de sistemas de energia solar em fábricas para reduzir a dependência de combustíveis fósseis e minimizar as emissões associadas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0039", + "name": { + "en": "Promote the substitution of traditional materials with sustainable alternatives", + "es": "Promover la sustitución de materiales tradicionales por alternativas sostenibles", + "pt": "Promover a substituição de materiais tradicionais por alternativas sustentáveis" + }, + "description": { + "en": "Stimulate the replacement of conventional materials in consumer goods with alternatives from Brazil's bioeconomy, such as sugarcane-based bioplastics, high-quality recycled polymers, bio-textiles made from biomass fibers or agricultural waste such as açaí seeds and coconut husks.", + "es": "Estimular la sustitución de materiales convencionales en bienes de consumo por alternativas provenientes de la bioeconomía de Brasil, como bioplásticos a base de caña de azúcar, polímeros reciclados de alta calidad, biotextiles elaborados a partir de fibras de biomasa o residuos agrícolas como semillas de açaí y cáscaras de coco.", + "pt": "Estimular a substituição de materiais convencionais em bens de consumo por alternativas da bioeconomia brasileira, como bioplásticos à base de cana-de-açúcar, polímeros reciclados de alta qualidade, biotêxteis feitos de fibras de biomassa ou resíduos agrícolas como sementes de açaí e cascas de coco." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0040", + "name": { + "en": "Promote industry-government collaborations on emissions reduction", + "es": "Promover colaboraciones entre la industria y el gobierno para la reducción de emisiones", + "pt": "Promover colaborações entre a indústria e o governo para a redução de emissões" + }, + "description": { + "en": "Foster collaborations between industry and government to create policies and incentives for reducing industrial emissions and supporting sustainability goals.", + "es": "Fomentar la colaboración entre la industria y el gobierno para crear políticas e incentivos que reduzcan las emisiones industriales y apoyen los objetivos de sostenibilidad.", + "pt": "Promover colaborações entre a indústria e o governo para criar políticas e incentivos para reduzir as emissões industriais e apoiar metas de sustentabilidade." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0041", + "name": { + "en": "Support research into carbon-neutral manufacturing technologies", + "es": "Apoyar la investigación en tecnologías de fabricación neutras en carbono", + "pt": "Apoiar pesquisas em tecnologias de manufatura neutras em carbono" + }, + "description": { + "en": "Invest in research and development of carbon-neutral technologies and encourage their adoption in industrial production.", + "es": "Invertir en investigación y desarrollo de tecnologías neutras en carbono y fomentar su adopción en la producción industrial.", + "pt": "Investir em pesquisa e desenvolvimento de tecnologias neutras em carbono e incentivar sua adoção na produção industrial." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0042", + "name": { + "en": "Set carbon emissions reduction targets for industrial sectors", + "es": "Establecer objetivos de reducción de emisiones de carbono para los sectores industriales", + "pt": "Definir metas de redução de emissões de carbono para os setores industriais" + }, + "description": { + "en": "Establish clear and achievable carbon emissions reduction goals for industries and require periodic reporting to ensure progress.", + "es": "Establecer objetivos claros y alcanzables de reducción de emisiones de carbono para las industrias y exigir informes periódicos para garantizar el progreso.", + "pt": "Estabelecer metas claras e alcançáveis de redução de emissões de carbono para as indústrias e exigir relatórios periódicos para garantir o progresso." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0043", + "name": { + "en": "Encourage the Use of Zero-Emission Fuels in Industrial Processes", + "es": "Fomentar el uso de combustibles de cero emisiones en los procesos industriales", + "pt": "Incentivar o uso de combustíveis de emissão zero em processos industriais" + }, + "description": { + "en": "Promote the transition to zero-emission energy sources and feedstocks in industrial processes, such as green hydrogen, biogas from sustainable sources, and synthetic e-fuels or chemicals produced with renewable electricity. These alternatives significantly reduce or eliminate process emissions compared to fossil-based fuels.\nCities can accelerate this shift by implementing pilot and demonstration projects, establishing green procurement standards, streamlining permitting processes, and creating targeted incentives, all aligned with national and sectoral decarbonization roadmaps.", + "es": "Promover la transición hacia fuentes de energía y materias primas de cero emisiones en los procesos industriales, como el hidrógeno verde, el biogás de fuentes sostenibles y los e-combustibles sintéticos o productos químicos producidos con electricidad renovable. Estas alternativas reducen significativamente o eliminan las emisiones de los procesos en comparación con los combustibles de origen fósil.\nLas ciudades pueden acelerar este cambio implementando proyectos piloto y de demostración, estableciendo estándares de compras verdes, agilizando los procesos de permisos y creando incentivos específicos, todo ello alineado con las hojas de ruta nacionales y sectoriales de descarbonización.", + "pt": "Promover a transição para fontes de energia e matérias-primas de emissão zero nos processos industriais, como hidrogênio verde, biogás de fontes sustentáveis e e-combustíveis sintéticos ou produtos químicos produzidos com eletricidade renovável. Essas alternativas reduzem significativamente ou eliminam as emissões dos processos em comparação com combustíveis de origem fóssil.\nAs cidades podem acelerar essa mudança implementando projetos-piloto e de demonstração, estabelecendo padrões de compras verdes, simplificando processos de licenciamento e criando incentivos direcionados, todos alinhados com roteiros nacionais e setoriais de descarbonização." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0045", + "name": { + "en": "Transition to renewable energy for industrial operations", + "es": "Transición a energías renovables para las operaciones industriales", + "pt": "Transição para energia renovável nas operações industriais" + }, + "description": { + "en": "Encourage the shift to renewable energy sources such as wind, solar, and hydroelectric power in industrial operations to reduce fossil fuel use.", + "es": "Fomentar la transición hacia fuentes de energía renovable como la eólica, solar e hidroeléctrica en las operaciones industriales para reducir el uso de combustibles fósiles.", + "pt": "Incentivar a transição para fontes de energia renovável, como eólica, solar e hidrelétrica, nas operações industriais para reduzir o uso de combustíveis fósseis." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0049", + "name": { + "en": "Develop and implement circular economy policies", + "es": "Desarrollar e implementar políticas de economía circular", + "pt": "Desenvolver e implementar políticas de economia circular" + }, + "description": { + "en": "Circular Economy (CE) policies aim to close the loop for materials and energy flows by reducing, reusing, and recycling resources. These policies promote durable goods, reuse and remanufacturing, industrial symbiosis, and urban symbiosis to minimize waste and reduce GHG emissions. CE policies operate at micro, meso, and macro levels to integrate strategies like eco-design, sustainable supply chains, and urban energy symbiosis.", + "es": "Las políticas de Economía Circular (EC) buscan cerrar el ciclo de los flujos de materiales y energía mediante la reducción, reutilización y reciclaje de recursos. Estas políticas promueven bienes duraderos, la reutilización y la remanufactura, la simbiosis industrial y la simbiosis urbana para minimizar los residuos y reducir las emisiones de GEI. Las políticas de EC operan a nivel micro, meso y macro para integrar estrategias como el ecodiseño, cadenas de suministro sostenibles y la simbiosis energética urbana.", + "pt": "As políticas de Economia Circular (EC) visam fechar o ciclo dos fluxos de materiais e energia por meio da redução, reutilização e reciclagem de recursos. Essas políticas promovem bens duráveis, reutilização e remanufatura, simbiose industrial e simbiose urbana para minimizar resíduos e reduzir as emissões de GEE. As políticas de EC operam nos níveis micro, meso e macro para integrar estratégias como ecodesign, cadeias de suprimentos sustentáveis e simbiose energética urbana." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "40-59", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0050", + "name": { + "en": "Create tax incentives for companies adopting clean technologies", + "es": "Crear incentivos fiscales para las empresas que adopten tecnologías limpias", + "pt": "Criar incentivos fiscais para empresas que adotam tecnologias limpas" + }, + "description": { + "en": "Implement tax incentives and subsidies for companies that invest in clean technologies, leading to substantial emission reductions.", + "es": "Implementar incentivos fiscales y subsidios para las empresas que inviertan en tecnologías limpias, lo que conducirá a una reducción sustancial de las emisiones.", + "pt": "Implementar incentivos fiscais e subsídios para empresas que investem em tecnologias limpas, levando a reduções substanciais de emissões." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "low", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0052", + "name": { + "en": "Reduce Deforestation and Degradation", + "es": "Reducir la deforestación y la degradación", + "pt": "Reduzir o Desmatamento e a Degradação" + }, + "description": { + "en": "Reduce deforestation and forest degradation to conserve carbon sequestered in forest vegetation and soil by avoiding tree cover loss and disturbance. This involves improving forest governance and supporting community forest management. Enhance monitoring and enforcement to prevent illegal deforestation and promote sustainable land use.", + "es": "Reducir la deforestación y la degradación de los bosques para conservar el carbono almacenado en la vegetación y el suelo forestal evitando la pérdida de cobertura arbórea y las perturbaciones. Esto implica mejorar la gobernanza forestal y apoyar la gestión comunitaria de los bosques. Fortalecer el monitoreo y la aplicación de la ley para prevenir la deforestación ilegal y promover el uso sostenible del suelo.", + "pt": "Reduzir o desmatamento e a degradação florestal para conservar o carbono sequestrado na vegetação e no solo das florestas, evitando a perda de cobertura arbórea e distúrbios. Isso envolve melhorar a governança florestal e apoiar a gestão comunitária das florestas. Reforçar o monitoramento e a fiscalização para prevenir o desmatamento ilegal e promover o uso sustentável da terra." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "60-79" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": "tropical_rainforest", + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0053", + "name": { + "en": "Implement afforestation, reforestation, and forest ecosystem restoration", + "es": "Implementar la forestación, la reforestación y la restauración de ecosistemas forestales", + "pt": "Implementar o reflorestamento, a aforestação e a restauração de ecossistemas florestais" + }, + "description": { + "en": "Advance tree-planting and forest recovery initiatives that strengthen biodiversity, ecosystem services, and carbon sequestration. Afforestation establishes new forests on historically non-forested land, reforestation restores deforested areas, and ecosystem restoration prioritizes native species and ecological integrity. Municipal governments should avoid monocultures, ensure projects deliver long-term benefits, and engage local communities so that restoration efforts provide social, cultural, and economic value alongside environmental gains.", + "es": "Avanzar en iniciativas de plantación de árboles y recuperación de bosques que fortalezcan la biodiversidad, los servicios ecosistémicos y la captura de carbono. La forestación establece nuevos bosques en tierras que históricamente no eran boscosas, la reforestación restaura áreas deforestadas y la restauración de ecosistemas prioriza las especies nativas y la integridad ecológica. Los gobiernos municipales deben evitar los monocultivos, asegurar que los proyectos generen beneficios a largo plazo e involucrar a las comunidades locales para que los esfuerzos de restauración aporten valor social, cultural y económico junto con beneficios ambientales.", + "pt": "Avançar com iniciativas de plantio de árvores e recuperação florestal que fortaleçam a biodiversidade, os serviços ecossistêmicos e a captura de carbono. A aforestação estabelece novas florestas em áreas historicamente não florestadas, a reflorestação restaura áreas desmatadas e a restauração de ecossistemas prioriza espécies nativas e a integridade ecológica. Os governos municipais devem evitar monoculturas, garantir que os projetos proporcionem benefícios a longo prazo e envolver as comunidades locais para que os esforços de restauração ofereçam valor social, cultural e econômico juntamente com ganhos ambientais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "60-79" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0054", + "name": { + "en": "Adopt sustainable forest management practices", + "es": "Adoptar prácticas de gestión forestal sostenible", + "pt": "Adotar práticas de manejo florestal sustentável" + }, + "description": { + "en": "Sustainable forest management of already managed forests will increase carbon stocks, improve wood quality, mitigate disturbances, and provide co-benefits like biodiversity conservation, water regulation, and soil protection. Practises include longer rotations, reduced harvesting, mixed stands, and climate-smart forestry, and working with Indigenous Peoples is essential to safeguard their work and practices. Cities can apply these principles if they are responsible for forest management, or partner with those responsible to encourage and support best practice.", + "es": "La gestión forestal sostenible de los bosques ya gestionados aumentará las reservas de carbono, mejorará la calidad de la madera, mitigará las perturbaciones y proporcionará co-beneficios como la conservación de la biodiversidad, la regulación del agua y la protección del suelo. Las prácticas incluyen rotaciones más largas, reducción de la tala, bosques mixtos y silvicultura inteligente frente al clima, y trabajar con los Pueblos Indígenas es esencial para salvaguardar su labor y prácticas. Las ciudades pueden aplicar estos principios si son responsables de la gestión forestal, o asociarse con quienes lo son para fomentar y apoyar las mejores prácticas.", + "pt": "O manejo florestal sustentável de florestas já manejadas aumentará os estoques de carbono, melhorará a qualidade da madeira, mitigará distúrbios e proporcionará co-benefícios como conservação da biodiversidade, regulação da água e proteção do solo. As práticas incluem rotações mais longas, redução da extração, povoamentos mistos e silvicultura inteligente para o clima, sendo essencial trabalhar com os Povos Indígenas para salvaguardar seu trabalho e práticas. As cidades podem aplicar esses princípios se forem responsáveis pelo manejo florestal, ou podem se associar com os responsáveis para incentivar e apoiar as melhores práticas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "40-59" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0055", + "name": { + "en": "Implement fire management in forests, grasslands, and savannas", + "es": "Implementar la gestión de incendios en bosques, pastizales y sabanas", + "pt": "Implementar o manejo do fogo em florestas, pastagens e savanas" + }, + "description": { + "en": "Implement fire management practices, including prescribed burning and natural resource management, to reduce uncontrolled wildfires in forests and savannas. Focuses on safeguarding life, property, and resources while mitigating GHG emissions and maintaining carbon stocks. Cities can apply these principles if they are responsible for forest management, or partner with those responsible to encourage and support best practice. Work with Indigenous Peoples to safeguard or support their own burning practices and fire management approaches.", + "es": "Implementar prácticas de gestión de incendios, incluyendo quemas prescritas y manejo de recursos naturales, para reducir los incendios forestales incontrolados en bosques y sabanas. Se enfoca en salvaguardar la vida, la propiedad y los recursos, al mismo tiempo que mitiga las emisiones de GEI y mantiene las reservas de carbono. Las ciudades pueden aplicar estos principios si son responsables de la gestión forestal, o asociarse con quienes lo son para fomentar y apoyar las mejores prácticas. Trabajar con los Pueblos Indígenas para proteger o apoyar sus propias prácticas de quema y enfoques de gestión del fuego.", + "pt": "Implementar práticas de manejo do fogo, incluindo queimas prescritas e gestão de recursos naturais, para reduzir incêndios florestais descontrolados em florestas e savanas. O foco é proteger vidas, propriedades e recursos, ao mesmo tempo em que se mitigam as emissões de GEE e se mantêm os estoques de carbono. As cidades podem aplicar esses princípios se forem responsáveis pelo manejo florestal, ou podem fazer parcerias com os responsáveis para incentivar e apoiar as melhores práticas. Trabalhar com Povos Indígenas para proteger ou apoiar suas próprias práticas de queima e abordagens de manejo do fogo." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0056", + "name": { + "en": "Reduce and prevent degradation and conversion of Grasslands and Savannas", + "es": "Reducir y prevenir la degradación y conversión de pastizales y sabanas", + "pt": "Reduzir e prevenir a degradação e conversão de pastagens e savanas" + }, + "description": { + "en": "Prevent the conversion of grasslands and savannas to croplands to conserve soil carbon and biodiversity, and implement sustainable soil management practices in croplands and grasslands to enhance soil organic carbon. Cities can promote sustainable grazing, reduced tillage, fire management, biochar application, improved grass varieties and vegetation management practices, while discouraging land-use change that accelerates degradation. Partnerships with local communities and alignment with regional conservation initiatives strengthen the protection of these ecosystems.These activities aim to increase soil organic matter, mitigate GHG emissions, and provide co-benefits for biodiversity, water provision, and food security.", + "es": "Prevenir la conversión de pastizales y sabanas en tierras de cultivo para conservar el carbono del suelo y la biodiversidad, e implementar prácticas sostenibles de manejo del suelo en tierras de cultivo y pastizales para aumentar el carbono orgánico del suelo. Las ciudades pueden promover el pastoreo sostenible, la reducción de la labranza, la gestión del fuego, la aplicación de biochar, la mejora de variedades de pastos y las prácticas de manejo de la vegetación, al mismo tiempo que desincentivan el cambio de uso de suelo que acelera la degradación. Las alianzas con comunidades locales y la alineación con iniciativas regionales de conservación fortalecen la protección de estos ecosistemas. Estas actividades buscan aumentar la materia orgánica del suelo, mitigar las emisiones de GEI y proporcionar co-beneficios para la biodiversidad, el suministro de agua y la seguridad alimentaria.", + "pt": "Prevenir a conversão de pastagens e savanas em áreas agrícolas para conservar o carbono do solo e a biodiversidade, e implementar práticas de manejo sustentável do solo em áreas agrícolas e pastagens para aumentar o carbono orgânico do solo. As cidades podem promover o pastoreio sustentável, a redução do revolvimento do solo, o manejo do fogo, a aplicação de biochar, a melhoria das variedades de gramíneas e práticas de manejo da vegetação, ao mesmo tempo em que desencorajam a mudança de uso da terra que acelera a degradação. Parcerias com comunidades locais e o alinhamento com iniciativas regionais de conservação fortalecem a proteção desses ecossistemas. Essas atividades visam aumentar a matéria orgânica do solo, mitigar as emissões de GEE e proporcionar co-benefícios para a biodiversidade, oferta de água e segurança alimentar." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": "grassland_savanna", + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0057", + "name": { + "en": "Restore degraded peatlands and prevent further conversion or degradation.", + "es": "Restaurar turberas degradadas y prevenir su conversión o degradación adicional.", + "pt": "Restaurar turfeiras degradadas e prevenir novas conversões ou degradações." + }, + "description": { + "en": "Protect intact peatlands from clearing, drainage, and conversion that release large carbon emissions, and rewet and revegetate degraded peatlands to prevent further degradation. Municipal governments can enhance governance and monitoring, restrict agricultural expansion, and collaborate with regional and national programs for wetland conservation. Safeguarding these ecosystems preserves carbon storage, reduces fire risks, and protects biodiversity and ecosystem services. Peatland restoration maintains water regulation, flood prevention, and can foster sustainable livelihoods through paludiculture.", + "es": "Proteger las turberas intactas de la tala, el drenaje y la conversión que liberan grandes emisiones de carbono, y rehumedecer y revegetar las turberas degradadas para evitar una mayor degradación. Los gobiernos municipales pueden mejorar la gobernanza y el monitoreo, restringir la expansión agrícola y colaborar con programas regionales y nacionales para la conservación de humedales. Salvaguardar estos ecosistemas preserva el almacenamiento de carbono, reduce los riesgos de incendios y protege la biodiversidad y los servicios ecosistémicos. La restauración de turberas mantiene la regulación del agua, la prevención de inundaciones y puede fomentar medios de vida sostenibles a través de la paludicultura.", + "pt": "Proteger turfeiras intactas contra desmatamento, drenagem e conversão que liberam grandes emissões de carbono, além de reumedecer e revegetar turfeiras degradadas para evitar mais degradação. Os governos municipais podem aprimorar a governança e o monitoramento, restringir a expansão agrícola e colaborar com programas regionais e nacionais para a conservação de áreas úmidas. Proteger esses ecossistemas preserva o armazenamento de carbono, reduz os riscos de incêndio e protege a biodiversidade e os serviços ecossistêmicos. A restauração de turfeiras mantém a regulação da água, previne enchentes e pode promover meios de subsistência sustentáveis por meio da paludicultura." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "40-59" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": "wetlands", + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0060", + "name": { + "en": "Protect and Restore Coastal Wetlands", + "es": "Proteger y restaurar los humedales costeros", + "pt": "Proteger e Restaurar Zonas Úmidas Costeiras" + }, + "description": { + "en": "Restore degraded or damaged coastal ecosystems, including mangroves, salt marshes, and seagrass beds. Restoration includes passive (removal of degradation drivers) and active (environmental manipulation) approaches to reinstate ecosystem functions and carbon sequestration potential. This supports biodiversity conservation, fisheries production, soil stabilization, water quality regulation, flood prevention, and resilience against cyclones. Cities can either take on restoration activities themselves, require restoration as part of Urban Planning and land use regulations, or partner with government, ecological organisations and other partners to carry out restoration projects. Economic incentives or regulations on activities that degrade coastal wetlands may also be effective.", + "es": "Restaurar ecosistemas costeros degradados o dañados, incluyendo manglares, marismas salinas y praderas marinas. La restauración incluye enfoques pasivos (eliminación de los factores de degradación) y activos (manipulación ambiental) para restablecer las funciones del ecosistema y el potencial de secuestro de carbono. Esto apoya la conservación de la biodiversidad, la producción pesquera, la estabilización del suelo, la regulación de la calidad del agua, la prevención de inundaciones y la resiliencia frente a ciclones. Las ciudades pueden llevar a cabo actividades de restauración por sí mismas, exigir la restauración como parte de la planificación urbana y las regulaciones de uso del suelo, o asociarse con el gobierno, organizaciones ecológicas y otros socios para realizar proyectos de restauración. Los incentivos económicos o las regulaciones sobre actividades que degradan los humedales costeros también pueden ser efectivos.", + "pt": "Restaurar ecossistemas costeiros degradados ou danificados, incluindo manguezais, marismas e pradarias marinhas. A restauração inclui abordagens passivas (remoção dos fatores de degradação) e ativas (manipulação ambiental) para restabelecer as funções do ecossistema e o potencial de sequestro de carbono. Isso apoia a conservação da biodiversidade, a produção pesqueira, a estabilização do solo, a regulação da qualidade da água, a prevenção de inundações e a resiliência contra ciclones. As cidades podem realizar atividades de restauração por conta própria, exigir a restauração como parte do planejamento urbano e das regulamentações de uso do solo, ou fazer parcerias com o governo, organizações ecológicas e outros parceiros para executar projetos de restauração. Incentivos econômicos ou regulamentações sobre atividades que degradam áreas úmidas costeiras também podem ser eficazes." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "40-59" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0062", + "name": { + "en": "Create partnerships to implement biochar plants.", + "es": "Crear alianzas para implementar plantas de biochar.", + "pt": "Criar parcerias para implementar usinas de biochar." + }, + "description": { + "en": "Biochar is produced by heating organic matter (e.g., forestry residues, straw, manure) in oxygen-limited environments. It has significant mitigation potential through carbon dioxide removal (CDR), reduced greenhouse gas emissions, and soil application benefits like improved fertility and reduced N2O emissions. Cities can consider trialling and adopting these technologies, in collaboration with local rural producers, utility companies and other industrial stakeholders.", + "es": "El biochar se produce al calentar materia orgánica (por ejemplo, residuos forestales, paja, estiércol) en ambientes con poco oxígeno. Tiene un importante potencial de mitigación mediante la eliminación de dióxido de carbono (CDR), la reducción de emisiones de gases de efecto invernadero y beneficios en la aplicación al suelo, como la mejora de la fertilidad y la reducción de emisiones de N2O. Las ciudades pueden considerar probar y adoptar estas tecnologías, en colaboración con productores rurales locales, empresas de servicios públicos y otros actores industriales.", + "pt": "O biochar é produzido pelo aquecimento de matéria orgânica (por exemplo, resíduos florestais, palha, esterco) em ambientes com pouco oxigênio. Ele possui um potencial significativo de mitigação por meio da remoção de dióxido de carbono (CDR), redução das emissões de gases de efeito estufa e benefícios na aplicação ao solo, como melhoria da fertilidade e redução das emissões de N2O. As cidades podem considerar testar e adotar essas tecnologias, em colaboração com produtores rurais locais, empresas de serviços públicos e outros atores industriais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0064", + "name": { + "en": "Reduce methane emissions from enteric fermentation in livestock", + "es": "Reducir las emisiones de metano provenientes de la fermentación entérica en el ganado", + "pt": "Reduzir as emissões de metano provenientes da fermentação entérica em animais de criação" + }, + "description": { + "en": "This action targets methane (CH4) emissions from enteric fermentation in livestock through direct interventions like feed additives, inhibitors, or vaccines, and indirect measures like improving production efficiency through better breeding and husbandry practices. It also includes early-life manipulation of the ruminal biome. Adopt or develop local standards for feed additives, vaccines, and inhibitors, and support rural producers to overcome barriers to costs, infrastructure and skills on this topic.", + "es": "Esta acción se dirige a las emisiones de metano (CH4) provenientes de la fermentación entérica en el ganado mediante intervenciones directas como aditivos alimentarios, inhibidores o vacunas, y medidas indirectas como la mejora de la eficiencia productiva a través de mejores prácticas de cría y manejo. También incluye la manipulación temprana del bioma ruminal. Adoptar o desarrollar normas locales para aditivos alimentarios, vacunas e inhibidores, y apoyar a los productores rurales para superar barreras relacionadas con los costos, la infraestructura y las capacidades en este tema.", + "pt": "Esta ação tem como alvo as emissões de metano (CH4) provenientes da fermentação entérica em animais de criação, por meio de intervenções diretas como aditivos alimentares, inibidores ou vacinas, e medidas indiretas como a melhoria da eficiência produtiva através de melhores práticas de reprodução e manejo. Também inclui a manipulação do bioma ruminal em fases iniciais da vida. Adotar ou desenvolver normas locais para aditivos alimentares, vacinas e inibidores, e apoiar os produtores rurais para superar barreiras de custos, infraestrutura e capacitação sobre este tema." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0067", + "name": { + "en": "Improve manure management and crop nutrient practices", + "es": "Mejorar la gestión del estiércol y las prácticas de nutrición de cultivos", + "pt": "Melhorar o manejo de esterco e as práticas de nutrientes das culturas" + }, + "description": { + "en": "Promote collective and cost-effective approaches to reduce methane (CH₄) and nitrous oxide (N₂O) emissions from manure storage and use, and implementation of improved crop nutrient management practices to reduce N2O emissions from cropland soils. Municipal governments can support the development of cooperative biodigesters, composting initiatives, and improved storage facilities, while encouraging better fertilizer application, crop rotation and grazing practices. These measures enhance nutrient recovery for crop production, reduce fertilizer costs, and generate co-benefits such as renewable energy through biogas. By facilitating financing models, partnerships, and technical assistance, cities can help farmers adopt sustainable manure and nutrient management practices at scale. ", + "es": "Promover enfoques colectivos y rentables para reducir las emisiones de metano (CH₄) y óxido nitroso (N₂O) provenientes del almacenamiento y uso de estiércol, así como la implementación de prácticas mejoradas de manejo de nutrientes en cultivos para disminuir las emisiones de N₂O en suelos agrícolas. Los gobiernos municipales pueden apoyar el desarrollo de biodigestores cooperativos, iniciativas de compostaje y mejores instalaciones de almacenamiento, al mismo tiempo que fomentan una mejor aplicación de fertilizantes, la rotación de cultivos y prácticas de pastoreo. Estas medidas mejoran la recuperación de nutrientes para la producción agrícola, reducen los costos de fertilizantes y generan co-beneficios como energía renovable a través del biogás. Al facilitar modelos de financiamiento, asociaciones y asistencia técnica, las ciudades pueden ayudar a los agricultores a adoptar prácticas sostenibles de manejo de estiércol y nutrientes a gran escala.", + "pt": "Promover abordagens coletivas e econômicas para reduzir as emissões de metano (CH₄) e óxido nitroso (N₂O) provenientes do armazenamento e uso de esterco, além da implementação de práticas aprimoradas de manejo de nutrientes em culturas para reduzir as emissões de N₂O dos solos agrícolas. Os governos municipais podem apoiar o desenvolvimento de biodigestores cooperativos, iniciativas de compostagem e instalações de armazenamento aprimoradas, ao mesmo tempo em que incentivam melhores práticas de aplicação de fertilizantes, rotação de culturas e manejo de pastagens. Essas medidas aumentam a recuperação de nutrientes para a produção agrícola, reduzem os custos com fertilizantes e geram co-benefícios como energia renovável por meio do biogás. Ao facilitar modelos de financiamento, parcerias e assistência técnica, as cidades podem ajudar os agricultores a adotar práticas sustentáveis de manejo de esterco e nutrientes em larga escala." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0068", + "name": { + "en": "Pilot Bioenergy with Carbon Capture in Partnership with Utilities/Industry.", + "es": "Piloto de bioenergía con captura de carbono en colaboración con empresas de servicios públicos/industria.", + "pt": "Piloto de Bioenergia com Captura de Carbono em Parceria com Concessionárias/Indústria." + }, + "description": { + "en": "Bioenergy involves producing energy from organic sources like biomass, organic waste, and harvest residues, displacing fossil fuels in heat, electricity, and fuel production. When combined with carbon capture and storage (BECCS), it stores biogenic carbon in geological or terrestrial reservoirs, achieving negative emissions. BECCS can also integrate with agriculture and forestry for co-benefits like land restoration and biogas production. Cities can consider piloting and trialling these technologies, in collaboration with local rural producers, utility companies and other industrial stakeholders.", + "es": "La bioenergía implica producir energía a partir de fuentes orgánicas como biomasa, residuos orgánicos y restos de cosecha, desplazando los combustibles fósiles en la producción de calor, electricidad y combustibles. Cuando se combina con captura y almacenamiento de carbono (BECCS), almacena carbono biogénico en reservorios geológicos o terrestres, logrando emisiones negativas. BECCS también puede integrarse con la agricultura y la silvicultura para obtener co-beneficios como la restauración de tierras y la producción de biogás. Las ciudades pueden considerar la implementación piloto y la prueba de estas tecnologías, en colaboración con productores rurales locales, empresas de servicios públicos y otros actores industriales.", + "pt": "A bioenergia envolve a produção de energia a partir de fontes orgânicas como biomassa, resíduos orgânicos e restos de colheita, substituindo combustíveis fósseis na produção de calor, eletricidade e combustíveis. Quando combinada com captura e armazenamento de carbono (BECCS), armazena carbono biogênico em reservatórios geológicos ou terrestres, alcançando emissões negativas. O BECCS também pode ser integrado à agricultura e à silvicultura para co-benefícios como restauração de terras e produção de biogás. As cidades podem considerar a implementação piloto e testes dessas tecnologias, em colaboração com produtores rurais locais, empresas de serviços públicos e outros atores industriais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "60-79" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Data, Tools & Planning Projects", + "keyImpacts": null + }, + { + "actionId": "ipcc_0069", + "name": { + "en": "Promote sustainable and healthy diets", + "es": "Promover dietas sostenibles y saludables", + "pt": "Promover dietas sustentáveis e saudáveis" + }, + "description": { + "en": "Support the transition to dietary patterns that improve health and reduce environmental impacts. This usually focusses on reducing animal-based food consumption (especially ruminants) and promoting plant-based options, making the action implementable and socially equitable. Cities can act through public procurement policies in schools, hospitals, events, and other institutions, as well as awareness campaigns and promoting national food guidelines.", + "es": "Apoyar la transición hacia patrones alimentarios que mejoren la salud y reduzcan los impactos ambientales. Esto suele centrarse en reducir el consumo de alimentos de origen animal (especialmente rumiantes) y promover opciones basadas en plantas, haciendo que la acción sea implementable y socialmente equitativa. Las ciudades pueden actuar a través de políticas de compras públicas en escuelas, hospitales, eventos y otras instituciones, así como mediante campañas de concienciación y la promoción de guías alimentarias nacionales.", + "pt": "Apoiar a transição para padrões alimentares que melhorem a saúde e reduzam os impactos ambientais. Isso geralmente se concentra na redução do consumo de alimentos de origem animal (especialmente ruminantes) e na promoção de opções à base de plantas, tornando a ação viável e socialmente equitativa. As cidades podem agir por meio de políticas de compras públicas em escolas, hospitais, eventos e outras instituições, bem como campanhas de conscientização e promoção de diretrizes alimentares nacionais." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "40-59" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0070", + "name": { + "en": "Reduce food loss and waste", + "es": "Reducir la pérdida y el desperdicio de alimentos", + "pt": "Reduzir a perda e o desperdício de alimentos" + }, + "description": { + "en": "Food loss and waste can be reduced through measures across the food supply chain, including improved harvesting and post-harvesting technologies and behaviours. To achieve these changes, cities can consider implementing food waste policies like mandatory reporting, reduction targets, consumer awareness and education campaigns, infrastructure for food storage and transportation, policy frameworks for waste reduction, financial incentives and taxation, and positive marketing for imperfect food products.", + "es": "La pérdida y el desperdicio de alimentos pueden reducirse mediante medidas a lo largo de toda la cadena de suministro alimentaria, incluyendo tecnologías y comportamientos mejorados en la cosecha y postcosecha. Para lograr estos cambios, las ciudades pueden considerar la implementación de políticas sobre el desperdicio de alimentos, como la obligatoriedad de reportes, metas de reducción, campañas de concienciación y educación para los consumidores, infraestructura para el almacenamiento y transporte de alimentos, marcos normativos para la reducción de residuos, incentivos financieros y fiscales, y marketing positivo para productos alimenticios imperfectos.", + "pt": "A perda e o desperdício de alimentos podem ser reduzidos por meio de medidas em toda a cadeia de suprimento alimentar, incluindo tecnologias e comportamentos aprimorados de colheita e pós-colheita. Para alcançar essas mudanças, as cidades podem considerar a implementação de políticas de desperdício de alimentos, como relatórios obrigatórios, metas de redução, campanhas de conscientização e educação do consumidor, infraestrutura para armazenamento e transporte de alimentos, estruturas de políticas para redução de resíduos, incentivos financeiros e tributação, e marketing positivo para produtos alimentícios imperfeitos." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "20-39" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0071", + "name": { + "en": "Increase sustainable use of wood products", + "es": "Aumentar el uso sostenible de productos de madera", + "pt": "Aumentar o uso sustentável de produtos de madeira" + }, + "description": { + "en": "Promote the use of certified sustainable wood (e.g., FSC, PEFC) as a substitute for more carbon-intensive and ecologically destructive materials like concrete or steel. Policies can include amending Building Regulations to include requirements on sustainable wood products, and urban procurement policies for municipal capital projects and spending that prioritize sustainable wood, recycling, and extending product lifetimes. Ensure policies include safeguards to avoid promoting unsustainable wood use.", + "es": "Promover el uso de madera certificada sostenible (por ejemplo, FSC, PEFC) como sustituto de materiales más intensivos en carbono y ecológicamente destructivos como el concreto o el acero. Las políticas pueden incluir la modificación de los Reglamentos de Construcción para incorporar requisitos sobre productos de madera sostenible, y políticas de adquisición urbana para proyectos de capital municipal y gastos que prioricen la madera sostenible, el reciclaje y la extensión de la vida útil de los productos. Asegurar que las políticas incluyan salvaguardas para evitar la promoción del uso insostenible de la madera.", + "pt": "Promover o uso de madeira certificada sustentável (por exemplo, FSC, PEFC) como substituto para materiais mais intensivos em carbono e ecologicamente destrutivos, como concreto ou aço. As políticas podem incluir a alteração dos Regulamentos de Construção para incluir exigências sobre produtos de madeira sustentável, e políticas de compras urbanas para projetos e gastos de capital municipais que priorizem madeira sustentável, reciclagem e extensão da vida útil dos produtos. Garantir que as políticas incluam salvaguardas para evitar a promoção do uso insustentável da madeira." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "afolu" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": "40-59" + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0074", + "name": { + "en": "Promote compact urban form through spatial planning", + "es": "Promover una forma urbana compacta mediante la planificación espacial", + "pt": "Promover a forma urbana compacta por meio do planejamento espacial" + }, + "description": { + "en": "Integrated spatial planning promotes compact urban form to reduce GHG emissions by increasing urban efficiency, supporting sustainable infrastructure such as district heating/cooling networks, and enhancing green areas. Co-design processes improve public acceptance and institutional capacity to support coordinated mitigation strategies.", + "es": "La planificación espacial integrada promueve una forma urbana compacta para reducir las emisiones de GEI al aumentar la eficiencia urbana, apoyar infraestructuras sostenibles como redes de calefacción/enfriamiento distrital y mejorar las áreas verdes. Los procesos de co-diseño mejoran la aceptación pública y la capacidad institucional para respaldar estrategias de mitigación coordinadas.", + "pt": "O planejamento espacial integrado promove uma forma urbana compacta para reduzir as emissões de GEE, aumentando a eficiência urbana, apoiando infraestruturas sustentáveis como redes de aquecimento/resfriamento distrital e ampliando áreas verdes. Processos de co-design melhoram a aceitação pública e a capacidade institucional para apoiar estratégias de mitigação coordenadas." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 0, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 0 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0076", + "name": { + "en": "Implement energy audits in industrial plants", + "es": "Implementar auditorías energéticas en plantas industriales", + "pt": "Implementar auditorias energéticas em plantas industriais" + }, + "description": { + "en": "Conduct regular energy audits to identify opportunities for energy savings and reduction in emissions.", + "es": "Realizar auditorías energéticas periódicas para identificar oportunidades de ahorro de energía y reducción de emisiones.", + "pt": "Realizar auditorias energéticas regulares para identificar oportunidades de economia de energia e redução de emissões." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "ippu" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": "20-39", + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0078", + "name": { + "en": "Implement green roofs and walls", + "es": "Implementar techos y muros verdes", + "pt": "Implementar telhados e paredes verdes" + }, + "description": { + "en": "The implementation of green roofs and green walls mitigates urban heat island effects, improves thermal comfort, reduces energy demand in buildings, manages stormwater, and enhances urban livability and biodiversity.", + "es": "La implementación de techos y muros verdes mitiga los efectos de la isla de calor urbana, mejora el confort térmico, reduce la demanda de energía en los edificios, gestiona las aguas pluviales y mejora la habitabilidad urbana y la biodiversidad.", + "pt": "A implementação de telhados verdes e paredes verdes mitiga os efeitos de ilha de calor urbana, melhora o conforto térmico, reduz a demanda de energia nos edifícios, gerencia a água da chuva e aumenta a habitabilidade urbana e a biodiversidade." + }, + "actionType": "adaptation", + "hazards": [ + "heatwaves", + "storms" + ], + "sectors": [ + "stationary_energy" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 0, + "housing": 0, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": "20-39", + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": null, + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "high", + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": "medium", + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0083", + "name": { + "en": "Plan strategic coastal retreat for vulnerable communities", + "es": "Planificar la retirada costera estratégica para comunidades vulnerables", + "pt": "Planejar a retirada estratégica das comunidades costeiras vulneráveis" + }, + "description": { + "en": "Planned relocation and retreat of people, assets, and activities from coastal hazard zones to reduce exposure and risks caused by sea-level rise and associated coastal hazards.", + "es": "Reubicación y retirada planificadas de personas, bienes y actividades de zonas costeras peligrosas para reducir la exposición y los riesgos causados por el aumento del nivel del mar y los peligros costeros asociados.", + "pt": "Realocação e retirada planejada de pessoas, bens e atividades das zonas costeiras de risco para reduzir a exposição e os riscos causados pela elevação do nível do mar e pelos perigos costeiros associados." + }, + "actionType": "adaptation", + "hazards": [ + "sea-level-rise", + "floods", + "storms", + "landslides" + ], + "sectors": [ + "geo-hydrological_disasters", + "public_health" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 2, + "cost_of_living": -1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": "high", + "landslides": "high", + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": ">10 years", + "biome": "coastal_marine", + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0084", + "name": { + "en": "Restore/create natural areas", + "es": "Restaurar/crear áreas naturales", + "pt": "Restaurar/criar áreas naturais" + }, + "description": { + "en": "Restoration and conservation of marine and coastal habitats, such as mangroves, vegetated dunes, seagrasses, coral reefs, and kelp forests, to protect coastal communities, support biodiversity, sequester carbon, and mitigate climate change. Efforts include creating marine protected areas, active restoration of coral reefs, ridge-to-reef management, restoring dunes, planting salinity-tolerant trees, increasing forest cover, detect and manage forest pests.", + "es": "Restauración y conservación de hábitats marinos y costeros, como manglares, dunas vegetadas, pastos marinos, arrecifes de coral y bosques de kelp, para proteger a las comunidades costeras, apoyar la biodiversidad, secuestrar carbono y mitigar el cambio climático. Los esfuerzos incluyen la creación de áreas marinas protegidas, la restauración activa de arrecifes de coral, la gestión de cuenca a arrecife, la restauración de dunas, la plantación de árboles tolerantes a la salinidad, el aumento de la cobertura forestal, la detección y el manejo de plagas forestales.", + "pt": "Restauração e conservação de habitats marinhos e costeiros, como manguezais, dunas vegetadas, pradarias marinhas, recifes de coral e florestas de kelp, para proteger comunidades costeiras, apoiar a biodiversidade, sequestrar carbono e mitigar as mudanças climáticas. Os esforços incluem a criação de áreas marinhas protegidas, restauração ativa de recifes de coral, gestão de encosta ao recife, restauração de dunas, plantio de árvores tolerantes à salinidade, aumento da cobertura florestal, detecção e manejo de pragas florestais." + }, + "actionType": "adaptation", + "hazards": [ + "sea-level-rise", + "floods", + "storms", + "droughts" + ], + "sectors": [ + "biodiversity", + "water_resources", + "geo-hydrological_disasters" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": null, + "floods": "high", + "sea-level-rise": "high", + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": "coastal_marine", + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0085", + "name": { + "en": "Reduce pressures on ecosystems to build resilience", + "es": "Reducir las presiones sobre los ecosistemas para fortalecer su resiliencia", + "pt": "Reduzir as pressões sobre os ecossistemas para aumentar a resiliência" + }, + "description": { + "en": "Reduce pollution, eutrophication, and anthropogenic pressures on natural systems, including marine and terrestrial ecosystems. Efforts include managing runoff, protecting sensitive habitats like the Great Barrier Reef, addressing non-climate drivers, promoting sustainable fisheries harvest, and increasing connectivity between natural areas to enhance ecosystem resilience.", + "es": "Reducir la contaminación, la eutrofización y las presiones antropogénicas sobre los sistemas naturales, incluidos los ecosistemas marinos y terrestres. Los esfuerzos incluyen gestionar la escorrentía, proteger hábitats sensibles como la Gran Barrera de Coral, abordar factores no climáticos, promover la pesca sostenible y aumentar la conectividad entre áreas naturales para mejorar la resiliencia de los ecosistemas.", + "pt": "Reduzir a poluição, a eutrofização e as pressões antrópicas sobre os sistemas naturais, incluindo ecossistemas marinhos e terrestres. Os esforços incluem o manejo do escoamento, a proteção de habitats sensíveis como a Grande Barreira de Coral, o enfrentamento de fatores não relacionados ao clima, a promoção da pesca sustentável e o aumento da conectividade entre áreas naturais para fortalecer a resiliência dos ecossistemas." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "floods", + "sea-level-rise", + "wildfires", + "storms" + ], + "sectors": [ + "biodiversity", + "water_resources", + "geo-hydrological_disasters" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 0, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": null, + "floods": "high", + "sea-level-rise": "high", + "landslides": null, + "storms": "high", + "wildfires": "medium", + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0086", + "name": { + "en": "Implement ecosystem‑based adaptation measures", + "es": "Implementar medidas de adaptación basadas en los ecosistemas", + "pt": "Implementar medidas de adaptação baseadas em ecossistemas" + }, + "description": { + "en": "Restoring and sustainably managing marine, coastal, urban, riverine, and wetland ecosystems to protect against climate hazards such as storm surges, floods, and heatwaves. Efforts include agroecology, coastal and marine vegetation and reefs, vegetation corridors, mangrove habitat restoration, urban green space to reduce temperatures. These actions improve biodiversity, store carbon, enhance water quality, and provide socio-economic and cultural co-benefits.", + "es": "Restaurar y gestionar de manera sostenible los ecosistemas marinos, costeros, urbanos, fluviales y de humedales para proteger contra riesgos climáticos como marejadas, inundaciones y olas de calor. Los esfuerzos incluyen la agroecología, la vegetación y los arrecifes costeros y marinos, los corredores de vegetación, la restauración de hábitats de manglares y los espacios verdes urbanos para reducir las temperaturas. Estas acciones mejoran la biodiversidad, almacenan carbono, mejoran la calidad del agua y proporcionan co-beneficios socioeconómicos y culturales.", + "pt": "Restaurar e gerir de forma sustentável os ecossistemas marinhos, costeiros, urbanos, fluviais e de zonas húmidas para proteger contra riscos climáticos como tempestades, inundações e ondas de calor. Os esforços incluem agroecologia, vegetação costeira e marinha e recifes, corredores de vegetação, restauração de habitats de manguezais, espaços verdes urbanos para reduzir as temperaturas. Essas ações melhoram a biodiversidade, armazenam carbono, aumentam a qualidade da água e proporcionam co-benefícios socioeconômicos e culturais." + }, + "actionType": "adaptation", + "hazards": [ + "storms", + "sea-level-rise", + "heatwaves", + "floods" + ], + "sectors": [ + "biodiversity", + "geo-hydrological_disasters", + "water_resources", + "public_health" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 0, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "high", + "floods": "high", + "sea-level-rise": "high", + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0087", + "name": { + "en": "Improve Infrastructure retrofitting", + "es": "Mejorar la modernización de infraestructuras", + "pt": "Melhorar a modernização da infraestrutura" + }, + "description": { + "en": "Strengthen and upgrade existing infrastructure, including roads, housing, and energy systems, to improve resilience against climate risks such as floods, droughts, and heatwaves. Efforts include using thermosiphons for permafrost degradation, increasing rooftop albedo (for reflectivity) and shading", + "es": "Fortalecer y modernizar la infraestructura existente, incluyendo carreteras, viviendas y sistemas energéticos, para mejorar la resiliencia frente a riesgos climáticos como inundaciones, sequías y olas de calor. Las acciones incluyen el uso de termosyfones para la degradación del permafrost, el aumento del albedo de los techos (para la reflectividad) y la incorporación de sombra.", + "pt": "Reforçar e modernizar a infraestrutura existente, incluindo estradas, habitações e sistemas de energia, para melhorar a resiliência contra riscos climáticos como inundações, secas e ondas de calor. Os esforços incluem o uso de termossifões para a degradação do permafrost, aumento do albedo dos telhados (para refletividade) e sombreamento." + }, + "actionType": "adaptation", + "hazards": [ + "floods", + "droughts", + "heatwaves" + ], + "sectors": [ + "road_infrastructure", + "public_health", + "energy_security" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 0, + "cost_of_living": -1, + "housing": 1, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "medium", + "heatwaves": "high", + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0088", + "name": { + "en": "Update and enforce climate‑resilient building codes", + "es": "Actualizar y hacer cumplir los códigos de construcción resilientes al clima", + "pt": "Atualizar e aplicar códigos de construção resilientes ao clima" + }, + "description": { + "en": "The development and implementation of building codes and architectural design regulations aimed at integrating climate adaptation parameters. These codes are focused on reducing risks from climate-induced hazards like floods and landslides. They also support climate-resilient urban development by guiding land use, construction practices, and infrastructure standards. The initiative fosters strategic long-term urban planning to coordinate public and private investments in adaptation, including the creation of safe zones and the transformation of precarious settlements. It ensures that new infrastructure is resilient to climate risks and that urban spaces are safe and sustainable for current and future populations.", + "es": "El desarrollo e implementación de códigos de construcción y regulaciones de diseño arquitectónico orientados a integrar parámetros de adaptación al clima. Estos códigos se enfocan en reducir los riesgos derivados de peligros climáticos como inundaciones y deslizamientos de tierra. También apoyan el desarrollo urbano resiliente al clima al guiar el uso del suelo, las prácticas de construcción y los estándares de infraestructura. La iniciativa fomenta la planificación urbana estratégica a largo plazo para coordinar inversiones públicas y privadas en adaptación, incluyendo la creación de zonas seguras y la transformación de asentamientos precarios. Garantiza que la nueva infraestructura sea resiliente a los riesgos climáticos y que los espacios urbanos sean seguros y sostenibles para las poblaciones actuales y futuras.", + "pt": "O desenvolvimento e a implementação de códigos de construção e regulamentos de design arquitetônico voltados para a integração de parâmetros de adaptação climática. Esses códigos têm como foco a redução de riscos provenientes de perigos induzidos pelo clima, como enchentes e deslizamentos de terra. Eles também apoiam o desenvolvimento urbano resiliente ao clima, orientando o uso do solo, as práticas de construção e os padrões de infraestrutura. A iniciativa promove o planejamento urbano estratégico de longo prazo para coordenar investimentos públicos e privados em adaptação, incluindo a criação de zonas seguras e a transformação de assentamentos precários. Garante que novas infraestruturas sejam resilientes aos riscos climáticos e que os espaços urbanos sejam seguros e sustentáveis para as populações atuais e futuras." + }, + "actionType": "adaptation", + "hazards": [ + "floods", + "landslides" + ], + "sectors": [ + "road_infrastructure", + "geo-hydrological_disasters" + ], + "coBenefits": { + "air_quality": 2, + "water_quality": 0, + "habitat": 1, + "cost_of_living": 1, + "housing": 2, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": "high", + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0089", + "name": { + "en": "Spatially redirect development", + "es": "Redirigir espacialmente el desarrollo", + "pt": "Redirecionar o desenvolvimento espacialmente" + }, + "description": { + "en": "Use zoning and land-use planning to regulate coastal development by implementing spatial development strategies that consider environmental vulnerabilities, protect ecosystems, and mitigate risks from flooding, heatwaves, and sea-level rise. This includes ensuring that development is directed away from high-risk areas, integrating climate adaptation considerations into urban planning, and promoting sustainable practices to close adaptation gaps while addressing urban inequality.", + "es": "Utilizar la zonificación y la planificación del uso del suelo para regular el desarrollo costero mediante la implementación de estrategias de desarrollo espacial que consideren las vulnerabilidades ambientales, protejan los ecosistemas y mitiguen los riesgos de inundaciones, olas de calor y aumento del nivel del mar. Esto incluye asegurar que el desarrollo se dirija fuera de las áreas de alto riesgo, integrar consideraciones de adaptación al clima en la planificación urbana y promover prácticas sostenibles para cerrar las brechas de adaptación mientras se aborda la desigualdad urbana.", + "pt": "Utilize o zoneamento e o planejamento do uso do solo para regular o desenvolvimento costeiro, implementando estratégias de desenvolvimento espacial que considerem as vulnerabilidades ambientais, protejam os ecossistemas e mitiguem riscos de inundações, ondas de calor e elevação do nível do mar. Isso inclui garantir que o desenvolvimento seja direcionado para longe de áreas de alto risco, integrar considerações de adaptação climática no planejamento urbano e promover práticas sustentáveis para fechar lacunas de adaptação enquanto se enfrenta a desigualdade urbana." + }, + "actionType": "adaptation", + "hazards": [ + "floods", + "heatwaves", + "sea-level-rise" + ], + "sectors": [ + "water_resources", + "food_security", + "geo-hydrological_disasters" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 1, + "habitat": 2, + "cost_of_living": -1, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": "medium", + "floods": "medium", + "sea-level-rise": "medium", + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": "coastal_marine", + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0090", + "name": { + "en": "Expand climate risk insurance coverage", + "es": "Ampliar la cobertura de seguros contra riesgos climáticos", + "pt": "Expandir a cobertura de seguros contra riscos climáticos" + }, + "description": { + "en": " Insurance provides financial risk management tools tailored to climate-induced challenges. This includes traditional agricultural insurance to protect farmers from weather-related losses and innovative index-based insurance solutions. Index-based insurance leverages measurable weather indices, such as rainfall or temperature, to trigger payouts automatically when thresholds are reached, bypassing the need for loss verification. These tools help stabilize incomes, encourage investment in climate-resilient practices, and reduce the economic vulnerability of stakeholders in agriculture, aquaculture, and energy sectors. Furthermore, bundled insurance products with additional services like fertilizer or seed access enhance overall resilience, particularly in underserved and rural communities. By mitigating risks associated with droughts, floods, and storms, insurance supports sustainable development and adaptation goals", + "es": "El seguro proporciona herramientas de gestión financiera de riesgos adaptadas a los desafíos inducidos por el clima. Esto incluye el seguro agrícola tradicional para proteger a los agricultores de pérdidas relacionadas con el clima y soluciones innovadoras de seguros basados en índices. El seguro basado en índices utiliza índices climáticos medibles, como la precipitación o la temperatura, para activar pagos automáticos cuando se alcanzan ciertos umbrales, evitando la necesidad de verificación de pérdidas. Estas herramientas ayudan a estabilizar los ingresos, fomentan la inversión en prácticas resilientes al clima y reducen la vulnerabilidad económica de los actores en los sectores agrícola, acuícola y energético. Además, los productos de seguros combinados con servicios adicionales como el acceso a fertilizantes o semillas mejoran la resiliencia general, especialmente en comunidades rurales y desatendidas. Al mitigar los riesgos asociados con sequías, inundaciones y tormentas, el seguro apoya los objetivos de desarrollo sostenible y adaptación.", + "pt": "O seguro oferece ferramentas de gestão de risco financeiro adaptadas aos desafios induzidos pelo clima. Isso inclui o seguro agrícola tradicional para proteger agricultores contra perdas relacionadas ao clima e soluções inovadoras de seguro indexado. O seguro indexado utiliza índices climáticos mensuráveis, como precipitação ou temperatura, para acionar pagamentos automaticamente quando determinados limites são atingidos, dispensando a necessidade de verificação de perdas. Essas ferramentas ajudam a estabilizar rendas, incentivar o investimento em práticas resilientes ao clima e reduzir a vulnerabilidade econômica dos envolvidos nos setores de agricultura, aquicultura e energia. Além disso, produtos de seguro combinados com serviços adicionais, como acesso a fertilizantes ou sementes, aumentam a resiliência geral, especialmente em comunidades rurais e pouco atendidas. Ao mitigar riscos associados a secas, inundações e tempestades, o seguro apoia o desenvolvimento sustentável e os objetivos de adaptação." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "floods", + "storms" + ], + "sectors": [ + "food_security", + "water_resources", + "energy_security" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 0, + "cost_of_living": -1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": null, + "floods": "medium", + "sea-level-rise": null, + "landslides": null, + "storms": "medium", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0091", + "name": { + "en": "Support livelihood diversification for climate resilience", + "es": "Apoyar la diversificación de medios de vida para la resiliencia climática", + "pt": "Apoiar a diversificação de meios de subsistência para a resiliência climática" + }, + "description": { + "en": "Promote alternative income opportunities to reduce the vulnerability of communities dependent on fisheries and mariculture. Municipal governments can facilitate training, microcredit programs, and connections to value chains that enable diversification into eco-tourism, agro-processing, crafts, and service sectors. By supporting infrastructure upgrades, skills development, and access to finance, cities can help stabilize incomes, strengthen local economies, and protect livelihoods from the impacts of shifting marine species distributions and climate variability.", + "es": "Promover oportunidades de ingresos alternativos para reducir la vulnerabilidad de las comunidades dependientes de la pesca y la maricultura. Los gobiernos municipales pueden facilitar la capacitación, programas de microcrédito y conexiones con cadenas de valor que permitan la diversificación hacia el ecoturismo, el agroprocesamiento, la artesanía y los sectores de servicios. Al apoyar la mejora de la infraestructura, el desarrollo de habilidades y el acceso a financiamiento, las ciudades pueden ayudar a estabilizar los ingresos, fortalecer las economías locales y proteger los medios de vida frente a los impactos de la variabilidad climática y la redistribución de especies marinas.", + "pt": "Promover oportunidades alternativas de renda para reduzir a vulnerabilidade de comunidades dependentes da pesca e maricultura. Os governos municipais podem facilitar treinamentos, programas de microcrédito e conexões com cadeias de valor que possibilitem a diversificação para o ecoturismo, agroprocessamento, artesanato e setores de serviços. Ao apoiar melhorias de infraestrutura, desenvolvimento de habilidades e acesso a financiamento, as cidades podem ajudar a estabilizar rendas, fortalecer as economias locais e proteger os meios de subsistência dos impactos das mudanças na distribuição de espécies marinhas e da variabilidade climática." + }, + "actionType": "adaptation", + "hazards": [ + "storms", + "sea-level-rise" + ], + "sectors": [ + "food_security", + "biodiversity" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": "high", + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": "coastal_marine", + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0092", + "name": { + "en": "Expand climate‑responsive social safety nets", + "es": "Ampliar las redes de protección social sensibles al clima", + "pt": "Expandir redes de proteção social sensíveis ao clima" + }, + "description": { + "en": "Social safety nets encompass adaptive social protection mechanisms to reduce food insecurity and malnutrition, especially for vulnerable populations. These include cash transfers, school feeding programs, public work initiatives, unemployment compensation, land reforms, credit and insurance schemes. Integrated approaches combine climate risk assessments with disaster risk reduction, education, and social equity to enhance resilience to climate stresses.", + "es": "Las redes de protección social abarcan mecanismos de protección social adaptativa para reducir la inseguridad alimentaria y la malnutrición, especialmente en las poblaciones vulnerables. Estas incluyen transferencias de efectivo, programas de alimentación escolar, iniciativas de trabajo público, compensación por desempleo, reformas agrarias, esquemas de crédito y seguros. Los enfoques integrados combinan evaluaciones de riesgo climático con reducción del riesgo de desastres, educación y equidad social para fortalecer la resiliencia frente a las tensiones climáticas.", + "pt": "Redes de proteção social abrangem mecanismos adaptativos de proteção social para reduzir a insegurança alimentar e a desnutrição, especialmente para populações vulneráveis. Isso inclui transferências de renda, programas de alimentação escolar, iniciativas de trabalho público, compensação por desemprego, reformas agrárias, esquemas de crédito e seguros. Abordagens integradas combinam avaliações de risco climático com redução de risco de desastres, educação e equidade social para aumentar a resiliência aos estresses climáticos." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "floods", + "storms" + ], + "sectors": [ + "food_security", + "public_health" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 2, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": "high", + "floods": "medium", + "sea-level-rise": null, + "landslides": null, + "storms": "medium", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0094", + "name": { + "en": "Strengthen climate‑resilient health services", + "es": "Fortalecer los servicios de salud resilientes al clima", + "pt": "Fortalecer os serviços de saúde resilientes ao clima" + }, + "description": { + "en": "Enhancing access to health care services, including health and nutrition services, clean water, sanitation, and culturally appropriate mental health resources. Expanding telemedicine capabilities enables efficient health service delivery, particularly for remote and underserved populations. Strengthening basic public health systems and disaster preparedness can rapidly reduce vulnerability to climate-related health risks.", + "es": "Mejorar el acceso a los servicios de atención médica, incluyendo servicios de salud y nutrición, agua limpia, saneamiento y recursos de salud mental culturalmente apropiados. Ampliar las capacidades de la telemedicina permite una prestación eficiente de servicios de salud, especialmente para poblaciones remotas y desatendidas. Fortalecer los sistemas básicos de salud pública y la preparación ante desastres puede reducir rápidamente la vulnerabilidad a los riesgos para la salud relacionados con el clima.", + "pt": "Aumentar o acesso a serviços de saúde, incluindo serviços de saúde e nutrição, água potável, saneamento e recursos de saúde mental culturalmente apropriados. Expandir as capacidades de telemedicina permite uma prestação eficiente de serviços de saúde, especialmente para populações remotas e carentes. Fortalecer os sistemas básicos de saúde pública e a preparação para desastres pode reduzir rapidamente a vulnerabilidade a riscos de saúde relacionados ao clima." + }, + "actionType": "adaptation", + "hazards": [ + "heatwaves", + "floods", + "droughts" + ], + "sectors": [ + "public_health", + "water_resources" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 0, + "cost_of_living": 1, + "housing": 1, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": "high", + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0096", + "name": { + "en": "Strengthen climate resilience in farming and fisheries", + "es": "Fortalecer la resiliencia climática en la agricultura y la pesca", + "pt": "Reforçar a resiliência climática na agricultura e na pesca" + }, + "description": { + "en": "Support the adoption of climate-smart agricultural and aquaculture practices by creating enabling conditions for farmers and fishers. Municipal governments can promote improved breeds, feed, and fertilizers, enhance irrigation efficiency, and foster aquaculture resilience through extension services, research partnerships, and targeted procurement. By offering incentives, technical assistance, and facilitating access to innovation and finance, cities can help producers adopt agroecological systems, diversify crops, and strengthen sustainable practices that build resilience to climate impacts.", + "es": "Apoyar la adopción de prácticas agrícolas y acuícolas inteligentes frente al clima mediante la creación de condiciones favorables para agricultores y pescadores. Los gobiernos municipales pueden promover razas mejoradas, piensos y fertilizantes, mejorar la eficiencia del riego y fomentar la resiliencia de la acuicultura a través de servicios de extensión, alianzas de investigación y adquisiciones específicas. Al ofrecer incentivos, asistencia técnica y facilitar el acceso a la innovación y la financiación, las ciudades pueden ayudar a los productores a adoptar sistemas agroecológicos, diversificar cultivos y fortalecer prácticas sostenibles que aumenten la resiliencia frente a los impactos climáticos.", + "pt": "Apoiar a adoção de práticas agrícolas e aquícolas inteligentes para o clima, criando condições favoráveis para agricultores e pescadores. Os governos municipais podem promover raças, rações e fertilizantes melhorados, aumentar a eficiência da irrigação e fortalecer a resiliência da aquicultura por meio de serviços de extensão, parcerias de pesquisa e compras direcionadas. Ao oferecer incentivos, assistência técnica e facilitar o acesso à inovação e ao financiamento, as cidades podem ajudar os produtores a adotar sistemas agroecológicos, diversificar culturas e fortalecer práticas sustentáveis que aumentam a resiliência aos impactos climáticos." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "floods", + "wildfires", + "storms" + ], + "sectors": [ + "food_security", + "biodiversity", + "water_resources" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": "high", + "floods": "medium", + "sea-level-rise": null, + "landslides": null, + "storms": "medium", + "wildfires": "low", + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0097", + "name": { + "en": "Upgrade food storage and distribution for climate resilience", + "es": "Mejorar el almacenamiento y la distribución de alimentos para la resiliencia climática", + "pt": "Aprimorar o armazenamento e a distribuição de alimentos para resiliência climática" + }, + "description": { + "en": "Strengthen local food systems by improving storage and distribution infrastructure to reduce losses and enhance resilience to climate impacts. Municipal governments can invest in public facilities such as cool storage units, silos, and warehouses, while upgrading logistics to handle perishable goods more efficiently. By supporting local markets, optimizing distribution networks, and facilitating access to reliable storage for producers and vendors, cities can improve food security, reduce waste, and ensure stable food availability during crises and extreme events.", + "es": "Fortalecer los sistemas alimentarios locales mejorando la infraestructura de almacenamiento y distribución para reducir pérdidas y aumentar la resiliencia frente a los impactos climáticos. Los gobiernos municipales pueden invertir en instalaciones públicas como cámaras frigoríficas, silos y almacenes, al mismo tiempo que modernizan la logística para manejar productos perecederos de manera más eficiente. Al apoyar los mercados locales, optimizar las redes de distribución y facilitar el acceso a almacenamiento confiable para productores y vendedores, las ciudades pueden mejorar la seguridad alimentaria, reducir el desperdicio y garantizar la disponibilidad estable de alimentos durante crisis y eventos extremos.", + "pt": "Fortalecer os sistemas alimentares locais melhorando a infraestrutura de armazenamento e distribuição para reduzir perdas e aumentar a resiliência aos impactos climáticos. Os governos municipais podem investir em instalações públicas como unidades de armazenamento refrigerado, silos e armazéns, além de modernizar a logística para lidar com produtos perecíveis de forma mais eficiente. Ao apoiar mercados locais, otimizar redes de distribuição e facilitar o acesso a armazenamento confiável para produtores e vendedores, as cidades podem melhorar a segurança alimentar, reduzir o desperdício e garantir a disponibilidade estável de alimentos durante crises e eventos extremos." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "floods", + "storms", + "heatwaves" + ], + "sectors": [ + "food_security", + "road_infrastructure" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 2, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": "high", + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0098", + "name": { + "en": "Increase resilience by improving access to food, improving livelihoods and promoting dietary shifts and food waste reduction", + "es": "Aumentar la resiliencia mejorando el acceso a los alimentos, mejorando los medios de vida y promoviendo cambios en la dieta y la reducción del desperdicio de alimentos", + "pt": "Aumentar a resiliência melhorando o acesso à alimentação, melhorando os meios de subsistência e promovendo mudanças nos hábitos alimentares e a redução do desperdício de alimentos" + }, + "description": { + "en": "Increase resilience through improved food production, distribution, and consumption practices. Actions include enhancing agricultural techniques, adopting water-saving technologies, implementing low-cost storage solutions, and promoting plant-based diets. Policymakers can encourage these behaviors with appropriate pricing policies, sustainable agriculture initiatives, and support for disadvantaged groups. The action emphasizes shifting to healthier diets, reducing overconsumption, and supporting local food systems to mitigate greenhouse gas emissions and ensure food security under climate change.", + "es": "Aumentar la resiliencia mediante la mejora de las prácticas de producción, distribución y consumo de alimentos. Las acciones incluyen mejorar las técnicas agrícolas, adoptar tecnologías de ahorro de agua, implementar soluciones de almacenamiento de bajo costo y promover dietas basadas en plantas. Los responsables de la formulación de políticas pueden fomentar estos comportamientos mediante políticas de precios adecuadas, iniciativas de agricultura sostenible y apoyo a los grupos desfavorecidos. La acción enfatiza el cambio hacia dietas más saludables, la reducción del sobreconsumo y el apoyo a los sistemas alimentarios locales para mitigar las emisiones de gases de efecto invernadero y garantizar la seguridad alimentaria frente al cambio climático.", + "pt": "Aumentar a resiliência por meio da melhoria das práticas de produção, distribuição e consumo de alimentos. As ações incluem aprimorar técnicas agrícolas, adotar tecnologias de economia de água, implementar soluções de armazenamento de baixo custo e promover dietas à base de plantas. Os formuladores de políticas podem incentivar esses comportamentos com políticas de preços adequadas, iniciativas de agricultura sustentável e apoio a grupos desfavorecidos. A ação enfatiza a transição para dietas mais saudáveis, a redução do consumo excessivo e o apoio a sistemas alimentares locais para mitigar as emissões de gases de efeito estufa e garantir a segurança alimentar diante das mudanças climáticas." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves", + "floods", + "wildfires" + ], + "sectors": [ + "food_security", + "biodiversity" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": "medium", + "floods": "medium", + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": "low", + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0099", + "name": { + "en": "Increase Water Capture and Storage", + "es": "Aumentar la captación y el almacenamiento de agua", + "pt": "Aumentar a Captação e Armazenamento de Água" + }, + "description": { + "en": "Implementation of water harvesting and storage solutions, such as on-farm ponds, water body revitalization, rain gardens, bioswales, retention ponds, pumped storage, and water storage tanks. These measures aim to mitigate climate-induced impacts by improving water management, reducing stormwater runoff, improving water quality, and supporting agriculture and energy production in changing climate scenarios. Water reservoirs and multipurpose dams offer additional benefits by addressing water scarcity and managing risks associated with natural disasters. These adaptation strategies contribute to sustainable water use and resilience to climate-related challenges.", + "es": "Implementación de soluciones para la captación y almacenamiento de agua, como estanques en las fincas, revitalización de cuerpos de agua, jardines de lluvia, bioswales, estanques de retención, almacenamiento por bombeo y tanques de almacenamiento de agua. Estas medidas tienen como objetivo mitigar los impactos inducidos por el clima mediante la mejora de la gestión del agua, la reducción de la escorrentía de aguas pluviales, la mejora de la calidad del agua y el apoyo a la agricultura y la producción de energía en escenarios de cambio climático. Los embalses y las represas multipropósito ofrecen beneficios adicionales al abordar la escasez de agua y gestionar los riesgos asociados con desastres naturales. Estas estrategias de adaptación contribuyen al uso sostenible del agua y a la resiliencia frente a los desafíos relacionados con el clima.", + "pt": "Implementação de soluções para captação e armazenamento de água, como açudes em propriedades rurais, revitalização de corpos d’água, jardins de chuva, valas de biossistemas, lagoas de retenção, armazenamento bombeado e reservatórios de água. Essas medidas visam mitigar os impactos induzidos pelo clima por meio da melhoria da gestão da água, redução do escoamento de águas pluviais, melhoria da qualidade da água e apoio à agricultura e à produção de energia em cenários de mudanças climáticas. Reservatórios de água e barragens multipropósito oferecem benefícios adicionais ao enfrentar a escassez de água e gerenciar riscos associados a desastres naturais. Essas estratégias de adaptação contribuem para o uso sustentável da água e para a resiliência diante dos desafios relacionados ao clima." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "floods", + "storms" + ], + "sectors": [ + "water_resources", + "food_security", + "energy_security", + "geo-hydrological_disasters" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 1, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0100", + "name": { + "en": "Improve Efficient water use/demand", + "es": "Mejorar el uso eficiente del agua y la demanda", + "pt": "Melhorar o uso/consumo eficiente de água" + }, + "description": { + "en": "Implementing advanced irrigation techniques such as precision and drip irrigation to enhance water use efficiency in agriculture. Managed Aquifer Recharge (MAR) is applied to replenish groundwater supplies using stormwater, treated wastewater, or other sources. These actions are complemented by cooperative policies across multiple sectors to ensure sustainable water resource management, equitable access, and regional collaboration. Additionally, promoting changes in water consumption patterns, such as reducing waste and improving efficiency in urban and agricultural water use, supports resilience against water scarcity and enhances adaptive capacity in vulnerable regions. These efforts collectively aim to address the growing demand for freshwater in the face of climate change and ensure long-term sustainability.", + "es": "Implementar técnicas avanzadas de riego, como el riego de precisión y el riego por goteo, para mejorar la eficiencia en el uso del agua en la agricultura. La Recarga Gestionada de Acuíferos (MAR) se aplica para reponer los suministros de agua subterránea utilizando aguas pluviales, aguas residuales tratadas u otras fuentes. Estas acciones se complementan con políticas de cooperación entre múltiples sectores para garantizar una gestión sostenible de los recursos hídricos, el acceso equitativo y la colaboración regional. Además, promover cambios en los patrones de consumo de agua, como la reducción del desperdicio y la mejora de la eficiencia en el uso del agua urbana y agrícola, apoya la resiliencia frente a la escasez de agua y mejora la capacidad de adaptación en regiones vulnerables. Estos esfuerzos en conjunto buscan abordar la creciente demanda de agua dulce ante el cambio climático y garantizar la sostenibilidad a largo plazo.", + "pt": "Implementação de técnicas avançadas de irrigação, como irrigação de precisão e por gotejamento, para aumentar a eficiência do uso da água na agricultura. A Recarga Gerenciada de Aquíferos (MAR) é aplicada para reabastecer os lençóis freáticos utilizando águas pluviais, águas residuais tratadas ou outras fontes. Essas ações são complementadas por políticas cooperativas entre múltiplos setores para garantir a gestão sustentável dos recursos hídricos, o acesso equitativo e a colaboração regional. Além disso, a promoção de mudanças nos padrões de consumo de água, como a redução do desperdício e a melhoria da eficiência no uso da água urbana e agrícola, apoia a resiliência contra a escassez de água e aumenta a capacidade adaptativa em regiões vulneráveis. Esses esforços, em conjunto, visam atender à crescente demanda por água doce diante das mudanças climáticas e garantir a sustentabilidade a longo prazo." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "heatwaves" + ], + "sectors": [ + "water_resources", + "food_security" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 2, + "habitat": 1, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": "medium", + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0101", + "name": { + "en": "Improve urban water management", + "es": "Mejorar la gestión urbana del agua", + "pt": "Melhorar a gestão urbana da água" + }, + "description": { + "en": "Implementing sustainable water supply systems by constructing irrigation infrastructure, promoting inter-basin water transfers, utilizing nature-based solutions (NBS) such as rain gardens, bioswales, and wetlands, and integrating advanced techniques like water reuse and water upgrading. Water reuse involves treating and recycling wastewater for non-potable or potable purposes, while water upgrading focuses on improving the quality of available water for diverse uses. These approaches enhance stormwater infiltration, improve urban water management, increase drought resilience, and support groundwater recharge. They provide energy-efficient and economical water solutions while maintaining sustainable urban development.", + "es": "Implementar sistemas sostenibles de suministro de agua mediante la construcción de infraestructuras de riego, la promoción de transferencias de agua entre cuencas, la utilización de soluciones basadas en la naturaleza (NBS) como jardines de lluvia, bioswales y humedales, e integrando técnicas avanzadas como la reutilización y mejora del agua. La reutilización del agua implica tratar y reciclar aguas residuales para fines no potables o potables, mientras que la mejora del agua se centra en mejorar la calidad del agua disponible para diversos usos. Estos enfoques mejoran la infiltración de aguas pluviales, optimizan la gestión urbana del agua, aumentan la resiliencia ante la sequía y apoyan la recarga de acuíferos. Proporcionan soluciones de agua eficientes en energía y económicas, al tiempo que mantienen un desarrollo urbano sostenible.", + "pt": "Implementação de sistemas sustentáveis de abastecimento de água por meio da construção de infraestrutura de irrigação, promoção de transferências interbacias, utilização de soluções baseadas na natureza (NBS), como jardins de chuva, valas de biossistemas e áreas úmidas, além da integração de técnicas avançadas como reúso e aprimoramento da água. O reúso da água envolve o tratamento e reciclagem de águas residuais para fins não potáveis ou potáveis, enquanto o aprimoramento da água foca na melhoria da qualidade da água disponível para diversos usos. Essas abordagens aumentam a infiltração de águas pluviais, melhoram a gestão urbana da água, aumentam a resiliência à seca e apoiam a recarga de aquíferos. Elas proporcionam soluções hídricas econômicas e energeticamente eficientes, mantendo o desenvolvimento urbano sustentável." + }, + "actionType": "adaptation", + "hazards": [ + "droughts", + "floods", + "storms" + ], + "sectors": [ + "water_resources" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 2, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "high", + "heatwaves": null, + "floods": "high", + "sea-level-rise": null, + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Projects & Physical Actions", + "keyImpacts": null + }, + { + "actionId": "ipcc_0102", + "name": { + "en": "Facilitate seasonal and temporary mobility strategies", + "es": "Facilitar estrategias de movilidad estacional y temporal", + "pt": "Facilitar estratégias de mobilidade sazonal e temporária" + }, + "description": { + "en": "Facilitating mobility of fishing fleets and workers to adapt to shifting marine species distributions caused by climate change. This includes enabling seasonal or temporary migration to align with the availability of resources, improving infrastructure and technology to support mobility, and fostering flexible governance to manage transboundary resources sustainably. These actions aim to maintain livelihoods and reduce economic impacts of climate variability.", + "es": "Facilitar la movilidad de las flotas pesqueras y los trabajadores para adaptarse a la redistribución de especies marinas causada por el cambio climático. Esto incluye permitir la migración estacional o temporal para alinearse con la disponibilidad de recursos, mejorar la infraestructura y la tecnología para apoyar la movilidad, y fomentar una gobernanza flexible para gestionar los recursos transfronterizos de manera sostenible. Estas acciones tienen como objetivo mantener los medios de vida y reducir los impactos económicos de la variabilidad climática.", + "pt": "Facilitar a mobilidade das frotas de pesca e dos trabalhadores para se adaptarem às mudanças na distribuição das espécies marinhas causadas pelas alterações climáticas. Isso inclui permitir a migração sazonal ou temporária para alinhar com a disponibilidade de recursos, melhorar a infraestrutura e a tecnologia para apoiar a mobilidade, e promover uma governança flexível para gerir os recursos transfronteiriços de forma sustentável. Essas ações visam manter os meios de subsistência e reduzir os impactos econômicos da variabilidade climática." + }, + "actionType": "adaptation", + "hazards": [ + "sea-level-rise", + "storms", + "droughts" + ], + "sectors": [ + "food_security", + "biodiversity" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 2, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": "low", + "heatwaves": null, + "floods": null, + "sea-level-rise": "medium", + "landslides": null, + "storms": "medium", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": "coastal_marine", + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0103", + "name": { + "en": "Strengthen cooperative climate governance", + "es": "Fortalecer la gobernanza climática cooperativa", + "pt": "Reforçar a governança climática cooperativa" + }, + "description": { + "en": "Enhancing cooperative governance through transboundary fishing agreements and inclusive ocean governance. This involves participatory approaches, structured decision-making tools, and decentralized frameworks that couple top-down management with community-driven initiatives. Additional strategies include collective water management systems to optimize resource use under climate-induced variability, indigenous water-sharing systems rooted in traditional practices to ensure sustainable and equitable resource allocation, and enforcing the land rights of Indigenous populations to protect biodiversity and cultural heritage. Adaptive co-management in Arctic fisheries integrates local and scientific knowledge to address climate impacts on marine resources. The international compact on migration fosters orderly and safe migration as an adaptive response to climate risks, and policies for adaptive governance promote ecosystem-based solutions, legal frameworks, and institutional adaptations to enhance resilience to climate change. These combined measures address geopolitical complexities, ensure equitable resource distribution, and strengthen resilience to climate-induced hazards.", + "es": "Mejorar la gobernanza cooperativa mediante acuerdos de pesca transfronterizos y una gobernanza oceánica inclusiva. Esto implica enfoques participativos, herramientas estructuradas de toma de decisiones y marcos descentralizados que combinan la gestión de arriba hacia abajo con iniciativas impulsadas por la comunidad. Otras estrategias incluyen sistemas colectivos de gestión del agua para optimizar el uso de los recursos ante la variabilidad inducida por el clima, sistemas indígenas de reparto de agua basados en prácticas tradicionales para garantizar una asignación sostenible y equitativa de los recursos, y la aplicación de los derechos territoriales de las poblaciones indígenas para proteger la biodiversidad y el patrimonio cultural. La co-gestión adaptativa en las pesquerías del Ártico integra el conocimiento local y científico para abordar los impactos climáticos en los recursos marinos. El pacto internacional sobre migración fomenta una migración ordenada y segura como respuesta adaptativa a los riesgos climáticos, y las políticas de gobernanza adaptativa promueven soluciones basadas en los ecosistemas, marcos legales y adaptaciones institucionales para fortalecer la resiliencia frente al cambio climático. Estas medidas combinadas abordan las complejidades geopolíticas, aseguran una distribución equitativa de los recursos y refuerzan la resiliencia ante los peligros inducidos por el clima.", + "pt": "Aprimorar a governança cooperativa por meio de acordos de pesca transfronteiriços e governança oceânica inclusiva. Isso envolve abordagens participativas, ferramentas estruturadas de tomada de decisão e estruturas descentralizadas que combinam a gestão de cima para baixo com iniciativas impulsionadas pela comunidade. Estratégias adicionais incluem sistemas coletivos de gestão da água para otimizar o uso dos recursos diante da variabilidade induzida pelo clima, sistemas indígenas de compartilhamento de água baseados em práticas tradicionais para garantir uma alocação sustentável e equitativa dos recursos, e a aplicação dos direitos territoriais das populações indígenas para proteger a biodiversidade e o patrimônio cultural. A co-gestão adaptativa nas pescarias do Ártico integra conhecimentos locais e científicos para enfrentar os impactos climáticos sobre os recursos marinhos. O pacto internacional sobre migração promove uma migração ordenada e segura como resposta adaptativa aos riscos climáticos, e políticas de governança adaptativa promovem soluções baseadas em ecossistemas, marcos legais e adaptações institucionais para aumentar a resiliência às mudanças climáticas. Essas medidas combinadas abordam complexidades geopolíticas, garantem uma distribuição equitativa dos recursos e fortalecem a resiliência a riscos induzidos pelo clima." + }, + "actionType": "adaptation", + "hazards": [ + "sea-level-rise", + "storms" + ], + "sectors": [ + "water_resources", + "biodiversity" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 2, + "cost_of_living": 1, + "housing": 0, + "mobility": 0, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "high", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": "high", + "landslides": null, + "storms": "high", + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0104", + "name": { + "en": "Plan and support permanent climate‑related migration", + "es": "Planificar y apoyar la migración permanente relacionada con el clima", + "pt": "Planejar e apoiar a migração permanente relacionada ao clima" + }, + "description": { + "en": "Resettlement of communities from flood-prone areas and rural–urban migration as a strategy to mitigate vulnerabilities caused by climate change. This includes addressing urbanization challenges, such as unplanned development, water insecurity, and socioeconomic disparities, while providing equitable opportunities for migrants in urban centers. Measures include enhancing urban planning, water resource management, and social support systems for displaced populations.", + "es": "Reasentamiento de comunidades de zonas propensas a inundaciones y migración rural-urbana como estrategia para mitigar las vulnerabilidades causadas por el cambio climático. Esto incluye abordar los desafíos de la urbanización, como el desarrollo no planificado, la inseguridad hídrica y las disparidades socioeconómicas, al tiempo que se brindan oportunidades equitativas para los migrantes en los centros urbanos. Las medidas incluyen mejorar la planificación urbana, la gestión de los recursos hídricos y los sistemas de apoyo social para las poblaciones desplazadas.", + "pt": "Reassentamento de comunidades de áreas propensas a inundações e migração rural-urbana como estratégia para mitigar vulnerabilidades causadas pelas mudanças climáticas. Isso inclui enfrentar desafios da urbanização, como desenvolvimento não planejado, insegurança hídrica e disparidades socioeconômicas, ao mesmo tempo em que se proporcionam oportunidades equitativas para migrantes em centros urbanos. As medidas incluem o aprimoramento do planejamento urbano, gestão de recursos hídricos e sistemas de apoio social para populações deslocadas." + }, + "actionType": "adaptation", + "hazards": [ + "floods", + "landslides", + "sea-level-rise" + ], + "sectors": [ + "geo-hydrological_disasters", + "public_health", + "water_resources" + ], + "coBenefits": { + "air_quality": 0, + "water_quality": 1, + "habitat": 1, + "cost_of_living": -1, + "housing": -1, + "mobility": 1, + "stakeholder_engagement": 2 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": null, + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": "high", + "sea-level-rise": "medium", + "landslides": "medium", + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "high", + "timeline": "5-10 years", + "biome": null, + "category": "Policies, Plans & Programs", + "keyImpacts": null + }, + { + "actionId": "ipcc_0105", + "name": { + "en": "Promote active mobility through road space reallocation", + "es": "Promover la movilidad activa mediante la reasignación del espacio vial", + "pt": "Promover mobilidade ativa através da realocação do espaço viário" + }, + "description": { + "en": "Promotes walking and cycling by reallocating road space from cars to active and sustainable modes on a permanent basis. Measures include developing pedestrian pathways, protected cycling infrastructure, green corridors, and universal accessibility improvements. By prioritizing active mobility, cities enhance public health, equity, and resilience while reducing emissions from private vehicles.", + "es": "Promueve caminar y andar en bicicleta mediante la reasignación permanente del espacio vial de los automóviles a modos activos y sostenibles. Las medidas incluyen el desarrollo de senderos peatonales, infraestructura ciclista protegida, corredores verdes y mejoras de accesibilidad universal. Al priorizar la movilidad activa, las ciudades mejoran la salud pública, la equidad y la resiliencia mientras reducen las emisiones de vehículos privados.", + "pt": "Promove a caminhada e o uso da bicicleta por meio da realocação permanente do espaço viário dos carros para modos ativos e sustentáveis. As medidas incluem o desenvolvimento de calçadas e passeios, infraestrutura cicloviária protegida, corredores verdes e melhorias de acessibilidade universal. Ao priorizar a mobilidade ativa, as cidades melhoram a saúde pública, a equidade e a resiliência, enquanto reduzem as emissões de veículos particulares." + }, + "actionType": "mitigation", + "hazards": [], + "sectors": [ + "transportation" + ], + "coBenefits": { + "air_quality": 1, + "water_quality": 0, + "habitat": 0, + "cost_of_living": 0, + "housing": 0, + "mobility": 1, + "stakeholder_engagement": 1 + }, + "ghgReductionPotential": { + "stationary_energy": null, + "transportation": "20-39", + "waste": null, + "ippu": null, + "afolu": null + }, + "adaptationEffectiveness": "medium", + "adaptationPerHazard": { + "droughts": null, + "heatwaves": null, + "floods": null, + "sea-level-rise": null, + "landslides": null, + "storms": null, + "wildfires": null, + "diseases": null + }, + "cost": "medium", + "timeline": "<5 years", + "biome": null, + "category": null, + "keyImpacts": null + } +]; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.ts new file mode 100644 index 0000000..0cf7785 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/climateActions.ts @@ -0,0 +1,56 @@ +// CityCatalyst HIAP action library — type + re-export of the baked data. +// The data is fetched once and committed (see scripts/fetch-climate-actions.mjs); +// per-city prioritization happens in src/app/lib/prioritize.ts. + +export type Lang = "en" | "es" | "pt"; +export type LangString = Record; + +export type HazardKey = + | "droughts" + | "heatwaves" + | "floods" + | "sea-level-rise" + | "landslides" + | "storms" + | "wildfires" + | "diseases"; + +export type GhgSectorKey = + | "stationary_energy" + | "transportation" + | "waste" + | "ippu" + | "afolu"; + +export type Effectiveness = "low" | "medium" | "high"; + +export type CoBenefits = Partial<{ + air_quality: number; + water_quality: number; + habitat: number; + cost_of_living: number; + housing: number; + mobility: number; + stakeholder_engagement: number; // the "fundable" civic-participation co-benefit +}>; + +export type ClimateAction = { + actionId: string; + name: LangString; + description: LangString; + actionType: "mitigation" | "adaptation"; + hazards: HazardKey[]; + sectors: string[]; // GHG sectors + adaptation sectors (e.g. water_resources) + coBenefits: CoBenefits; + // Per-sector % reduction range as a string, e.g. "20-39", or null. + ghgReductionPotential: Partial>; + adaptationEffectiveness: Effectiveness | null; + adaptationPerHazard: Partial>; + cost: string | null; // "low" | "medium" | "high" + timeline: string | null; // e.g. "<5 years" + biome: string | null; + category: string | null; + keyImpacts: string | null; +}; + +export { climateActions } from "./climateActions.generated"; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/engagement.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/engagement.ts new file mode 100644 index 0000000..57de863 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/engagement.ts @@ -0,0 +1,122 @@ +// Curated, LATAM-first civic engagement opportunities per city (the "Engage" +// layer). LATAM lacks clean civic APIs (Open311/Legistar are US-centric), so +// these are hand-curated and honestly flagged `needs_local_validation` until a +// local partner confirms the current link/contact — adopting the data contract +// from the parallel team's branch. + +import type { LangString } from "./climateActions"; + +export type CitizenActionKind = "attend_meeting" | "submit_feedback" | "join_group"; +export type Difficulty = "easy" | "moderate" | "committed"; + +export type CitizenAction = { + kind: CitizenActionKind; + label: LangString; + difficulty: Difficulty; +}; + +export type EngagementOpportunity = { + id: string; + title: LangString; + description: LangString; + citizenActions: CitizenAction[]; + url?: string; + needs_local_validation: boolean; +}; + +const join = (en: string, es: string, pt: string, difficulty: Difficulty): CitizenAction => ({ + kind: "join_group", + label: { en, es, pt }, + difficulty, +}); +const attend = (en: string, es: string, pt: string, difficulty: Difficulty): CitizenAction => ({ + kind: "attend_meeting", + label: { en, es, pt }, + difficulty, +}); +const feedback = (en: string, es: string, pt: string, difficulty: Difficulty): CitizenAction => ({ + kind: "submit_feedback", + label: { en, es, pt }, + difficulty, +}); + +export const engagementByCity: Record = { + "sao-paulo": [ + { + id: "sp-cades", + title: { + en: "Municipal Council for the Environment (CADES)", + es: "Consejo Municipal de Medio Ambiente (CADES)", + pt: "Conselho Municipal do Meio Ambiente (CADES)", + }, + description: { + en: "São Paulo's environmental council holds public sessions where residents can follow and influence climate and green-area decisions.", + es: "El consejo ambiental de São Paulo realiza sesiones públicas donde los vecinos pueden seguir e influir en decisiones climáticas.", + pt: "O conselho ambiental de São Paulo realiza sessões públicas onde moradores podem acompanhar e influenciar decisões climáticas.", + }, + citizenActions: [ + attend("Attend a public council session", "Asistir a una sesión pública", "Participar de uma sessão pública", "moderate"), + feedback("Submit a comment on a green-area proposal", "Comentar una propuesta de área verde", "Comentar uma proposta de área verde", "easy"), + ], + needs_local_validation: true, + }, + ], + "rio-de-janeiro": [ + { + id: "rio-reflorestamento", + title: { + en: "Community Reforestation crews (Mutirão de Reflorestamento)", + es: "Brigadas comunitarias de reforestación", + pt: "Mutirão Comunitário de Reflorestamento", + }, + description: { + en: "Rio contracts and trains residents to replant landslide-prone hillsides — a direct way to act on the city's flood and landslide risk.", + es: "Río contrata y capacita a vecinos para reforestar laderas — una forma directa de actuar ante el riesgo de deslizamientos.", + pt: "O Rio contrata e capacita moradores para reflorestar encostas — uma forma direta de agir sobre o risco de deslizamentos.", + }, + citizenActions: [ + join("Join a hillside reforestation crew", "Unirse a una brigada de reforestación", "Entrar em um mutirão de reflorestamento", "committed"), + ], + needs_local_validation: true, + }, + ], + curitiba: [ + { + id: "cwb-cambio-verde", + title: { + en: "Green Exchange (Câmbio Verde)", + es: "Cambio Verde (Câmbio Verde)", + pt: "Câmbio Verde", + }, + description: { + en: "Bring sorted recyclables to a neighborhood station and swap them for fresh produce — the backbone of Curitiba's citizen recycling.", + es: "Lleva reciclables separados a una estación de barrio y cámbialos por alimentos frescos.", + pt: "Leve recicláveis separados a uma estação do bairro e troque por alimentos frescos.", + }, + citizenActions: [ + join("Take recyclables to a Green Exchange point", "Llevar reciclables a un punto de Cambio Verde", "Levar recicláveis a um ponto do Câmbio Verde", "easy"), + ], + needs_local_validation: true, + }, + ], + "porto-alegre": [ + { + id: "poa-orcamento", + title: { + en: "Participatory Budgeting (Orçamento Participativo)", + es: "Presupuesto Participativo (Orçamento Participativo)", + pt: "Orçamento Participativo", + }, + description: { + en: "The city that invented participatory budgeting lets residents vote on real spending — propose or back a climate or drainage project.", + es: "La ciudad que inventó el presupuesto participativo permite votar el gasto real — propone o apoya un proyecto climático.", + pt: "A cidade que inventou o orçamento participativo deixa moradores votarem gastos reais — proponha ou apoie um projeto climático.", + }, + citizenActions: [ + attend("Attend a neighborhood budget assembly", "Asistir a una asamblea de presupuesto", "Participar de uma assembleia do orçamento", "moderate"), + feedback("Propose a climate or drainage project", "Proponer un proyecto climático o de drenaje", "Propor um projeto climático ou de drenagem", "moderate"), + ], + needs_local_validation: true, + }, + ], +}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx index b6ceda4..bc04510 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx @@ -1,5 +1,7 @@ import type { Metadata } from "next"; import "./globals.css"; +import { CarbonProvider } from "./lib/carbonContext"; +import CarbonCounter from "./components/CarbonCounter"; export const metadata: Metadata = { title: "Civic Climate Action — Your City, Your Move", @@ -10,7 +12,12 @@ export const metadata: Metadata = { export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - {children} + + + {children} + + + ); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/carbonContext.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/carbonContext.tsx new file mode 100644 index 0000000..5524c5c --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/carbonContext.tsx @@ -0,0 +1,37 @@ +"use client"; + +import { createContext, useCallback, useContext, useMemo, useState } from "react"; + +type Carbon = { + totalGramsCO2e: number; + totalWh: number; + callCount: number; + addUsage: (gCO2e: number, energyWh: number) => void; +}; + +const CarbonCtx = createContext(null); + +export function CarbonProvider({ children }: { children: React.ReactNode }) { + const [totalGramsCO2e, setG] = useState(0); + const [totalWh, setWh] = useState(0); + const [callCount, setCount] = useState(0); + + const addUsage = useCallback((g: number, wh: number) => { + setG((p) => p + (g || 0)); + setWh((p) => p + (wh || 0)); + setCount((p) => p + 1); + }, []); + + const value = useMemo( + () => ({ totalGramsCO2e, totalWh, callCount, addUsage }), + [totalGramsCO2e, totalWh, callCount, addUsage] + ); + + return {children}; +} + +export function useCarbon(): Carbon { + const ctx = useContext(CarbonCtx); + if (!ctx) throw new Error("useCarbon must be used within "); + return ctx; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts new file mode 100644 index 0000000..9f04a31 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts @@ -0,0 +1,45 @@ +// Map a city's hazard / sector strings onto CityCatalyst's canonical keys. +// +// Hazard names are bimodal: the 4 CityCatalyst (Brazilian) hero cities use +// canonical names ("Heatwaves", "Landslides", "Floods", "Diseases") that hit the +// keyword rules cleanly; the 11 external cities use prose ("Storm surge & +// sea-level rise", "Water shortage & drought") that may map to several keys. + +import type { HazardKey, GhgSectorKey } from "../data/climateActions"; + +// Ordered keyword → hazard rules. A single input may match several. +const HAZARD_RULES: [RegExp, HazardKey][] = [ + [/drought|water shortage|water scarcity|water stress/, "droughts"], + [/heat|overheat/, "heatwaves"], + [/sea[-\s]?level|coastal|storm surge|tidal/, "sea-level-rise"], + [/flood|cloudburst|rain|stormwater|deluge|inundation/, "floods"], + [/landslide|mudslide|mudflow/, "landslides"], + [/storm|cyclone|hurricane|wind/, "storms"], + [/wildfire|forest fire|bushfire|dieback|fire/, "wildfires"], + [/disease|vector|epidemic|dengue|malaria/, "diseases"], +]; + +export function normalizeHazard(input: string): HazardKey[] { + const s = input.toLowerCase(); + const out = new Set(); + for (const [re, key] of HAZARD_RULES) { + if (re.test(s)) out.add(key); + } + return [...out]; +} + +const SECTOR_RULES: [RegExp, GhgSectorKey][] = [ + [/transport|mobility|road|vehicle/, "transportation"], + [/stationary|energy|building|electric|power|heat\b/, "stationary_energy"], + [/waste|landfill|wastewater|sanitation/, "waste"], + [/ippu|industrial process|industry|cement|manufactur/, "ippu"], + [/afolu|land use|land-use|forest|agricultur|livestock/, "afolu"], +]; + +export function normalizeSector(input: string): GhgSectorKey | null { + const s = input.toLowerCase(); + for (const [re, key] of SECTOR_RULES) { + if (re.test(s)) return key; + } + return null; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts new file mode 100644 index 0000000..5ef8496 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts @@ -0,0 +1,166 @@ +// Per-city prioritization of the HIAP action library. +// +// CityCatalyst's climate_actions are city-agnostic; we rank them for a given +// city by matching adaptation actions to the city's top CCRA hazards and +// mitigation actions to its dominant emitting sectors (GHGI). Pure + deterministic. + +import type { City, RiskLevel } from "../data/types"; +import type { + ClimateAction, + HazardKey, + GhgSectorKey, + Effectiveness, +} from "../data/climateActions"; +import { normalizeHazard, normalizeSector } from "./hazardNormalize"; + +export type SourceSignal = { + kind: "hazard" | "sector"; + cityValue: string; // e.g. "Heatwaves (Very High)" or "Transportation (81%)" + matchedOn: string; // the canonical key the action matched on + weight: number; // contribution to the score (for an honest "why") +}; + +export type RankedAction = { + action: ClimateAction; + score: number; + sourceSignals: SourceSignal[]; +}; + +const RISK_WEIGHT: Record = { + "Very High": 1.0, + High: 0.75, + Medium: 0.45, + Low: 0.2, +}; + +const EFF_SCORE: Record = { high: 1, medium: 0.6, low: 0.3 }; + +function effScore(e: Effectiveness | null | undefined): number { + return e ? EFF_SCORE[e] : 0.5; // unknown effectiveness → neutral midpoint +} + +// "20-39" → 0.295 ; "80-100" → 0.9 ; null → 0 +function ghgScore(range: string | null | undefined): number { + if (!range) return 0; + const m = range.match(/(\d+)\s*-\s*(\d+)/); + if (!m) return 0; + return (Number(m[1]) + Number(m[2])) / 2 / 100; +} + +const SECTOR_LABEL: Record = { + stationary_energy: "Stationary Energy", + transportation: "Transportation", + waste: "Waste", + ippu: "IPPU", + afolu: "AFOLU", +}; + +type HazardCtx = { key: HazardKey; level: RiskLevel; label: string }; +type SectorCtx = { key: GhgSectorKey; share: number; label: string }; + +// Deduplicate by canonical key (several prose hazards can map to the same key), +// keeping the highest-severity context so each key is scored once. +function cityHazards(city: City): HazardCtx[] { + const byKey = new Map(); + for (const h of city.risk?.topHazards ?? []) { + for (const key of normalizeHazard(h.hazard)) { + const prev = byKey.get(key); + if (!prev || RISK_WEIGHT[h.level] > RISK_WEIGHT[prev.level]) { + byKey.set(key, { key, level: h.level, label: h.hazard }); + } + } + } + return [...byKey.values()]; +} + +function citySectors(city: City): SectorCtx[] { + const e = city.emissions; + if (!e) return []; + const byKey = new Map(); + if (e.sectors?.length) { + for (const s of e.sectors) { + const key = normalizeSector(s.sector); + if (!key) continue; + const prev = byKey.get(key); + if (!prev || s.sharePct / 100 > prev.share) { + byKey.set(key, { key, share: s.sharePct / 100, label: s.sector }); + } + } + } else if (e.topSector) { + const key = normalizeSector(e.topSector); + if (key) byKey.set(key, { key, share: 0.6, label: e.topSector }); + } + return [...byKey.values()]; +} + +export function prioritizeActions( + city: City, + actions: ClimateAction[], + opts: { topN?: number } = {} +): RankedAction[] { + const topN = opts.topN ?? 6; + const hazards = cityHazards(city); + const sectors = citySectors(city); + + const ranked: RankedAction[] = []; + + for (const action of actions) { + let score = 0; + const signals: SourceSignal[] = []; + + if (action.actionType === "adaptation") { + for (const h of hazards) { + if (!action.hazards.includes(h.key)) continue; + const eff = effScore(action.adaptationPerHazard?.[h.key] ?? action.adaptationEffectiveness); + const contrib = RISK_WEIGHT[h.level] * eff; + score += contrib; + signals.push({ + kind: "hazard", + cityValue: `${h.label} (${h.level})`, + matchedOn: h.key, + weight: contrib, + }); + } + } else { + for (const s of sectors) { + const ghg = action.ghgReductionPotential?.[s.key]; + const matchesSector = action.sectors.includes(s.key); + if (ghg == null && !matchesSector) continue; + const contrib = s.share * (ghgScore(ghg) || 0.5); + score += contrib; + signals.push({ + kind: "sector", + cityValue: `${s.label} (${Math.round(s.share * 100)}%)`, + matchedOn: s.key, + weight: contrib, + }); + } + } + + if (score <= 0) continue; + + // Tie-breaker: reward the stakeholder-engagement co-benefit (the fundable signal). + score += 0.05 * (action.coBenefits?.stakeholder_engagement ?? 0); + + ranked.push({ action, score, sourceSignals: signals }); + } + + ranked.sort((a, b) => b.score - a.score); + + // Balance the result so both adaptation (matches risks) and mitigation + // (matches emissions) are represented — adaptation scores are on a larger + // scale and would otherwise crowd out every mitigation action. + const adapt = ranked.filter((r) => r.action.actionType === "adaptation"); + const mitig = ranked.filter((r) => r.action.actionType === "mitigation"); + const target = Math.ceil(topN / 2); + const out = [...adapt.slice(0, target), ...mitig.slice(0, topN - target)]; + // Backfill if one type was short. + if (out.length < topN) { + const used = new Set(out); + for (const r of ranked) { + if (out.length >= topN) break; + if (!used.has(r)) out.push(r); + } + } + return out; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts new file mode 100644 index 0000000..6289647 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts @@ -0,0 +1,51 @@ +"use client"; + +import { useCallback, useState } from "react"; +import type { Lang } from "../data/climateActions"; +import { useCarbon } from "./carbonContext"; + +export type LocalizeRequest = { + action: { name: string; description: string; type: "mitigation" | "adaptation" }; + cityContext: { name: string; country: string; topHazards: string[]; topSectors: string[] }; + language: Lang; +}; + +export type LocalizeResult = { + localizedSteps: string[]; + energyWh: number; + gCO2e: number; + model: string; + provider: string; + mock: boolean; +}; + +export function useLocalize() { + const { addUsage } = useCarbon(); + const [loading, setLoading] = useState(false); + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + + const run = useCallback( + async (req: LocalizeRequest) => { + setLoading(true); + setError(null); + try { + const res = await fetch("/api/localize", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(req), + }); + const data: LocalizeResult = await res.json(); + setResult(data); + addUsage(data.gCO2e, data.energyWh); + } catch (e) { + setError(String(e)); + } finally { + setLoading(false); + } + }, + [addUsage] + ); + + return { run, loading, result, error }; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.env.example b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.env.example new file mode 100644 index 0000000..5df3c61 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.env.example @@ -0,0 +1,21 @@ +# Copy to .env and fill in to enable LIVE (non-mock) localization. +# With no LLM_API_KEY set, the service runs in MOCK mode (templated steps + +# estimated carbon) — the demo works with zero secrets. + +# Provider preset: scaleway | greenpt | mistral | qwen | salamandra | aya | groq +LLM_PROVIDER=scaleway + +# Override the preset's base_url / model if needed (all OpenAI-compatible): +# LLM_BASE_URL=https://api.scaleway.ai/v1 +# LLM_MODEL=mistral-small-3.2-24b-instruct-2506 + +# Your provider API key. Leave empty to stay in mock mode. +LLM_API_KEY= + +# Force mock mode even if a key is present: +# LLM_MOCK=1 + +# Which provider EcoLogits should use for impact estimation (default: openai): +ECOLOGITS_PROVIDER=openai + +PORT=8000 diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.gitignore b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.gitignore new file mode 100644 index 0000000..a98520d --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/.gitignore @@ -0,0 +1,4 @@ +.venv/ +__pycache__/ +*.pyc +.env diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/README.md b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/README.md new file mode 100644 index 0000000..3fda9e9 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/README.md @@ -0,0 +1,51 @@ +# LLM Localizer Service (green + cheap) + +A small FastAPI sidecar that turns a chosen CityCatalyst HIAP action + a city's +climate profile into concrete, localized next steps (EN/ES/PT) using a **low-carbon, +open-weight** model through an OpenAI-compatible API — and reports the per-call +carbon footprint with **EcoLogits**. + +The Next.js app calls it at `POST /localize`. If this service is down, the app's +route handler falls back to a built-in templated localizer, so the demo never breaks. + +## Run (mock mode — no secrets) + +```bash +cd llm-service +python -m venv .venv && source .venv/bin/activate +pip install fastapi "uvicorn[standard]" pydantic python-dotenv # mock-mode minimum +uvicorn main:app --port 8000 +``` + +`GET /health` → `{"mock": true, ...}`. `POST /localize` returns templated steps + +an estimated footprint. Point the app at it with `LLM_SERVICE_URL=http://localhost:8000`. + +## Run (live, green model) + +```bash +pip install -r requirements.txt # adds openai + ecologits +cp .env.example .env # set LLM_PROVIDER + LLM_API_KEY +uvicorn main:app --port 8000 +``` + +## Swapping models/providers (config only) + +Everything is OpenAI-compatible, so changing model is **one env var** — no code +change. Presets in `providers.py`: + +| `LLM_PROVIDER` | Why | +|---|---| +| `scaleway` (default) | Low-carbon EU grid (DC5, adiabatic cooling, PUE ~1.15) — the green pick | +| `greenpt` | Green AI, per-conversation CO₂, EU data residency | +| `salamandra` | BSC, Spanish-first (Apache-2.0) — ES/PT-critical path | +| `aya` | Cohere Aya Expanse — strong Spanish + Portuguese | +| `qwen` / `groq` | Cheap multilingual workhorse / fast fallback | + +Override `LLM_BASE_URL` / `LLM_MODEL` for anything not in the table. + +## Carbon accounting + +`ecolog.py` wraps each call with EcoLogits and reads `response.impacts` → +energy (Wh) + gCO₂e. In mock mode it returns a documented estimate. EcoLogits +figures are **estimates** (generic-GPU / fixed-batch assumptions), surfaced in the +UI as "estimated" — directionally useful for the green-AI story, not audited. diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py new file mode 100644 index 0000000..335d338 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py @@ -0,0 +1,64 @@ +"""EcoLogits carbon accounting for the localizer. + +EcoLogits (by the GenAI Impact non-profit) estimates per-request energy (kWh) +and GHG emissions (kgCO2eq) for LLM API calls. We init it once and read the +`.impacts` attribute EcoLogits attaches to each response. When running without a +live call (mock mode), we fall back to a documented constant so the carbon +counter still moves with a defensible number. + +Note: EcoLogits figures are *estimates* (generic-GPU, fixed-batch assumptions) — +directionally useful for dashboards, not audited emissions. The UI labels mocked +numbers as "estimated". +""" + +_INITIALIZED = False + +# Fallback for mock mode: a small open model, short completion, low-carbon EU +# grid. ~0.8 Wh / ~0.3 gCO2e per call. Kept in sync with the JS route fallback. +MOCK_ENERGY_WH = 0.8 +MOCK_GCO2E = 0.3 + + +def init() -> bool: + """Initialize EcoLogits' tracer. Safe to call repeatedly. Returns availability.""" + global _INITIALIZED + if _INITIALIZED: + return True + try: + from ecologits import EcoLogits # type: ignore + + EcoLogits.init(providers=["openai"]) + _INITIALIZED = True + except Exception: + _INITIALIZED = False + return _INITIALIZED + + +def _scalar(v) -> float: + """EcoLogits values may be a float or a range object (min/max/mean).""" + for attr in ("mean", "value"): + inner = getattr(v, attr, None) + if isinstance(inner, (int, float)): + return float(inner) + lo, hi = getattr(v, "min", None), getattr(v, "max", None) + if isinstance(lo, (int, float)) and isinstance(hi, (int, float)): + return (lo + hi) / 2 + return float(v) if isinstance(v, (int, float)) else 0.0 + + +def measure(response) -> dict: + """Read EcoLogits impacts off an OpenAI-compatible response → Wh + gCO2e.""" + try: + impacts = response.impacts + energy_wh = _scalar(impacts.energy.value) * 1000.0 # kWh → Wh + gco2e = _scalar(impacts.gwp.value) * 1000.0 # kgCO2e → g + if energy_wh > 0 or gco2e > 0: + return {"energyWh": round(energy_wh, 4), "gCO2e": round(gco2e, 4)} + except Exception: + pass + return estimate() + + +def estimate() -> dict: + """Mock-mode estimate (no live call).""" + return {"energyWh": MOCK_ENERGY_WH, "gCO2e": MOCK_GCO2E} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py new file mode 100644 index 0000000..fb7db03 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py @@ -0,0 +1,174 @@ +"""Green/cheap LLM localizer sidecar. + +Turns a chosen CityCatalyst HIAP action + a city's climate profile into concrete, +localized, executable next steps (EN/ES/PT) using a low-carbon open-weight model +through an OpenAI-compatible API, and reports the per-call carbon footprint via +EcoLogits. Runs in mock mode with zero secrets so the demo always works. + +Run: uvicorn main:app --port 8000 +""" +import os + +try: + from dotenv import load_dotenv + + load_dotenv() +except Exception: + pass + +from fastapi import FastAPI + +import providers +import ecolog +from schemas import LocalizeRequest, LocalizeResponse + +app = FastAPI(title="Civic Climate Action — LLM Localizer") +ecolog.init() + + +@app.get("/health") +def health(): + provider, _base, model, _key = providers.get_config() + return { + "status": "ok", + "mock": providers.is_mock(), + "provider": provider, + "model": model or "mock-small", + } + + +@app.post("/localize", response_model=LocalizeResponse) +def localize(req: LocalizeRequest): + provider, base_url, model, api_key = providers.get_config() + + if providers.is_mock(): + return LocalizeResponse( + localizedSteps=mock_steps(req), + model=model or "mock-small", + provider=provider, + mock=True, + **ecolog.estimate(), + ) + + # Real path: OpenAI-compatible call, wrapped by EcoLogits. + from openai import OpenAI + + client = OpenAI(base_url=base_url, api_key=api_key) + resp = client.chat.completions.create( + model=model, + messages=[ + {"role": "system", "content": _system(req.language)}, + {"role": "user", "content": _prompt(req)}, + ], + temperature=0.4, + max_tokens=400, + ) + text = resp.choices[0].message.content or "" + impacts = ecolog.measure(resp) + return LocalizeResponse( + localizedSteps=_parse_steps(text), + model=model, + provider=provider, + mock=False, + **impacts, + ) + + +# --------------------------------------------------------------------------- +# Prompt construction +# --------------------------------------------------------------------------- +_LANG_NAME = {"en": "English", "es": "Spanish", "pt": "Brazilian Portuguese"} + + +def _system(language: str) -> str: + lang = _LANG_NAME.get(language, "English") + return ( + f"You are a civic-engagement assistant. Reply ONLY in {lang}. " + "Turn a city climate action into 4 short, concrete, executable next steps " + "a resident can actually take. Each step one sentence, imperative, no preamble. " + "Return a numbered list, nothing else." + ) + + +def _prompt(req: LocalizeRequest) -> str: + c = req.cityContext + hazards = ", ".join(c.topHazards[:3]) or "n/a" + sectors = ", ".join(c.topSectors[:3]) or "n/a" + return ( + f"City: {c.name}, {c.country}\n" + f"Top climate hazards: {hazards}\n" + f"Top emitting sectors: {sectors}\n" + f"Action ({req.action.type}): {req.action.name}\n" + f"Description: {req.action.description[:400]}\n\n" + "Give 4 concrete next steps a resident of this city can take to push this " + "action forward (join a group, attend a meeting, submit a comment, start " + "something small). Ground them in the city's hazards/sectors above." + ) + + +def _parse_steps(text: str) -> list[str]: + import re + + lines = [l.strip() for l in text.splitlines() if l.strip()] + steps = [re.sub(r"^\s*(?:\d+[\.\)]|[-*•])\s*", "", l) for l in lines] + steps = [s for s in steps if len(s) > 8] + return steps[:4] if steps else [text.strip()] + + +# --------------------------------------------------------------------------- +# Mock localization (no key) — mirrors the Next.js route fallback. +# --------------------------------------------------------------------------- +_FOCUS = { + "heat": ("las olas de calor", "as ondas de calor"), + "landslide": ("los deslizamientos", "os deslizamentos"), + "flood": ("las inundaciones", "as inundações"), + "drought": ("la sequía", "a seca"), + "disease": ("las enfermedades", "as doenças"), + "sea-level": ("el aumento del nivel del mar", "a elevação do nível do mar"), + "storm": ("las tormentas", "as tempestades"), + "wildfire": ("los incendios", "os incêndios"), + "transport": ("el transporte", "o transporte"), + "energy": ("la energía", "a energia"), + "waste": ("los residuos", "os resíduos"), + "stationary": ("la energía", "a energia"), +} + + +def _focus(raw: str, lang: str) -> str: + s = raw.lower() + if lang == "en": + return s + for key, (es, pt) in _FOCUS.items(): + if key in s: + return es if lang == "es" else pt + return s + + +def mock_steps(req: LocalizeRequest) -> list[str]: + c = req.cityContext + lang = req.language + raw = (c.topHazards[0] if req.action.type == "adaptation" else None) or ( + c.topSectors[0] if c.topSectors else "climate" + ) + focus = _focus(raw, lang) + action = req.action.name + if lang == "es": + return [ + f"Identifica en {c.name} a un grupo vecinal o colectivo que ya trabaje en {focus}.", + f'Asiste a la próxima sesión del consejo municipal donde se discuta "{action}".', + "Presenta esta acción como propuesta o comentario público, citando el riesgo local.", + "Invita a tres vecinos a sumarse y comparte el avance en tu comunidad.", + ] + if lang == "pt": + return [ + f"Identifique em {c.name} um grupo de bairro ou coletivo que já atue em {focus}.", + f'Participe da próxima sessão do conselho municipal onde "{action}" for discutida.', + "Apresente esta ação como proposta ou comentário público, citando o risco local.", + "Convide três vizinhos para participar e compartilhe o progresso na sua comunidade.", + ] + return [ + f"Find a neighborhood group or collective in {c.name} already working on {focus}.", + f'Attend the next city-council session where "{action}" is on the agenda.', + "Submit this action as a proposal or public comment, citing the local risk.", + "Invite three neighbors to join and share progress in your community.", + ] diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/providers.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/providers.py new file mode 100644 index 0000000..d5d916a --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/providers.py @@ -0,0 +1,46 @@ +"""Provider abstraction — pick a green/cheap open-weight model via env only. + +Swapping providers is a config change, not a code change. All providers expose +an OpenAI-compatible API, so the client code is identical; only base_url + model ++ key differ. Defaults point at a low-carbon EU provider (Scaleway), per the +sustainability research. For Spanish/Portuguese-critical text, route to +Salamandra (BSC, Spanish-first) or Aya Expanse. +""" +import os + +# name -> (base_url, default model). All OpenAI-compatible endpoints. +PRESETS: dict[str, tuple[str, str]] = { + # Low-carbon EU grid (Scaleway DC5, adiabatic cooling) — default green pick. + "scaleway": ("https://api.scaleway.ai/v1", "mistral-small-3.2-24b-instruct-2506"), + "greenpt": ("https://api.greenpt.ai/v1", "mistral-small"), + "mistral": ("https://api.mistral.ai/v1", "mistral-small-latest"), + "qwen": ("https://dashscope-intl.aliyuncs.com/compatible-mode/v1", "qwen-turbo"), + # Spanish/Portuguese-critical path: + "salamandra": ("https://api.scaleway.ai/v1", "salamandra-7b-instruct"), + "aya": ("https://api.cohere.ai/compatibility/v1", "c4ai-aya-expanse-32b"), + # Cheap multilingual fallback: + "groq": ("https://api.groq.com/openai/v1", "llama-3.3-70b-versatile"), +} + + +def get_config() -> tuple[str, str, str, str]: + """Return (provider, base_url, model, api_key) from env, with preset fallback.""" + provider = os.getenv("LLM_PROVIDER", "scaleway") + base_url, default_model = PRESETS.get(provider, ("", "")) + base_url = os.getenv("LLM_BASE_URL", base_url) + model = os.getenv("LLM_MODEL", default_model) + api_key = os.getenv("LLM_API_KEY", "") + return provider, base_url, model, api_key + + +def is_mock() -> bool: + """Mock when explicitly requested or when no API key is configured.""" + flag = os.getenv("LLM_MOCK", "").lower() in ("1", "true", "yes") + return flag or not os.getenv("LLM_API_KEY") + + +# EcoLogits maps an OpenAI-compatible model to its impact factors. Custom +# base_urls aren't always in its registry, so we expose the provider it should +# pretend to be for estimation purposes (default: a generic open model on openai). +def ecologits_provider() -> str: + return os.getenv("ECOLOGITS_PROVIDER", "openai") diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/requirements.txt b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/requirements.txt new file mode 100644 index 0000000..12a8bef --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/requirements.txt @@ -0,0 +1,7 @@ +fastapi>=0.110 +uvicorn[standard]>=0.29 +pydantic>=2.6 +python-dotenv>=1.0 +# Optional — only needed for live (non-mock) calls + real carbon measurement: +openai>=1.30 +ecologits>=0.5 diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py new file mode 100644 index 0000000..88d2685 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py @@ -0,0 +1,30 @@ +"""Request/response models for the localizer service.""" +from pydantic import BaseModel, Field + + +class ActionIn(BaseModel): + name: str + description: str = "" + type: str = "adaptation" # "mitigation" | "adaptation" + + +class CityContext(BaseModel): + name: str + country: str = "" + topHazards: list[str] = Field(default_factory=list) + topSectors: list[str] = Field(default_factory=list) + + +class LocalizeRequest(BaseModel): + action: ActionIn + cityContext: CityContext + language: str = "en" # en | es | pt + + +class LocalizeResponse(BaseModel): + localizedSteps: list[str] + energyWh: float + gCO2e: float + model: str + provider: str + mock: bool From 75c8f45e7bf6ef7e3fe3b527aa7759085d93d37a Mon Sep 17 00:00:00 2001 From: Carlos Octavio Graffi Date: Sun, 14 Jun 2026 01:04:04 -0300 Subject: [PATCH 4/8] Simplify per-city UX: pilots, full-width detail, AI-developed actions (live) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pilot cities (São Paulo, Porto Alegre) get the actions+AI experience; others show just the profile + stories (lib/pilots.ts gating). - Restructure CityExplorer: full-width detail below the [list|map] row instead of the cramped right column; add a static at-a-glance profile headline (lib/profileHeadline.ts). - Replace the 6-card grid with a master-detail: a slim selectable action list (ActionRow) + a prominent AiDevelopPanel. Single useLocalize, keyed per action; the LLM fires on a button, not on every card. - Fold engagement into the AI panel as "where to engage" grounding: unified localSources.ts (Porto Alegre from the teammate's data, São Paulo curated); source names are passed to the LLM so steps cite real channels. - Live LLM: wire Scaleway Mistral Small (via gitignored .env), stronger 4-6 step prompt, token-based EcoLogits estimate labeled "est." (Scaleway model isn't in EcoLogits' registry); built-in fallback retained. - Responsive grid classes in globals.css. Remove unused ActionCard. Co-Authored-By: Claude Opus 4.8 --- .gitignore | 2 + .../app/src/app/api/localize/route.ts | 44 ++-- .../app/src/app/components/ActionCard.tsx | 195 ------------------ .../app/src/app/components/ActionRow.tsx | 53 +++++ .../app/src/app/components/AiDevelopPanel.tsx | 157 ++++++++++++++ .../app/src/app/components/CityActions.tsx | 113 ++++------ .../app/src/app/components/CityExplorer.tsx | 82 ++++---- .../app/src/app/data/localSources.ts | 56 +++++ .../app/src/app/globals.css | 23 +++ .../app/src/app/lib/pilots.ts | 7 + .../app/src/app/lib/profileHeadline.ts | 89 ++++++++ .../app/src/app/lib/useLocalize.ts | 8 +- .../llm-service/ecolog.py | 32 ++- .../civic-climate-action/llm-service/main.py | 23 ++- .../llm-service/schemas.py | 1 + 15 files changed, 546 insertions(+), 339 deletions(-) delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pilots.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts diff --git a/.gitignore b/.gitignore index 6926df2..56870e7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ __pycache__/ dist/ .DS_Store *.log + +*.tsbuildinfo diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts index b3a8816..dc30aa8 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts @@ -9,7 +9,13 @@ export const runtime = "nodejs"; type Body = { action: { name: string; description: string; type: "mitigation" | "adaptation" }; - cityContext: { name: string; country: string; topHazards: string[]; topSectors: string[] }; + cityContext: { + name: string; + country: string; + topHazards: string[]; + topSectors: string[]; + localSources: string[]; + }; language: "en" | "es" | "pt"; }; @@ -49,13 +55,15 @@ function fallbackLocalize(body: Body) { ? cityContext.topHazards[0] ?? "climate risk" : cityContext.topSectors[0] ?? "emissions"; const focus = translateFocus(rawFocus, language); + const channel = cityContext.localSources?.[0] ?? null; - const steps = templates(language, city, focus, action.name); - // A modest estimate (no live call): ~0.3 g CO₂e for a small open model call. + const steps = templates(language, city, focus, action.name, channel); + // Token-based estimate consistent with the sidecar (small open model, low-carbon + // EU grid): ~350 tokens × 0.0009 Wh × 0.052 gCO2e/Wh. return { localizedSteps: steps, - energyWh: 0.8, - gCO2e: 0.3, + energyWh: 0.32, + gCO2e: 0.016, model: "templated-fallback", provider: "fallback", mock: true, @@ -87,27 +95,39 @@ function translateFocus(raw: string, lang: "en" | "es" | "pt"): string { return s; } -function templates(lang: "en" | "es" | "pt", city: string, focus: string, action: string): string[] { +function templates( + lang: "en" | "es" | "pt", + city: string, + focus: string, + action: string, + channel: string | null +): string[] { if (lang === "es") { return [ `Identifica en ${city} a un grupo vecinal o colectivo que ya trabaje en ${focus}.`, - `Asiste a la próxima sesión del consejo municipal donde se discuta "${action}".`, - `Presenta esta acción como propuesta o comentario público, citando el riesgo local.`, + channel + ? `Lleva esta acción a ${channel} como propuesta o comentario público.` + : `Asiste a la próxima sesión del consejo municipal donde se discuta "${action}".`, + `Documenta el riesgo local con datos para respaldar la propuesta.`, `Invita a tres vecinos a sumarse y comparte el avance en tu comunidad.`, ]; } if (lang === "pt") { return [ `Identifique em ${city} um grupo de bairro ou coletivo que já atue em ${focus}.`, - `Participe da próxima sessão do conselho municipal onde "${action}" for discutida.`, - `Apresente esta ação como proposta ou comentário público, citando o risco local.`, + channel + ? `Leve esta ação ao ${channel} como proposta ou comentário público.` + : `Participe da próxima sessão do conselho municipal onde "${action}" for discutida.`, + `Documente o risco local com dados para embasar a proposta.`, `Convide três vizinhos para participar e compartilhe o progresso na sua comunidade.`, ]; } return [ `Find a neighborhood group or collective in ${city} already working on ${focus}.`, - `Attend the next city-council session where "${action}" is on the agenda.`, - `Submit this action as a proposal or public comment, citing the local risk.`, + channel + ? `Bring this action to ${channel} as a proposal or public comment.` + : `Attend the next city-council session where "${action}" is on the agenda.`, + `Back it with local risk data to make the case.`, `Invite three neighbors to join and share progress in your community.`, ]; } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx deleted file mode 100644 index fcc92a3..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionCard.tsx +++ /dev/null @@ -1,195 +0,0 @@ -"use client"; - -import { useState } from "react"; -import type { Lang } from "../data/climateActions"; -import type { RankedAction } from "../lib/prioritize"; -import { useLocalize } from "../lib/useLocalize"; - -const typeMeta = { - adaptation: { label: { en: "Adaptation", es: "Adaptación", pt: "Adaptação" }, color: "var(--accent)" }, - mitigation: { label: { en: "Mitigation", es: "Mitigación", pt: "Mitigação" }, color: "#d97706" }, -} as const; - -const coBenefitLabel: Record> = { - air_quality: { en: "Air quality", es: "Calidad del aire", pt: "Qualidade do ar" }, - water_quality: { en: "Water", es: "Agua", pt: "Água" }, - habitat: { en: "Habitat", es: "Hábitat", pt: "Habitat" }, - cost_of_living: { en: "Lower costs", es: "Menor costo", pt: "Menor custo" }, - housing: { en: "Housing", es: "Vivienda", pt: "Moradia" }, - mobility: { en: "Mobility", es: "Movilidad", pt: "Mobilidade" }, - stakeholder_engagement: { en: "Civic engagement", es: "Participación", pt: "Participação" }, -}; - -const t = { - why: { en: "Why this matters for", es: "Por qué importa en", pt: "Por que importa em" }, - make: { en: "Make this concrete for my city", es: "Hazlo concreto para mi ciudad", pt: "Torne isto concreto para minha cidade" }, - working: { en: "Generating…", es: "Generando…", pt: "Gerando…" }, - steps: { en: "Your localized next steps", es: "Tus próximos pasos locales", pt: "Seus próximos passos locais" }, - estimated: { en: "estimated", es: "estimado", pt: "estimado" }, -}; - -export default function ActionCard({ - ranked, - cityName, - cityContext, - lang, -}: { - ranked: RankedAction; - cityName: string; - cityContext: { country: string; topHazards: string[]; topSectors: string[] }; - lang: Lang; -}) { - const { action, sourceSignals } = ranked; - const meta = typeMeta[action.actionType]; - const { run, loading, result } = useLocalize(); - - // Deduplicate the "why" signals by what they matched on. - const seen = new Set(); - const signals = sourceSignals.filter((s) => { - if (seen.has(s.matchedOn)) return false; - seen.add(s.matchedOn); - return true; - }); - - const benefits = Object.entries(action.coBenefits) - .filter(([, v]) => (v ?? 0) > 0) - .map(([k]) => coBenefitLabel[k]?.[lang] ?? k); - - const [open, setOpen] = useState(false); - - function localize() { - setOpen(true); - run({ - action: { name: action.name[lang], description: action.description[lang], type: action.actionType }, - cityContext: { name: cityName, ...cityContext }, - language: lang, - }); - } - - return ( -
-
- - {meta.label[lang]} - - - {action.cost && {action.cost} cost} - {action.timeline && {action.timeline}} - -
- -

{action.name[lang]}

-

- {action.description[lang].length > 220 - ? action.description[lang].slice(0, 217).trimEnd() + "…" - : action.description[lang]} -

- - {signals.length > 0 && ( -
-
- {t.why[lang]} {cityName} -
-
- {signals.map((s) => ( - - • {s.cityValue} - - ))} -
-
- )} - - {benefits.length > 0 && ( -
- {benefits.map((b) => ( - - + {b} - - ))} -
- )} - -
- {!open ? ( - - ) : ( -
-
- {loading ? t.working[lang] : t.steps[lang]} -
- {loading &&
} - {result && ( - <> -
    - {result.localizedSteps.map((step, i) => ( -
  1. - {step} -
  2. - ))} -
-
- ~{result.gCO2e.toFixed(2)} g CO₂e · {result.model} - {result.mock ? ` · ${t.estimated[lang]}` : ""} -
- - )} -
- )} -
-
- ); -} - -function Pill({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} - -const ctaStyle: React.CSSProperties = { - font: "inherit", - fontSize: "0.85rem", - fontWeight: 650, - cursor: "pointer", - color: "var(--accent)", - background: "var(--accent-soft)", - border: "none", - borderRadius: 8, - padding: "0.5rem 0.85rem", - width: "100%", -}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx new file mode 100644 index 0000000..23597d0 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx @@ -0,0 +1,53 @@ +"use client"; + +import type { Lang } from "../data/climateActions"; +import type { RankedAction } from "../lib/prioritize"; + +const typeMeta = { + adaptation: { label: { en: "Adaptation", es: "Adaptación", pt: "Adaptação" }, color: "var(--accent)" }, + mitigation: { label: { en: "Mitigation", es: "Mitigación", pt: "Mitigação" }, color: "#d97706" }, +} as const; + +export default function ActionRow({ + ranked, + lang, + selected, + onSelect, +}: { + ranked: RankedAction; + lang: Lang; + selected: boolean; + onSelect: () => void; +}) { + const { action, sourceSignals } = ranked; + const meta = typeMeta[action.actionType]; + const why = sourceSignals[0]?.cityValue; + + return ( + + ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx new file mode 100644 index 0000000..7f98615 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx @@ -0,0 +1,157 @@ +"use client"; + +import type { Lang } from "../data/climateActions"; +import type { LocalSource } from "../data/localEngagement"; +import type { RankedAction } from "../lib/prioritize"; +import { useLocalize } from "../lib/useLocalize"; + +const typeColor = { adaptation: "var(--accent)", mitigation: "#d97706" } as const; + +const t = { + develop: { en: "Develop this with AI", es: "Desarrollar con IA", pt: "Desenvolver com IA" }, + regenerate: { en: "Regenerate", es: "Regenerar", pt: "Regenerar" }, + working: { en: "Developing a local plan…", es: "Generando un plan local…", pt: "Gerando um plano local…" }, + plan: { en: "Your local plan", es: "Tu plan local", pt: "Seu plano local" }, + empty: { + en: "Pick an action on the left, then develop a concrete plan grounded in", + es: "Elige una acción a la izquierda y desarrolla un plan concreto basado en", + pt: "Escolha uma ação à esquerda e desenvolva um plano concreto baseado em", + }, + where: { en: "Where to engage locally", es: "Dónde participar localmente", pt: "Onde participar localmente" }, + estimated: { en: "estimated", es: "estimado", pt: "estimado" }, +}; + +export default function AiDevelopPanel({ + ranked, + cityName, + cityContext, + localSources, + lang, +}: { + ranked: RankedAction; + cityName: string; + cityContext: { country: string; topHazards: string[]; topSectors: string[]; localSources: string[] }; + localSources: LocalSource[]; + lang: Lang; +}) { + const { action } = ranked; + const { run, loading, result } = useLocalize(); + + function develop() { + run({ + action: { name: action.name[lang], description: action.description[lang], type: action.actionType }, + cityContext: { name: cityName, ...cityContext }, + language: lang, + }); + } + + return ( +
+ + {action.actionType} + +

{action.name[lang]}

+

+ {action.description[lang].length > 240 + ? action.description[lang].slice(0, 237).trimEnd() + "…" + : action.description[lang]} +

+ + {!result && !loading && ( + <> +

+ {t.empty[lang]} {cityName}. +

+ + + )} + + {loading &&
{t.working[lang]}
} + + {result && ( +
+
+ {t.plan[lang]} +
+
    + {result.localizedSteps.map((step, i) => ( +
  1. + {step} +
  2. + ))} +
+
+ + + ~{result.gCO2e.toFixed(3)} g CO₂e ({t.estimated[lang]}) · {result.model} + +
+
+ )} + + {localSources.length > 0 && ( +
+
+ {t.where[lang]} +
+
+ {localSources.slice(0, 8).map((s) => ( + + {s.name} ↗ + + ))} +
+
+ )} +
+ ); +} + +const ctaStyle: React.CSSProperties = { + font: "inherit", + fontSize: "0.9rem", + fontWeight: 650, + cursor: "pointer", + color: "#fff", + background: "var(--accent)", + border: "none", + borderRadius: 8, + padding: "0.6rem 1rem", + width: "100%", +}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx index 894b7b0..4beae45 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx @@ -5,8 +5,9 @@ import type { City } from "../data/types"; import type { Lang } from "../data/climateActions"; import { climateActions } from "../data/climateActions"; import { prioritizeActions } from "../lib/prioritize"; -import { engagementByCity } from "../data/engagement"; -import ActionCard from "./ActionCard"; +import { localSourcesByCity, localSourceNamesByCity } from "../data/localSources"; +import ActionRow from "./ActionRow"; +import AiDevelopPanel from "./AiDevelopPanel"; const LANGS: { key: Lang; label: string }[] = [ { key: "en", label: "EN" }, @@ -21,37 +22,40 @@ const defaultLang = (country: string): Lang => { }; const copy = { - heading: { en: "Prioritized actions for", es: "Acciones prioritarias para", pt: "Ações prioritárias para" }, + heading: { en: "Develop an action for", es: "Desarrolla una acción para", pt: "Desenvolva uma ação para" }, intro: { - en: "Drawn from CityCatalyst's HIAP library and ranked for this city's top risks and emissions.", - es: "Tomadas de la biblioteca HIAP de CityCatalyst y priorizadas según los riesgos y emisiones de la ciudad.", - pt: "Extraídas da biblioteca HIAP do CityCatalyst e priorizadas pelos riscos e emissões da cidade.", + en: "Priorities from CityCatalyst's HIAP library, ranked for this city. Pick one and build a concrete, local plan.", + es: "Prioridades de la biblioteca HIAP de CityCatalyst, ordenadas para esta ciudad. Elige una y crea un plan local concreto.", + pt: "Prioridades da biblioteca HIAP do CityCatalyst, ordenadas para esta cidade. Escolha uma e crie um plano local concreto.", }, - engage: { en: "Where to engage", es: "Dónde participar", pt: "Onde participar" }, - unverified: { en: "needs local validation", es: "requiere validación local", pt: "requer validação local" }, }; export default function CityActions({ city }: { city: City }) { const [lang, setLang] = useState(defaultLang(city.country)); + const ranked = useMemo(() => prioritizeActions(city, climateActions, { topN: 4 }), [city]); + const [selectedActionId, setSelectedActionId] = useState(ranked[0]?.action.actionId ?? null); - const ranked = useMemo(() => prioritizeActions(city, climateActions, { topN: 6 }), [city]); if (ranked.length === 0) return null; + const selected = ranked.find((r) => r.action.actionId === selectedActionId) ?? ranked[0]; const cityContext = { country: city.country, topHazards: (city.risk?.topHazards ?? []).map((h) => h.hazard), - topSectors: city.emissions?.sectors?.map((s) => s.sector) ?? + topSectors: + city.emissions?.sectors?.map((s) => s.sector) ?? (city.emissions?.topSector ? [city.emissions.topSector] : []), + localSources: localSourceNamesByCity[city.id] ?? [], }; - - const engagement = engagementByCity[city.id] ?? []; + const localSources = localSourcesByCity[city.id] ?? []; return ( -
+
-
{copy.heading[lang]} {city.name}
-

+

+ {copy.heading[lang]} {city.name} +
+

{copy.intro[lang]}

@@ -79,65 +83,28 @@ export default function CityActions({ city }: { city: City }) {
-
- {ranked.map((r) => ( - - ))} -
- - {engagement.length > 0 && ( -
-
- {copy.engage[lang]} -
-
- {engagement.map((o) => ( -
-
- {o.title[lang]} - {o.needs_local_validation && ( - - {copy.unverified[lang]} - - )} -
-

- {o.description[lang]} -

-
- {o.citizenActions.map((a, i) => ( - - {a.label[lang]} - - ))} -
-
- ))} -
+
+
+ {ranked.map((r) => ( + setSelectedActionId(r.action.actionId)} + /> + ))}
- )} + + +
); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx index d59b537..d3dc405 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx @@ -6,7 +6,8 @@ import type { City, Story } from "../data/types"; import { categoryMeta } from "../data/types"; import CitySnapshot from "./CitySnapshot"; import CityActions from "./CityActions"; -import LocalEngagementPanel from "./LocalEngagementPanel"; +import { isPilot } from "../lib/pilots"; +import { profileHeadline } from "../lib/profileHeadline"; const CityMap = dynamic(() => import("./CityMap"), { ssr: false, @@ -69,10 +70,14 @@ export default function CityExplorer({ cities, stories }: { cities: City[]; stor setSelectedId(id); } + const headline = selected ? profileHeadline(selected, "en") : null; + return ( -
+
+ {/* Top row: search + list | map */} +
{/* Left: search + list */} -
+
setQuery(e.target.value)} @@ -136,44 +141,41 @@ export default function CityExplorer({ cities, stories }: { cities: City[]; stor
- {/* Right: map + detail */} -
-
- -
+ {/* Right: map */} +
+ +
+
- {selected && ( -
-

- {selected.name}, {selected.country} -

-

- {selected.summary} -

+ {/* Full-width detail for the selected city */} + {selected && ( +
+

+ {selected.name}, {selected.country} +

+ {headline && ( +

{headline}

+ )} +

+ {selected.summary} +

- + - + {isPilot(selected.id) && } - {selected.highlights.length > 0 && ( -
-
- Ways to take part -
-
    - {selected.highlights.map((h) => ( -
  • - {h} -
  • - ))} -
+ {selectedStories.length > 0 && ( +
+
+ Citizens have done this
- )} - - - - {selectedStories.length > 0 && ( -
+
{selectedStories.map((s) => (
))}
- )} -
- )} -
+
+ )} +
+ )}
); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts new file mode 100644 index 0000000..be412ce --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts @@ -0,0 +1,56 @@ +// Unified "where to engage locally" sources per pilot city — reused as grounding +// for the AI develop panel (chips + names passed to the LLM). Reconciles the two +// earlier engagement representations into one shape: +// - Porto Alegre: derived from the teammate's localEngagement.ts (do not edit it). +// - São Paulo: a small curated set (real municipal + community channels). + +import type { LocalSource } from "./localEngagement"; +import { portoAlegreEngagementRecommendations } from "./localEngagement"; + +// Flatten + dedupe POA sources by id (same logic as LocalEngagementPanel). +const poaSources: LocalSource[] = Array.from( + new Map( + portoAlegreEngagementRecommendations.flatMap((r) => r.sources).map((s) => [s.id, s]) + ).values() +); + +const saoPauloSources: LocalSource[] = [ + { + id: "sp-participemais", + name: "Participe+ São Paulo", + type: "official", + url: "https://participemais.prefeitura.sp.gov.br/", + note: "City participation platform — open consultations, proposals and participatory processes.", + }, + { + id: "sp-cades", + name: "CADES — Conselho Municipal do Meio Ambiente", + type: "official", + url: "https://www.prefeitura.sp.gov.br/cidade/secretarias/meio_ambiente/conselho_municipal_do_meio_ambiente/", + note: "Municipal environment & sustainable-development council with public sessions.", + }, + { + id: "sp-defesacivil", + name: "Defesa Civil de São Paulo", + type: "official", + url: "https://www.prefeitura.sp.gov.br/cidade/secretarias/subprefeituras/defesa_civil/", + note: "Official disaster-risk and emergency-response channel (heat, flooding).", + }, + { + id: "sp-ciclocidade", + name: "Ciclocidade", + type: "community", + url: "https://www.ciclocidade.org.br/", + note: "Cycling-advocacy association — active mobility campaigns. Community source; verify locally.", + }, +]; + +export const localSourcesByCity: Record = { + "porto-alegre": poaSources, + "sao-paulo": saoPauloSources, +}; + +export const localSourceNamesByCity: Record = { + "porto-alegre": poaSources.map((s) => s.name), + "sao-paulo": saoPauloSources.map((s) => s.name), +}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css index 8b3f968..74952dd 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css @@ -84,3 +84,26 @@ a:hover { background: var(--bg-soft); font-family: inherit; } + +/* Explorer top row: city list + map, side by side, stacking on narrow screens. */ +.explorer-top { + display: grid; + grid-template-columns: minmax(280px, 360px) 1fr; + gap: 1.5rem; + align-items: start; +} + +/* Per-city action lab: selectable action list (left) + AI develop panel (right). */ +.lab-grid { + display: grid; + grid-template-columns: minmax(230px, 320px) 1fr; + gap: 1.1rem; + align-items: start; +} + +@media (max-width: 760px) { + .explorer-top, + .lab-grid { + grid-template-columns: 1fr; + } +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pilots.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pilots.ts new file mode 100644 index 0000000..ad4ceeb --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pilots.ts @@ -0,0 +1,7 @@ +// Pilot cities get the full per-city experience: prioritized HIAP actions + the +// AI "develop this action" panel. Other cities show only the profile + stories. +export const PILOT_CITY_IDS = new Set(["sao-paulo", "porto-alegre"]); + +export function isPilot(cityId: string): boolean { + return PILOT_CITY_IDS.has(cityId); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts new file mode 100644 index 0000000..90a6b69 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts @@ -0,0 +1,89 @@ +// A one-line, plain-language "at a glance" headline for a city, derived purely +// from its emissions + risk data (no LLM). Localized EN/ES/PT. + +import type { City, RiskLevel } from "../data/types"; +import type { HazardKey, Lang } from "../data/climateActions"; +import { normalizeHazard, normalizeSector } from "./hazardNormalize"; + +const LEVEL_ORDER: Record = { "Very High": 4, High: 3, Medium: 2, Low: 1 }; + +const LEVEL_WORD: Record> = { + "Very High": { en: "Very high", es: "muy alto", pt: "muito alto" }, + High: { en: "High", es: "alto", pt: "alto" }, + Medium: { en: "Medium", es: "medio", pt: "médio" }, + Low: { en: "Low", es: "bajo", pt: "bajo" }, +}; + +const HAZARD_WORD: Record> = { + heatwaves: { en: "heatwaves", es: "olas de calor", pt: "ondas de calor" }, + landslides: { en: "landslides", es: "deslizamientos", pt: "deslizamentos" }, + floods: { en: "flooding", es: "inundaciones", pt: "inundações" }, + droughts: { en: "drought", es: "sequía", pt: "seca" }, + diseases: { en: "disease", es: "enfermedades", pt: "doenças" }, + "sea-level-rise": { en: "sea-level rise", es: "aumento del nivel del mar", pt: "elevação do nível do mar" }, + storms: { en: "storms", es: "tormentas", pt: "tempestades" }, + wildfires: { en: "wildfire", es: "incendios", pt: "incêndios" }, +}; + +const SECTOR_WORD: Record> = { + transportation: { en: "transport", es: "el transporte", pt: "o transporte" }, + stationary_energy: { en: "energy use", es: "la energía", pt: "a energia" }, + waste: { en: "waste", es: "los residuos", pt: "os resíduos" }, + ippu: { en: "industry", es: "la industria", pt: "a indústria" }, + afolu: { en: "land use", es: "el uso del suelo", pt: "o uso do solo" }, +}; + +const JOIN: Record = { en: " & ", es: " y ", pt: " e " }; + +function topHazardWords(city: City, lang: Lang): { word: string; level: RiskLevel } | null { + const hazards = city.risk?.topHazards ?? []; + if (hazards.length === 0) return null; + const keys: HazardKey[] = []; + let level: RiskLevel = "Low"; + for (const h of hazards) { + if (LEVEL_ORDER[h.level] > LEVEL_ORDER[level]) level = h.level; + for (const k of normalizeHazard(h.hazard)) if (!keys.includes(k)) keys.push(k); + } + if (keys.length === 0) return null; + const word = keys.slice(0, 2).map((k) => HAZARD_WORD[k][lang]).join(JOIN[lang]); + return { word, level }; +} + +function sectorClause(city: City, lang: Lang): string | null { + const e = city.emissions; + if (!e) return null; + if (e.sectors?.length) { + const top = [...e.sectors].sort((a, b) => b.sharePct - a.sharePct)[0]; + const key = normalizeSector(top.sector); + const word = key ? SECTOR_WORD[key][lang] : top.sector; + const pct = Math.round(top.sharePct); + if (lang === "es") return `${word} genera el ${pct}% de las emisiones`; + if (lang === "pt") return `${word} gera ${pct}% das emissões`; + return `${word} drives ${pct}% of emissions`; + } + if (e.topSector) { + const key = normalizeSector(e.topSector); + const word = key ? SECTOR_WORD[key][lang] : e.topSector.toLowerCase(); + if (lang === "es") return `${word} es la mayor fuente de emisiones`; + if (lang === "pt") return `${word} é a maior fonte de emissões`; + return `${word} is the largest emissions source`; + } + return null; +} + +export function profileHeadline(city: City, lang: Lang = "en"): string | null { + const hz = topHazardWords(city, lang); + const sec = sectorClause(city, lang); + const riskPart = hz + ? lang === "es" + ? `Riesgo ${LEVEL_WORD[hz.level].es} por ${hz.word}` + : lang === "pt" + ? `Risco ${LEVEL_WORD[hz.level].pt} de ${hz.word}` + : `${LEVEL_WORD[hz.level].en} risk from ${hz.word}` + : null; + + if (riskPart && sec) return `${riskPart}; ${sec}.`; + if (riskPart) return `${riskPart}.`; + if (sec) return `${sec[0].toUpperCase()}${sec.slice(1)}.`; + return null; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts index 6289647..a331075 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts @@ -6,7 +6,13 @@ import { useCarbon } from "./carbonContext"; export type LocalizeRequest = { action: { name: string; description: string; type: "mitigation" | "adaptation" }; - cityContext: { name: string; country: string; topHazards: string[]; topSectors: string[] }; + cityContext: { + name: string; + country: string; + topHazards: string[]; + topSectors: string[]; + localSources: string[]; + }; language: Lang; }; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py index 335d338..0f31674 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/ecolog.py @@ -13,10 +13,12 @@ _INITIALIZED = False -# Fallback for mock mode: a small open model, short completion, low-carbon EU -# grid. ~0.8 Wh / ~0.3 gCO2e per call. Kept in sync with the JS route fallback. -MOCK_ENERGY_WH = 0.8 -MOCK_GCO2E = 0.3 +# Token-based estimate, used when EcoLogits can't measure (e.g. Scaleway's model +# id isn't in its registry) or in mock mode. Grounded in a small (~24B) open model +# on a low-carbon EU grid (Scaleway France ≈ 52 gCO2e/kWh). +ENERGY_WH_PER_TOKEN = 0.0009 # rough active-inference energy for a ~24B model +EU_GRID_GCO2E_PER_WH = 0.052 # France/Scaleway low-carbon grid intensity +DEFAULT_TOKENS = 350 # assumed completion length when token count is unknown def init() -> bool: @@ -47,7 +49,11 @@ def _scalar(v) -> float: def measure(response) -> dict: - """Read EcoLogits impacts off an OpenAI-compatible response → Wh + gCO2e.""" + """Read EcoLogits impacts off an OpenAI-compatible response → Wh + gCO2e. + + Falls back to a token-based estimate when EcoLogits has no data for the model + (e.g. a non-OpenAI model served via a custom base_url like Scaleway). + """ try: impacts = response.impacts energy_wh = _scalar(impacts.energy.value) * 1000.0 # kWh → Wh @@ -56,9 +62,17 @@ def measure(response) -> dict: return {"energyWh": round(energy_wh, 4), "gCO2e": round(gco2e, 4)} except Exception: pass - return estimate() + # Estimate from the completion token count when available. + tokens = DEFAULT_TOKENS + try: + tokens = response.usage.completion_tokens or response.usage.total_tokens or DEFAULT_TOKENS + except Exception: + pass + return estimate(tokens) -def estimate() -> dict: - """Mock-mode estimate (no live call).""" - return {"energyWh": MOCK_ENERGY_WH, "gCO2e": MOCK_GCO2E} +def estimate(completion_tokens: int = DEFAULT_TOKENS) -> dict: + """Token-based estimate (no usable EcoLogits measurement).""" + energy_wh = completion_tokens * ENERGY_WH_PER_TOKEN + gco2e = energy_wh * EU_GRID_GCO2E_PER_WH + return {"energyWh": round(energy_wh, 4), "gCO2e": round(gco2e, 4)} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py index fb7db03..21f6096 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py @@ -61,7 +61,7 @@ def localize(req: LocalizeRequest): {"role": "user", "content": _prompt(req)}, ], temperature=0.4, - max_tokens=400, + max_tokens=500, ) text = resp.choices[0].message.content or "" impacts = ecolog.measure(resp) @@ -83,10 +83,12 @@ def localize(req: LocalizeRequest): def _system(language: str) -> str: lang = _LANG_NAME.get(language, "English") return ( - f"You are a civic-engagement assistant. Reply ONLY in {lang}. " - "Turn a city climate action into 4 short, concrete, executable next steps " - "a resident can actually take. Each step one sentence, imperative, no preamble. " - "Return a numbered list, nothing else." + f"You are a civic-engagement assistant for city residents. Reply ONLY in {lang}. " + "Turn a city climate action into a short plan of 4-6 concrete, executable next steps an " + "ordinary resident can take over the coming weeks. Each step: one imperative sentence, " + "specific and doable, no preamble. Where a step involves contacting government or joining " + "a group, name a real local channel from the context when one is provided. " + "Return ONLY a numbered list — no title, no closing remarks." ) @@ -94,15 +96,18 @@ def _prompt(req: LocalizeRequest) -> str: c = req.cityContext hazards = ", ".join(c.topHazards[:3]) or "n/a" sectors = ", ".join(c.topSectors[:3]) or "n/a" + channels = ", ".join(c.localSources[:5]) or "n/a" return ( f"City: {c.name}, {c.country}\n" f"Top climate hazards: {hazards}\n" f"Top emitting sectors: {sectors}\n" + f"Local civic channels: {channels}\n" f"Action ({req.action.type}): {req.action.name}\n" f"Description: {req.action.description[:400]}\n\n" - "Give 4 concrete next steps a resident of this city can take to push this " - "action forward (join a group, attend a meeting, submit a comment, start " - "something small). Ground them in the city's hazards/sectors above." + "Write 4-6 concrete next steps a resident of this city can take to push this action " + "forward (join a group, attend a meeting, submit a public comment, start something small). " + "Ground them in the city's hazards/sectors, and when a step involves contacting government " + "or joining a group, name one of the local civic channels above explicitly." ) @@ -112,7 +117,7 @@ def _parse_steps(text: str) -> list[str]: lines = [l.strip() for l in text.splitlines() if l.strip()] steps = [re.sub(r"^\s*(?:\d+[\.\)]|[-*•])\s*", "", l) for l in lines] steps = [s for s in steps if len(s) > 8] - return steps[:4] if steps else [text.strip()] + return steps[:6] if steps else [text.strip()] # --------------------------------------------------------------------------- diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py index 88d2685..dec28d5 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py @@ -13,6 +13,7 @@ class CityContext(BaseModel): country: str = "" topHazards: list[str] = Field(default_factory=list) topSectors: list[str] = Field(default_factory=list) + localSources: list[str] = Field(default_factory=list) class LocalizeRequest(BaseModel): From 1c496eac0846a3ee395e9ff8ebbf3de190a281d1 Mon Sep 17 00:00:00 2001 From: Carlos Octavio Graffi Date: Sun, 14 Jun 2026 22:42:09 -0300 Subject: [PATCH 5/8] Add multi-lens AI workspace + Futures Design vision; cut jargon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per-city experience becomes a drafting/refine workspace instead of one-shot suggestions: - New /generate task API (next_steps · draft_proposal · evidence · pathways · future_vision · refine) returning markdown; AiWorkspace renders lens tabs, caches per lens, and offers an iterative Refine bar + Copy. - Futures Design "future vision" lens (Experiential Futures, grounded by a research workflow): a short hopeful "day in the life" with a First-ripple line. - Examples lens is data-driven (matchStories) — no LLM. - Grounding: cityFacts() passes the city's real numbers + real local channels to the model; prompts forbid invented stats/dates (caught + fixed a fabricated "100k trees by 2025"); strip stray ```markdown fences. - Live Scaleway Mistral Small; carbon shown as a token-based estimate, labeled "(est.)" everywhere (EcoLogits can't measure the Scaleway model id). Jargon cleanup: remove the "How it works" section + FlowDiagram; replace user-facing CCRA/GHGI/HIAP/SEEG with global-standard names (emissions inventory, climate-risk assessment, recommended climate actions). Adversarial-review fixes: clear cached content on language switch (no stale language), per-lens loading state (no cross-lens race / duplicate calls), reset refine text on lens change, clipboard fallback, offline-refine note, markdown overflow wrapping, guard non-OK API responses, honest carbon-counter label. Co-Authored-By: Claude Opus 4.8 --- .../civic-climate-action/app/README.md | 39 +- .../app/package-lock.json | 1592 ++++++++++++++++- .../civic-climate-action/app/package.json | 4 +- .../app/src/app/api/generate/route.ts | 110 ++ .../app/src/app/api/localize/route.ts | 133 -- .../app/src/app/components/AiDevelopPanel.tsx | 157 -- .../app/src/app/components/AiWorkspace.tsx | 394 ++++ .../app/src/app/components/CarbonCounter.tsx | 6 +- .../app/src/app/components/CityActions.tsx | 20 +- .../app/src/app/components/FlowDiagram.tsx | 107 -- .../app/src/app/components/Markdown.tsx | 14 + .../app/src/app/data/cities.ts | 16 +- .../app/src/app/globals.css | 68 + .../app/src/app/lib/cityFacts.ts | 91 + .../app/src/app/lib/matchStories.ts | 48 + .../lib/{useLocalize.ts => useGenerate.ts} | 41 +- .../civic-climate-action/app/src/app/page.tsx | 26 +- .../civic-climate-action/llm-service/main.py | 329 ++-- .../llm-service/schemas.py | 19 +- 19 files changed, 2578 insertions(+), 636 deletions(-) create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/FlowDiagram.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/Markdown.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts rename events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/{useLocalize.ts => useGenerate.ts} (54%) diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md index d6985c1..770a558 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/README.md @@ -71,18 +71,19 @@ To refresh the baked HIAP action library: `npm run data:actions`. 1. **The gap** — CityCatalyst is powerful but government-only. Citizens are locked out of their own city's climate plan. -2. **How it works** — the diagram: city planning data → plain language → *Understand, Connect, - Act*. No dashboards to decode. -3. **Explore** — search a city, or click the map. Pick Medellín / Bogotá / a Brazilian city - and read, in everyday language, what residents there did and what you could do. -4. **Prioritized actions** — pick a Brazilian hero city (São Paulo): real CityCatalyst **HIAP** - actions, ranked for *this* city's hazards and emitting sectors, each with a "why this matters - here" trace. Switch EN/ES/PT. Hit **"Make this concrete for my city"** → a cheap, green - open-weight LLM rewrites the action into localized next steps, and the **CO₂ counter** (bottom - right) shows the call's EcoLogits footprint. -5. **The "aha"** — the Inspiration gallery: real, sourced stories of citizens who cooled their - streets, bought their power grid, rewrote climate law. Filter by action type; every claim - links to its source. +2. **Explore** — search a city, or click the map. Pick a pilot city (São Paulo / Porto Alegre): + a one-line plain-language profile (top risks + where emissions come from), then recommended + climate actions ranked for *this* city, each with a "why this matters here" trace. +3. **The workspace** — pick an action and open the AI workspace. It's not one suggestion: tabs for + **Next steps · Draft a proposal · Back it with data · Pathways (short→long) · Examples · Future + vision**. A cheap, green open-weight model (Mistral Small on a low-carbon EU grid) drafts each, + grounded in the city's real numbers and real local channels (Orçamento Participativo, CADES…). + **Refine** any output ("shorter", "more formal", "focus on flooding"), **Copy** the draft. The + **CO₂ counter** (bottom right) shows each call's EcoLogits footprint. +4. **Future vision** — the Futures-Design lens paints a short, hopeful "day in the life" of the + city once the action takes hold — vision, not just guides. +5. **Inspiration** — real, sourced stories of citizens who cooled their streets, bought their + power grid, rewrote climate law. Every claim links to its source. 6. **Who pays** — civic engagement is a co-benefit funders already score; this makes it visible and measurable. B2G, IDB, philanthropy. @@ -93,12 +94,16 @@ To refresh the baked HIAP action library: `npm run data:actions`. - [Leaflet](https://leafletjs.com/) + react-leaflet, with free OpenStreetMap / CARTO basemap tiles - Cities keyed by **UN/LOCODE** — the same key the [CityCatalyst Global API](https://github.com/Open-Earth-Foundation/CityCatalyst/tree/develop/global-api) - uses — so they connect to live GHGI / CCRA / HIAP data (`api.citycatalyst.io`) -- **HIAP action library** baked from `GET /api/v0/climate_actions` (155 actions, EN/ES/PT), + uses — so they connect to live emissions-inventory, climate-risk, and recommended-action data + (`api.citycatalyst.io`) +- **Recommended climate actions** baked from `GET /api/v0/climate_actions` (155 actions, EN/ES/PT), prioritized per city in `src/app/lib/prioritize.ts` -- **Green LLM localizer**: a Python/FastAPI sidecar (`../llm-service`) calling an open-weight - model via an OpenAI-compatible API on a low-carbon EU provider, instrumented with - [EcoLogits](https://ecologits.ai/) for per-call carbon; model/provider is an env-only swap +- **AI workspace**: a Python/FastAPI sidecar (`../llm-service`) with a `/generate` task API + (next-steps · draft proposal · evidence · pathways · future vision · refine), calling an + open-weight model (Mistral Small) via an OpenAI-compatible API on a low-carbon EU provider + (Scaleway), instrumented with [EcoLogits](https://ecologits.ai/) for per-call carbon. Model and + provider are an env-only swap. The "Future vision" lens uses an Experiential-Futures prompt. +- AI output rendered with `react-markdown` (no raw HTML — safe by default) ## Data & Sources diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/package-lock.json b/events/2026-06-11-unlock-the-money/civic-climate-action/app/package-lock.json index 7b05b4e..22c1c50 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/package-lock.json +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/package-lock.json @@ -13,7 +13,9 @@ "next": "^15", "react": "^19", "react-dom": "^19", - "react-leaflet": "^5.0.0" + "react-leaflet": "^5.0.0", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1" }, "devDependencies": { "@types/node": "^22", @@ -651,89 +653,1268 @@ "tslib": "^2.8.0" } }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/leaflet": { "version": "1.9.21", "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.21.tgz", "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", "license": "MIT", "dependencies": { - "@types/geojson": "*" + "@types/geojson": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.21.tgz", + "integrity": "sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "license": "ISC" + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/@types/node": { - "version": "22.19.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.21.tgz", - "integrity": "sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==", - "dev": true, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "dev": true, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "csstype": "^3.2.2" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001799", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", - "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } ], - "license": "CC-BY-4.0" - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/leaflet": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", - "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.12", @@ -805,6 +1986,31 @@ } } }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -839,6 +2045,16 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/react": { "version": "19.2.7", "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", @@ -874,6 +2090,99 @@ "react-dom": "^19.0.0" } }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -947,6 +2256,48 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -970,6 +2321,26 @@ } } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -996,6 +2367,131 @@ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json b/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json index 6877fdd..4c5a4f1 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/package.json @@ -14,7 +14,9 @@ "next": "^15", "react": "^19", "react-dom": "^19", - "react-leaflet": "^5.0.0" + "react-leaflet": "^5.0.0", + "react-markdown": "^10.1.0", + "remark-gfm": "^4.0.1" }, "devDependencies": { "@types/node": "^22", diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts new file mode 100644 index 0000000..e85d295 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts @@ -0,0 +1,110 @@ +// Proxy to the green-LLM sidecar (llm-service) /generate. If the sidecar is +// unreachable, fall back to deterministic templated Markdown so the demo never +// breaks. Adding this route handler means the app runs via `next start` (a Node +// server) rather than a pure static export. + +import { NextResponse } from "next/server"; + +export const runtime = "nodejs"; + +type Lang = "en" | "es" | "pt"; + +type Body = { + task: string; + action: { name: string; description: string; type: "mitigation" | "adaptation" }; + cityContext: { + name: string; + country: string; + topHazards: string[]; + topSectors: string[]; + localSources: string[]; + facts: string[]; + }; + language: Lang; + prior?: string; + instruction?: string; +}; + +const SERVICE_URL = process.env.LLM_SERVICE_URL ?? "http://localhost:8000"; + +export async function POST(req: Request) { + let body: Body; + try { + body = await req.json(); + } catch { + return NextResponse.json({ error: "invalid body" }, { status: 400 }); + } + + try { + const res = await fetch(`${SERVICE_URL}/generate`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + signal: AbortSignal.timeout(30000), + }); + if (res.ok) return NextResponse.json(await res.json()); + } catch { + // fall through + } + + return NextResponse.json({ + content: fallbackContent(body), + energyWh: 0.32, + gCO2e: 0.016, + model: "templated-fallback", + provider: "fallback", + mock: true, + }); +} + +function fallbackContent(b: Body): string { + const c = b.cityContext; + const a = b.action.name; + const channel = c.localSources?.[0] ?? "your city council"; + const lang = b.language; + const T = (en: string, es: string, pt: string) => (lang === "es" ? es : lang === "pt" ? pt : en); + + if (b.task === "future_vision") { + return T( + `**A cooler, calmer corner of ${c.name}**\n\nA few years from now, your block in ${c.name} simply feels better cared for — more shade, cleaner air, fewer worries when the rain comes hard. Neighbors pushed it through ${channel}, and "${a.toLowerCase()}" has quietly reshaped the everyday. It isn't finished, but your corner feels looked after.\n\n*First ripple: the next block asks for the same, and the idea spreads.*`, + `**Un rincón más fresco de ${c.name}**\n\nDentro de unos años, tu cuadra en ${c.name} se siente mejor cuidada — más sombra, aire más limpio, menos preocupación cuando llueve fuerte. Los vecinos lo impulsaron a través de ${channel}, y "${a.toLowerCase()}" cambió el día a día. No está terminado, pero tu rincón se siente atendido.\n\n*Primer efecto: la cuadra de al lado pide lo mismo y la idea se extiende.*`, + `**Um canto mais fresco de ${c.name}**\n\nDaqui a alguns anos, a sua rua em ${c.name} parece mais bem cuidada — mais sombra, ar mais limpo, menos preocupação quando chove forte. Os vizinhos levaram isso adiante pelo ${channel}, e "${a.toLowerCase()}" transformou o dia a dia. Não está pronto, mas o seu canto parece cuidado.\n\n*Primeiro efeito: a rua vizinha pede o mesmo e a ideia se espalha.*` + ); + } + if (b.task === "draft_proposal") { + return T( + `# Proposal: ${a} in ${c.name}\n\nTo: ${channel} \nRe: ${a}\n\n## Why this matters here\nThis action responds directly to our city's top climate concerns.\n\n## What we ask\n- Pilot **${a.toLowerCase()}** in our neighborhood\n\n## Expected benefits\n- A safer, healthier, more comfortable neighborhood\n\n## A note on getting started\nBegin with a small, low-cost pilot on one block.\n\n## How to submit this\nSubmit through **${channel}**.\n\nSincerely, [Your name], [Neighborhood], [Date]`, + `# Propuesta: ${a} en ${c.name}\n\nA: ${channel} \nAsunto: ${a}\n\n## Por qué importa aquí\nEsta acción responde directamente a las principales preocupaciones climáticas de la ciudad.\n\n## Lo que pedimos\n- Probar **${a.toLowerCase()}** en nuestro barrio\n\n## Beneficios esperados\n- Un barrio más seguro, sano y cómodo\n\n## Cómo empezar\nComenzar con un piloto pequeño y de bajo costo en una cuadra.\n\n## Cómo presentarlo\nPresentar a través de **${channel}**.\n\nAtentamente, [Tu nombre], [Barrio], [Fecha]`, + `# Proposta: ${a} em ${c.name}\n\nPara: ${channel} \nAssunto: ${a}\n\n## Por que isto importa aqui\nEsta ação responde diretamente às principais preocupações climáticas da cidade.\n\n## O que pedimos\n- Testar **${a.toLowerCase()}** no nosso bairro\n\n## Benefícios esperados\n- Um bairro mais seguro, saudável e confortável\n\n## Como começar\nComeçar com um piloto pequeno e de baixo custo em uma rua.\n\n## Como enviar\nEnviar pelo **${channel}**.\n\nAtenciosamente, [Seu nome], [Bairro], [Data]` + ); + } + if (b.task === "evidence") { + const facts = (c.facts?.slice(0, 3) ?? []).map((f) => `- ${f}`).join("\n") || "- (see your city's data)"; + return T( + `## Your city's facts\n${facts}\n\n## Widely-known context\n- Local action on this issue improves health and comfort.\n\n## Sources to cite\n- Your city's emissions inventory (via CityCatalyst)\n- Your city's climate-risk assessment\n- IPCC / WRI / C40 city briefs\n\n## Talking points\n- Our own city data backs this action as a practical response.`, + `## Datos de tu ciudad\n${facts}\n\n## Contexto conocido\n- La acción local en este tema mejora la salud y el confort.\n\n## Fuentes para citar\n- El inventario de emisiones de tu ciudad (vía CityCatalyst)\n- La evaluación de riesgo climático de tu ciudad\n- Informes de IPCC / WRI / C40\n\n## Puntos clave\n- Los datos de la propia ciudad respaldan esta acción.`, + `## Dados da sua cidade\n${facts}\n\n## Contexto conhecido\n- A ação local neste tema melhora saúde e conforto.\n\n## Fontes para citar\n- O inventário de emissões da sua cidade (via CityCatalyst)\n- A avaliação de risco climático da sua cidade\n- Relatórios do IPCC / WRI / C40\n\n## Pontos de fala\n- Os dados da própria cidade embasam esta ação.` + ); + } + if (b.task === "pathways") { + return T( + `## Now (most feasible, weeks)\n- **What it is:** A resident-led first step.\n- **Effort / cost:** low / volunteer time\n- **Who's involved:** neighbors\n- **First move:** Gather a few neighbors this week.\n\n## Next (a few months)\n- **What it is:** A funded neighborhood version.\n- **Effort / cost:** medium\n- **Who's involved:** ${channel}\n- **First move:** Propose it through ${channel}.\n\n## Long-term (most ambitious, a year+)\n- **What it is:** A citywide policy or investment.\n- **Effort / cost:** high\n- **Who's involved:** the city council\n- **First move:** Ask your council to take it up.\n\nThese escalate — start at Now and build toward Long-term.`, + `## Ahora (más viable, semanas)\n- **Qué es:** Un primer paso liderado por vecinos.\n- **Esfuerzo / costo:** bajo / tiempo voluntario\n- **Quiénes participan:** vecinos\n- **Primer paso:** Reúne a algunos vecinos esta semana.\n\n## Luego (unos meses)\n- **Qué es:** Una versión financiada a escala de barrio.\n- **Esfuerzo / costo:** medio\n- **Quiénes participan:** ${channel}\n- **Primer paso:** Propónlo a través de ${channel}.\n\n## Largo plazo (más ambicioso, un año+)\n- **Qué es:** Una política o inversión a escala de ciudad.\n- **Esfuerzo / costo:** alto\n- **Quiénes participan:** el concejo municipal\n- **Primer paso:** Pide al concejo que lo retome.\n\nEstos escalan — empieza en Ahora y avanza hacia Largo plazo.`, + `## Agora (mais viável, semanas)\n- **O que é:** Um primeiro passo liderado por moradores.\n- **Esforço / custo:** baixo / tempo voluntário\n- **Quem participa:** vizinhos\n- **Primeiro passo:** Reúna alguns vizinhos esta semana.\n\n## Depois (alguns meses)\n- **O que é:** Uma versão financiada na escala do bairro.\n- **Esforço / custo:** médio\n- **Quem participa:** ${channel}\n- **Primeiro passo:** Proponha pelo ${channel}.\n\n## Longo prazo (mais ambicioso, um ano+)\n- **O que é:** Uma política ou investimento na escala da cidade.\n- **Esforço / custo:** alto\n- **Quem participa:** a câmara municipal\n- **Primeiro passo:** Peça à câmara que assuma o tema.\n\nEles escalam — comece em Agora e avance para Longo prazo.` + ); + } + if (b.task === "refine") { + const note = T( + "\n\n> _Refinement needs the live model — it's offline right now, so the text is unchanged._", + "\n\n> _Refinar requiere el modelo en vivo — está desconectado, así que el texto no cambió._", + "\n\n> _Refinar precisa do modelo ativo — ele está offline, então o texto não mudou._" + ); + return (b.prior || "_(nothing to refine yet)_") + note; + } + // next_steps + return T( + `1. Find a neighborhood group in ${c.name} already working on this.\n2. Bring **${a}** to **${channel}** as a proposal or public comment.\n3. Back it with your city's own climate data.\n4. Invite three neighbors to join and share progress.`, + `1. Busca un grupo vecinal en ${c.name} que ya trabaje en esto.\n2. Lleva **${a}** a **${channel}** como propuesta o comentario público.\n3. Respáldalo con los datos climáticos de tu ciudad.\n4. Invita a tres vecinos a sumarse y comparte el avance.`, + `1. Procure um grupo de bairro em ${c.name} que já atue nisso.\n2. Leve **${a}** ao **${channel}** como proposta ou comentário público.\n3. Embase com os dados climáticos da sua cidade.\n4. Convide três vizinhos e compartilhe o progresso.` + ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts deleted file mode 100644 index dc30aa8..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/localize/route.ts +++ /dev/null @@ -1,133 +0,0 @@ -// Proxy to the green-LLM sidecar (llm-service). If the sidecar is unreachable, -// fall back to a deterministic templated localization so the demo never breaks. -// Adding this route handler is the one thing that makes the app need a Node -// server (next start) rather than a pure static export. - -import { NextResponse } from "next/server"; - -export const runtime = "nodejs"; - -type Body = { - action: { name: string; description: string; type: "mitigation" | "adaptation" }; - cityContext: { - name: string; - country: string; - topHazards: string[]; - topSectors: string[]; - localSources: string[]; - }; - language: "en" | "es" | "pt"; -}; - -const SERVICE_URL = process.env.LLM_SERVICE_URL ?? "http://localhost:8000"; - -export async function POST(req: Request) { - let body: Body; - try { - body = await req.json(); - } catch { - return NextResponse.json({ error: "invalid body" }, { status: 400 }); - } - - // Try the sidecar first (real or mock-mode EcoLogits measurement). - try { - const res = await fetch(`${SERVICE_URL}/localize`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), - signal: AbortSignal.timeout(8000), - }); - if (res.ok) return NextResponse.json(await res.json()); - } catch { - // fall through to local fallback - } - - return NextResponse.json(fallbackLocalize(body)); -} - -// Deterministic templated localization — mirrors the sidecar's mock mode so the -// click-through and CO₂ counter work even with the sidecar down. -function fallbackLocalize(body: Body) { - const { action, cityContext, language } = body; - const city = cityContext.name; - const rawFocus = - action.type === "adaptation" - ? cityContext.topHazards[0] ?? "climate risk" - : cityContext.topSectors[0] ?? "emissions"; - const focus = translateFocus(rawFocus, language); - const channel = cityContext.localSources?.[0] ?? null; - - const steps = templates(language, city, focus, action.name, channel); - // Token-based estimate consistent with the sidecar (small open model, low-carbon - // EU grid): ~350 tokens × 0.0009 Wh × 0.052 gCO2e/Wh. - return { - localizedSteps: steps, - energyWh: 0.32, - gCO2e: 0.016, - model: "templated-fallback", - provider: "fallback", - mock: true, - }; -} - -// Localize the matched hazard/sector term so templated steps read naturally. -function translateFocus(raw: string, lang: "en" | "es" | "pt"): string { - if (lang === "en") return raw.toLowerCase(); - const s = raw.toLowerCase(); - const map: Record = { - // [es, pt] - heat: ["las olas de calor", "as ondas de calor"], - landslide: ["los deslizamientos", "os deslizamentos"], - flood: ["las inundaciones", "as inundações"], - drought: ["la sequía", "a seca"], - disease: ["las enfermedades", "as doenças"], - "sea-level": ["el aumento del nivel del mar", "a elevação do nível do mar"], - storm: ["las tormentas", "as tempestades"], - wildfire: ["los incendios", "os incêndios"], - transport: ["el transporte", "o transporte"], - energy: ["la energía", "a energia"], - waste: ["los residuos", "os resíduos"], - stationary: ["la energía", "a energia"], - }; - for (const key of Object.keys(map)) { - if (s.includes(key)) return lang === "es" ? map[key][0] : map[key][1]; - } - return s; -} - -function templates( - lang: "en" | "es" | "pt", - city: string, - focus: string, - action: string, - channel: string | null -): string[] { - if (lang === "es") { - return [ - `Identifica en ${city} a un grupo vecinal o colectivo que ya trabaje en ${focus}.`, - channel - ? `Lleva esta acción a ${channel} como propuesta o comentario público.` - : `Asiste a la próxima sesión del consejo municipal donde se discuta "${action}".`, - `Documenta el riesgo local con datos para respaldar la propuesta.`, - `Invita a tres vecinos a sumarse y comparte el avance en tu comunidad.`, - ]; - } - if (lang === "pt") { - return [ - `Identifique em ${city} um grupo de bairro ou coletivo que já atue em ${focus}.`, - channel - ? `Leve esta ação ao ${channel} como proposta ou comentário público.` - : `Participe da próxima sessão do conselho municipal onde "${action}" for discutida.`, - `Documente o risco local com dados para embasar a proposta.`, - `Convide três vizinhos para participar e compartilhe o progresso na sua comunidade.`, - ]; - } - return [ - `Find a neighborhood group or collective in ${city} already working on ${focus}.`, - channel - ? `Bring this action to ${channel} as a proposal or public comment.` - : `Attend the next city-council session where "${action}" is on the agenda.`, - `Back it with local risk data to make the case.`, - `Invite three neighbors to join and share progress in your community.`, - ]; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx deleted file mode 100644 index 7f98615..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiDevelopPanel.tsx +++ /dev/null @@ -1,157 +0,0 @@ -"use client"; - -import type { Lang } from "../data/climateActions"; -import type { LocalSource } from "../data/localEngagement"; -import type { RankedAction } from "../lib/prioritize"; -import { useLocalize } from "../lib/useLocalize"; - -const typeColor = { adaptation: "var(--accent)", mitigation: "#d97706" } as const; - -const t = { - develop: { en: "Develop this with AI", es: "Desarrollar con IA", pt: "Desenvolver com IA" }, - regenerate: { en: "Regenerate", es: "Regenerar", pt: "Regenerar" }, - working: { en: "Developing a local plan…", es: "Generando un plan local…", pt: "Gerando um plano local…" }, - plan: { en: "Your local plan", es: "Tu plan local", pt: "Seu plano local" }, - empty: { - en: "Pick an action on the left, then develop a concrete plan grounded in", - es: "Elige una acción a la izquierda y desarrolla un plan concreto basado en", - pt: "Escolha uma ação à esquerda e desenvolva um plano concreto baseado em", - }, - where: { en: "Where to engage locally", es: "Dónde participar localmente", pt: "Onde participar localmente" }, - estimated: { en: "estimated", es: "estimado", pt: "estimado" }, -}; - -export default function AiDevelopPanel({ - ranked, - cityName, - cityContext, - localSources, - lang, -}: { - ranked: RankedAction; - cityName: string; - cityContext: { country: string; topHazards: string[]; topSectors: string[]; localSources: string[] }; - localSources: LocalSource[]; - lang: Lang; -}) { - const { action } = ranked; - const { run, loading, result } = useLocalize(); - - function develop() { - run({ - action: { name: action.name[lang], description: action.description[lang], type: action.actionType }, - cityContext: { name: cityName, ...cityContext }, - language: lang, - }); - } - - return ( -
- - {action.actionType} - -

{action.name[lang]}

-

- {action.description[lang].length > 240 - ? action.description[lang].slice(0, 237).trimEnd() + "…" - : action.description[lang]} -

- - {!result && !loading && ( - <> -

- {t.empty[lang]} {cityName}. -

- - - )} - - {loading &&
{t.working[lang]}
} - - {result && ( -
-
- {t.plan[lang]} -
-
    - {result.localizedSteps.map((step, i) => ( -
  1. - {step} -
  2. - ))} -
-
- - - ~{result.gCO2e.toFixed(3)} g CO₂e ({t.estimated[lang]}) · {result.model} - -
-
- )} - - {localSources.length > 0 && ( -
-
- {t.where[lang]} -
-
- {localSources.slice(0, 8).map((s) => ( - - {s.name} ↗ - - ))} -
-
- )} -
- ); -} - -const ctaStyle: React.CSSProperties = { - font: "inherit", - fontSize: "0.9rem", - fontWeight: 650, - cursor: "pointer", - color: "#fff", - background: "var(--accent)", - border: "none", - borderRadius: 8, - padding: "0.6rem 1rem", - width: "100%", -}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx new file mode 100644 index 0000000..1ee301d --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx @@ -0,0 +1,394 @@ +"use client"; + +import { useEffect, useMemo, useState } from "react"; +import type { Lang } from "../data/climateActions"; +import type { LocalSource } from "../data/localEngagement"; +import type { RankedAction } from "../lib/prioritize"; +import { useGenerate, type GenResult, type GenTask } from "../lib/useGenerate"; +import { stories } from "../data/stories"; +import { matchStories } from "../lib/matchStories"; +import { categoryMeta } from "../data/types"; +import Markdown from "./Markdown"; + +type LensKey = GenTask | "examples"; + +type CityContext = { + country: string; + topHazards: string[]; + topSectors: string[]; + localSources: string[]; + facts: string[]; +}; + +const LENSES: { + key: LensKey; + llm: boolean; + label: Record; + desc: Record; +}[] = [ + { + key: "next_steps", + llm: true, + label: { en: "Next steps", es: "Próximos pasos", pt: "Próximos passos" }, + desc: { + en: "Concrete moves you can make in the coming weeks.", + es: "Acciones concretas para las próximas semanas.", + pt: "Ações concretas para as próximas semanas.", + }, + }, + { + key: "draft_proposal", + llm: true, + label: { en: "Draft a proposal", es: "Redactar propuesta", pt: "Redigir proposta" }, + desc: { + en: "A ready-to-send draft for your town hall.", + es: "Un borrador listo para enviar a tu municipio.", + pt: "Um rascunho pronto para enviar à prefeitura.", + }, + }, + { + key: "evidence", + llm: true, + label: { en: "Back it with data", es: "Respáldalo con datos", pt: "Embase com dados" }, + desc: { + en: "Facts and sources to make your case.", + es: "Datos y fuentes para sustentar tu caso.", + pt: "Dados e fontes para embasar seu caso.", + }, + }, + { + key: "pathways", + llm: true, + label: { en: "Pathways", es: "Rutas", pt: "Caminhos" }, + desc: { + en: "From a quick first move to citywide change.", + es: "De un primer paso a un cambio en toda la ciudad.", + pt: "De um primeiro passo à mudança em toda a cidade.", + }, + }, + { + key: "examples", + llm: false, + label: { en: "Examples", es: "Ejemplos", pt: "Exemplos" }, + desc: { + en: "Where this has already worked.", + es: "Dónde ya ha funcionado.", + pt: "Onde isto já funcionou.", + }, + }, + { + key: "future_vision", + llm: true, + label: { en: "Future vision", es: "Visión de futuro", pt: "Visão de futuro" }, + desc: { + en: "Picture your city once this takes hold.", + es: "Imagina tu ciudad cuando esto se afiance.", + pt: "Imagine sua cidade quando isto se firmar.", + }, + }, +]; + +const t = { + generate: { en: "Generate", es: "Generar", pt: "Gerar" }, + regenerate: { en: "Regenerate", es: "Regenerar", pt: "Regenerar" }, + working: { en: "Working…", es: "Generando…", pt: "Gerando…" }, + copy: { en: "Copy", es: "Copiar", pt: "Copiar" }, + copied: { en: "Copied", es: "Copiado", pt: "Copiado" }, + refinePh: { + en: "Refine — e.g. shorter, more formal, focus on flooding…", + es: "Refinar — p. ej. más corto, más formal, enfocar en inundaciones…", + pt: "Refinar — ex. mais curto, mais formal, focar em enchentes…", + }, + refine: { en: "Refine", es: "Refinar", pt: "Refinar" }, + where: { en: "Where to engage locally", es: "Dónde participar localmente", pt: "Onde participar localmente" }, + estimated: { en: "est.", es: "est.", pt: "est." }, + futureLabel: { en: "An imagined near future", es: "Un futuro cercano imaginado", pt: "Um futuro próximo imaginado" }, + noExamples: { en: "No close examples yet — browse the Inspiration gallery below.", es: "Aún sin ejemplos cercanos — mira la galería de Inspiración abajo.", pt: "Ainda sem exemplos próximos — veja a galeria de Inspiração abaixo." }, +}; + +const typeColor = { adaptation: "var(--accent)", mitigation: "#d97706" } as const; + +export default function AiWorkspace({ + ranked, + cityName, + cityContext, + localSources, + lang, +}: { + ranked: RankedAction; + cityName: string; + cityContext: CityContext; + localSources: LocalSource[]; + lang: Lang; +}) { + const { action } = ranked; + const { run } = useGenerate(); + const [active, setActive] = useState("next_steps"); + const [cache, setCache] = useState>>({}); + const [pendingSet, setPendingSet] = useState>(new Set()); + const [refineText, setRefineText] = useState(""); + const [copied, setCopied] = useState(false); + + // Reset transient input/feedback when the lens changes (don't carry a refine + // instruction or a "Copied" flag across lenses). + useEffect(() => { + setRefineText(""); + setCopied(false); + }, [active]); + + const exampleStories = useMemo(() => matchStories(action, stories), [action]); + + const lens = LENSES.find((l) => l.key === active)!; + const result = cache[active]; + + async function generate(task: GenTask, opts: { prior?: string; instruction?: string } = {}) { + const lensKey = active; // capture: the lens this generation belongs to + setPendingSet((p) => new Set(p).add(lensKey)); + const res = await run({ + task, + action: { name: action.name[lang], description: action.description[lang], type: action.actionType }, + cityContext: { name: cityName, ...cityContext }, + language: lang, + ...opts, + }); + setPendingSet((p) => { + const n = new Set(p); + n.delete(lensKey); + return n; + }); + if (res) setCache((c) => ({ ...c, [lensKey]: res })); + } + + function onRefine() { + if (!result || !refineText.trim()) return; + generate("refine", { prior: result.content, instruction: refineText.trim() }); + setRefineText(""); + } + + function copy() { + if (!result) return; + const done = () => { + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }; + if (navigator.clipboard?.writeText) { + navigator.clipboard.writeText(result.content).then(done).catch(fallbackCopy); + } else { + fallbackCopy(); + } + function fallbackCopy() { + try { + const ta = document.createElement("textarea"); + ta.value = result!.content; + ta.style.position = "fixed"; + ta.style.opacity = "0"; + document.body.appendChild(ta); + ta.select(); + document.execCommand("copy"); + document.body.removeChild(ta); + done(); + } catch { + /* clipboard unavailable */ + } + } + } + + const isLoading = pendingSet.has(active); + + return ( +
+ {/* Action header */} +
+ + {action.actionType} + +

{action.name[lang]}

+
+ + {/* Lens tabs */} +
+ {LENSES.map((l) => ( + + ))} +
+ + {/* Lens body */} +
+

+ {lens.desc[lang]} +

+ + {active === "examples" ? ( + + ) : isLoading ? ( +
{t.working[lang]}
+ ) : !result ? ( + + ) : ( +
+ {active === "future_vision" && ( +
+ {t.futureLabel[lang]} +
+ )} + {result.content} + + {/* Refine bar */} +
+ setRefineText(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && onRefine()} + placeholder={t.refinePh[lang]} + style={{ + flex: 1, + padding: "0.5rem 0.7rem", + border: "1px solid var(--line)", + borderRadius: 8, + fontSize: "0.85rem", + background: "var(--bg)", + outlineColor: "var(--accent)", + }} + /> + +
+ + {/* Actions + carbon */} +
+ + + {isLoading ? ( + {t.working[lang]} + ) : ( + + ~{result.gCO2e.toFixed(3)} g CO₂e ({t.estimated[lang]}) · {result.model} + + )} +
+
+ )} +
+ + {/* Local sources footer */} + {localSources.length > 0 && ( +
+
+ {t.where[lang]} +
+
+ {localSources.slice(0, 8).map((s) => ( + + {s.name} ↗ + + ))} +
+
+ )} +
+ ); +} + +function ExamplesList({ stories, lang }: { stories: ReturnType; lang: Lang }) { + if (stories.length === 0) { + return

{t.noExamples[lang]}

; + } + return ( +
+ {stories.map((s) => { + const m = categoryMeta[s.category]; + return ( +
+
+ {m.label} + + {s.city}, {s.country} + +
+
{s.title}
+

{s.outcome}

+ + {s.sourceName} ↗ + +
+ ); + })} +
+ ); +} + +const ctaStyle: React.CSSProperties = { + font: "inherit", + fontSize: "0.9rem", + fontWeight: 650, + cursor: "pointer", + color: "#fff", + background: "var(--accent)", + border: "none", + borderRadius: 8, + padding: "0.6rem 1rem", +}; + +const smallBtn: React.CSSProperties = { + font: "inherit", + fontSize: "0.78rem", + fontWeight: 600, + cursor: "pointer", + color: "var(--accent)", + background: "var(--accent-soft)", + border: "none", + borderRadius: 8, + padding: "0.35rem 0.7rem", +}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx index ccd0dd8..2415a13 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CarbonCounter.tsx @@ -9,7 +9,7 @@ export default function CarbonCounter() { return (
- {totalGramsCO2e.toFixed(2)} g CO₂e - · {callCount} AI {callCount === 1 ? "call" : "calls"} + ~{totalGramsCO2e.toFixed(2)} g CO₂e + (est.) · {callCount} AI {callCount === 1 ? "call" : "calls"}
); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx index 4beae45..734c6ff 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx @@ -6,8 +6,9 @@ import type { Lang } from "../data/climateActions"; import { climateActions } from "../data/climateActions"; import { prioritizeActions } from "../lib/prioritize"; import { localSourcesByCity, localSourceNamesByCity } from "../data/localSources"; +import { cityFacts } from "../lib/cityFacts"; import ActionRow from "./ActionRow"; -import AiDevelopPanel from "./AiDevelopPanel"; +import AiWorkspace from "./AiWorkspace"; const LANGS: { key: Lang; label: string }[] = [ { key: "en", label: "EN" }, @@ -24,9 +25,9 @@ const defaultLang = (country: string): Lang => { const copy = { heading: { en: "Develop an action for", es: "Desarrolla una acción para", pt: "Desenvolva uma ação para" }, intro: { - en: "Priorities from CityCatalyst's HIAP library, ranked for this city. Pick one and build a concrete, local plan.", - es: "Prioridades de la biblioteca HIAP de CityCatalyst, ordenadas para esta ciudad. Elige una y crea un plan local concreto.", - pt: "Prioridades da biblioteca HIAP do CityCatalyst, ordenadas para esta cidade. Escolha uma e crie um plano local concreto.", + en: "Recommended climate actions for this city, from CityCatalyst. Pick one and build a concrete, local plan.", + es: "Acciones climáticas recomendadas para esta ciudad, según CityCatalyst. Elige una y crea un plan local concreto.", + pt: "Ações climáticas recomendadas para esta cidade, segundo o CityCatalyst. Escolha uma e crie um plano local concreto.", }, }; @@ -40,11 +41,14 @@ export default function CityActions({ city }: { city: City }) { const cityContext = { country: city.country, - topHazards: (city.risk?.topHazards ?? []).map((h) => h.hazard), + topHazards: (city.risk?.topHazards ?? []).map( + (h) => `${h.hazard} (${h.level})` + ), topSectors: - city.emissions?.sectors?.map((s) => s.sector) ?? + city.emissions?.sectors?.map((s) => `${s.sector} (${Math.round(s.sharePct)}%)`) ?? (city.emissions?.topSector ? [city.emissions.topSector] : []), localSources: localSourceNamesByCity[city.id] ?? [], + facts: cityFacts(city, lang), }; const localSources = localSourcesByCity[city.id] ?? []; @@ -96,8 +100,8 @@ export default function CityActions({ city }: { city: City }) { ))}
- - {/* Inputs */} -
-
- CityCatalyst data -
- {inputs.map((i) => ( -
-
- {i.label} - - {i.code} - -
-
{i.desc}
-
- ))} -
- - {/* Translation layer */} -
-
- → -
-
- translation layer -
-
- → -
-
- - {/* Outputs */} -
-
- What a citizen gets -
- {outputs.map((o, n) => ( -
-
- {n + 1}. {o.label} -
-
{o.desc}
-
- ))} -
-
- ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/Markdown.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/Markdown.tsx new file mode 100644 index 0000000..6509988 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/Markdown.tsx @@ -0,0 +1,14 @@ +"use client"; + +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; + +// Minimal markdown renderer for AI-generated content. Styling lives in +// globals.css under `.md`. +export default function Markdown({ children }: { children: string }) { + return ( +
+ {children} +
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts index 21bc9a3..5659895 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts @@ -110,7 +110,7 @@ export const cities: City[] = [ ], inventoryYear: "2023 / 2022 (waste)", note: BR_PARTIAL_NOTE, - source: "CityCatalyst Global API (SEEG, SINIR, SNIS)", + source: "CityCatalyst · emissions inventory", sourceUrl: "https://api.citycatalyst.io", }, risk: { @@ -119,7 +119,7 @@ export const cities: City[] = [ { hazard: "Floods", keyImpact: "infrastructure", level: "Very High" }, ], year: 2024, - source: "CityCatalyst CCRA", + source: "CityCatalyst · climate-risk assessment", sourceUrl: "https://api.citycatalyst.io", }, }, @@ -149,7 +149,7 @@ export const cities: City[] = [ ], inventoryYear: "2023 / 2022 (waste)", note: BR_PARTIAL_NOTE, - source: "CityCatalyst Global API (SEEG, SINIR, SNIS)", + source: "CityCatalyst · emissions inventory", sourceUrl: "https://api.citycatalyst.io", }, risk: { @@ -158,7 +158,7 @@ export const cities: City[] = [ { hazard: "Landslides", keyImpact: "infrastructure", level: "Very High" }, ], year: 2024, - source: "CityCatalyst CCRA", + source: "CityCatalyst · climate-risk assessment", sourceUrl: "https://api.citycatalyst.io", }, }, @@ -187,7 +187,7 @@ export const cities: City[] = [ ], inventoryYear: "2023 / 2022 (waste)", note: BR_PARTIAL_NOTE, - source: "CityCatalyst Global API (SEEG, SINIR, SNIS)", + source: "CityCatalyst · emissions inventory", sourceUrl: "https://api.citycatalyst.io", }, risk: { @@ -196,7 +196,7 @@ export const cities: City[] = [ { hazard: "Landslides", keyImpact: "infrastructure", level: "Very High" }, ], year: 2024, - source: "CityCatalyst CCRA", + source: "CityCatalyst · climate-risk assessment", sourceUrl: "https://api.citycatalyst.io", }, }, @@ -225,7 +225,7 @@ export const cities: City[] = [ ], inventoryYear: "2023 / 2022 (waste)", note: BR_PARTIAL_NOTE, - source: "CityCatalyst Global API (SEEG, SINIR, SNIS)", + source: "CityCatalyst · emissions inventory", sourceUrl: "https://api.citycatalyst.io", }, risk: { @@ -234,7 +234,7 @@ export const cities: City[] = [ { hazard: "Floods", keyImpact: "infrastructure", level: "Very High" }, ], year: 2024, - source: "CityCatalyst CCRA", + source: "CityCatalyst · climate-risk assessment", sourceUrl: "https://api.citycatalyst.io", }, }, diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css index 74952dd..da2ea3f 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css @@ -107,3 +107,71 @@ a:hover { grid-template-columns: 1fr; } } + +/* AI-generated markdown content */ +.md { + font-size: 0.92rem; + line-height: 1.55; + color: var(--ink); + overflow-wrap: anywhere; + word-break: break-word; +} +.md pre { + white-space: pre-wrap; + overflow-x: auto; + background: var(--bg-soft); + border: 1px solid var(--line); + border-radius: 8px; + padding: 0.6rem 0.8rem; + font-size: 0.85rem; +} +.md code { + word-break: break-word; +} +.md > :first-child { + margin-top: 0; +} +.md > :last-child { + margin-bottom: 0; +} +.md h1 { + font-size: 1.2rem; + margin: 0 0 0.5rem; +} +.md h2 { + font-size: 0.82rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--accent); + margin: 1rem 0 0.4rem; +} +.md h3 { + font-size: 1rem; + margin: 0.9rem 0 0.3rem; +} +.md p { + margin: 0 0 0.6rem; +} +.md ul, +.md ol { + margin: 0 0 0.6rem; + padding-left: 1.2rem; +} +.md li { + margin-bottom: 0.3rem; +} +.md strong { + font-weight: 650; +} +.md em { + color: var(--ink-soft); +} +.md a { + color: var(--accent); +} +.md blockquote { + margin: 0.6rem 0; + padding-left: 0.8rem; + border-left: 3px solid var(--line); + color: var(--ink-soft); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts new file mode 100644 index 0000000..42aadc3 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts @@ -0,0 +1,91 @@ +// Plain factual lines derived from a city's real data, in the user's language. +// These are passed to the LLM as the ONLY numbers it may use, so the generated +// content stays grounded and honest. + +import type { City, RiskLevel } from "../data/types"; +import type { HazardKey, Lang } from "../data/climateActions"; +import { normalizeHazard, normalizeSector } from "./hazardNormalize"; + +const LEVEL_ORDER: Record = { "Very High": 4, High: 3, Medium: 2, Low: 1 }; + +const LEVEL_WORD: Record> = { + "Very High": { en: "Very High", es: "Muy alto", pt: "Muito alto" }, + High: { en: "High", es: "Alto", pt: "Alto" }, + Medium: { en: "Medium", es: "Medio", pt: "Médio" }, + Low: { en: "Low", es: "Bajo", pt: "Baixo" }, +}; + +const HAZARD_WORD: Record> = { + heatwaves: { en: "Heatwaves", es: "Las olas de calor", pt: "As ondas de calor" }, + landslides: { en: "Landslides", es: "Los deslizamientos", pt: "Os deslizamentos" }, + floods: { en: "Flooding", es: "Las inundaciones", pt: "As inundações" }, + droughts: { en: "Drought", es: "La sequía", pt: "A seca" }, + diseases: { en: "Climate-related disease", es: "Las enfermedades", pt: "As doenças" }, + "sea-level-rise": { en: "Sea-level rise", es: "El aumento del nivel del mar", pt: "A elevação do nível do mar" }, + storms: { en: "Storms", es: "Las tormentas", pt: "As tempestades" }, + wildfires: { en: "Wildfire", es: "Los incendios", pt: "Os incêndios" }, +}; + +const SECTOR_WORD: Record> = { + transportation: { en: "Transportation", es: "El transporte", pt: "O transporte" }, + stationary_energy: { en: "Energy use in buildings", es: "La energía en edificios", pt: "A energia em edifícios" }, + waste: { en: "Waste", es: "Los residuos", pt: "Os resíduos" }, + ippu: { en: "Industry", es: "La industria", pt: "A indústria" }, + afolu: { en: "Land use", es: "El uso del suelo", pt: "O uso do solo" }, +}; + +function formatCo2e(t: number, lang: Lang): string { + const unit = (n: number, u: string) => + `${n.toLocaleString(lang === "en" ? "en-US" : lang === "es" ? "es" : "pt-BR")} ${u}`; + if (t >= 1_000_000) return unit(Number((t / 1_000_000).toFixed(1)), "Mt"); + if (t >= 1_000) return unit(Math.round(t / 1_000), "kt"); + return unit(Math.round(t), "t"); +} + +export function cityFacts(city: City, lang: Lang): string[] { + const facts: string[] = []; + + // Top distinct hazards (highest severity), up to 2. + const byKey = new Map(); + for (const h of city.risk?.topHazards ?? []) { + for (const k of normalizeHazard(h.hazard)) { + const prev = byKey.get(k); + if (!prev || LEVEL_ORDER[h.level] > LEVEL_ORDER[prev]) byKey.set(k, h.level); + } + } + for (const [key, level] of [...byKey.entries()].slice(0, 2)) { + const hz = HAZARD_WORD[key][lang]; + const lv = LEVEL_WORD[level][lang]; + if (lang === "es") facts.push(`${hz} tienen un riesgo climático ${lv} en ${city.name}.`); + else if (lang === "pt") facts.push(`${hz} têm risco climático ${lv} em ${city.name}.`); + else facts.push(`${hz} are rated ${lv} climate risk in ${city.name}.`); + } + + // Dominant emitting sector by share. + const e = city.emissions; + if (e?.sectors?.length) { + const top = [...e.sectors].sort((a, b) => b.sharePct - a.sharePct)[0]; + const key = normalizeSector(top.sector); + const word = key ? SECTOR_WORD[key][lang] : top.sector; + const pct = Math.round(top.sharePct); + if (lang === "es") facts.push(`${word} es cerca del ${pct}% de las emisiones medidas de ${city.name}.`); + else if (lang === "pt") facts.push(`${word} é cerca de ${pct}% das emissões medidas de ${city.name}.`); + else facts.push(`${word} is about ${pct}% of ${city.name}'s measured emissions.`); + } else if (e?.topSector) { + const key = normalizeSector(e.topSector); + const word = key ? SECTOR_WORD[key][lang] : e.topSector; + if (lang === "es") facts.push(`${word} es la mayor fuente de emisiones de ${city.name}.`); + else if (lang === "pt") facts.push(`${word} é a maior fonte de emissões de ${city.name}.`); + else facts.push(`${word} is the largest emissions source in ${city.name}.`); + } + + // City total emissions. + if (e?.totalTonnesCo2e) { + const v = formatCo2e(e.totalTonnesCo2e, lang); + if (lang === "es") facts.push(`Las emisiones medidas de ${city.name} son de unas ${v} CO₂e al año.`); + else if (lang === "pt") facts.push(`As emissões medidas de ${city.name} são cerca de ${v} CO₂e por ano.`); + else facts.push(`${city.name}'s measured emissions are about ${v} CO₂e per year.`); + } + + return facts; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts new file mode 100644 index 0000000..08f7e0b --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts @@ -0,0 +1,48 @@ +// Match real success stories to a chosen action (data-driven, no LLM) for the +// "Examples" lens — so a resident sees where this kind of action already worked. + +import type { ClimateAction } from "../data/climateActions"; +import type { Story, Category } from "../data/types"; + +function categoriesFor(action: ClimateAction): Set { + const out = new Set(); + for (const s of action.sectors) { + if (/transport|mobil|road/.test(s)) out.add("Mobility"); + if (/energy/.test(s)) out.add("Energy"); + if (/waste/.test(s)) out.add("Waste"); + if (/afolu|land|forest|biodiv|green/.test(s)) out.add("Greening"); + if (/water|flood|geo|disaster|resilien/.test(s)) out.add("Resilience"); + if (/air|health/.test(s)) { + out.add("AirQuality"); + out.add("Resilience"); + } + } + for (const h of action.hazards) { + if (h === "heatwaves" || h === "wildfires") { + out.add("Greening"); + out.add("Resilience"); + } else { + out.add("Resilience"); // floods, landslides, storms, sea-level-rise, droughts, diseases + } + } + if (out.size === 0) out.add(action.actionType === "adaptation" ? "Resilience" : "Participation"); + return out; +} + +export function matchStories(action: ClimateAction, stories: Story[], limit = 4): Story[] { + const cats = categoriesFor(action); + const primary = stories.filter((s) => cats.has(s.category)); + // Always offer at least one "how change happened" participation example. + const participation = stories.filter( + (s) => s.category === "Participation" && !primary.includes(s) + ); + const seen = new Set(); + const out: Story[] = []; + for (const s of [...primary, ...participation]) { + if (out.length >= limit) break; + if (seen.has(s.id)) continue; + seen.add(s.id); + out.push(s); + } + return out; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts similarity index 54% rename from events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts rename to events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts index a331075..7184cf0 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useLocalize.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts @@ -4,7 +4,16 @@ import { useCallback, useState } from "react"; import type { Lang } from "../data/climateActions"; import { useCarbon } from "./carbonContext"; -export type LocalizeRequest = { +export type GenTask = + | "next_steps" + | "draft_proposal" + | "evidence" + | "pathways" + | "future_vision" + | "refine"; + +export type GenerateRequest = { + task: GenTask; action: { name: string; description: string; type: "mitigation" | "adaptation" }; cityContext: { name: string; @@ -12,12 +21,15 @@ export type LocalizeRequest = { topHazards: string[]; topSectors: string[]; localSources: string[]; + facts: string[]; }; language: Lang; + prior?: string; + instruction?: string; }; -export type LocalizeResult = { - localizedSteps: string[]; +export type GenResult = { + content: string; energyWh: number; gCO2e: number; model: string; @@ -25,27 +37,26 @@ export type LocalizeResult = { mock: boolean; }; -export function useLocalize() { +export function useGenerate() { const { addUsage } = useCarbon(); const [loading, setLoading] = useState(false); - const [result, setResult] = useState(null); - const [error, setError] = useState(null); const run = useCallback( - async (req: LocalizeRequest) => { + async (req: GenerateRequest): Promise => { setLoading(true); - setError(null); try { - const res = await fetch("/api/localize", { + const res = await fetch("/api/generate", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(req), }); - const data: LocalizeResult = await res.json(); - setResult(data); - addUsage(data.gCO2e, data.energyWh); - } catch (e) { - setError(String(e)); + if (!res.ok) return null; + const data: GenResult = await res.json(); + if (typeof data?.content !== "string") return null; + addUsage(data.gCO2e ?? 0, data.energyWh ?? 0); + return data; + } catch { + return null; } finally { setLoading(false); } @@ -53,5 +64,5 @@ export function useLocalize() { [addUsage] ); - return { run, loading, result, error }; + return { run, loading }; } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx index 1093405..4181eb3 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx @@ -1,4 +1,3 @@ -import FlowDiagram from "./components/FlowDiagram"; import CityExplorer from "./components/CityExplorer"; import StoriesGallery from "./components/StoriesGallery"; import TakeAction from "./components/TakeAction"; @@ -27,22 +26,6 @@ export default function Home() {
- {/* How it works */} -
-
-
How it works
-

- From city data to things you can actually do -

-

- We take the same data cities use to plan — their emissions inventory, climate-risk - assessment, and prioritized actions — and translate it into plain language and concrete - next steps. No jargon, no dashboards to decode. -

- -
-
- {/* Explore cities */}
@@ -101,11 +84,10 @@ export default function Home() {

- Built for OEF Hackday 26Q2. Brazilian cities pull live emissions and climate-risk data - from the CityCatalyst Global API (SEEG inventory · CCRA risk); other cities use the - latest verified inventories and risk profiles from official sources. Every figure and - success story links to its source — look for the “CityCatalyst live” vs - “External source” badge. + Built for OEF Hackday 26Q2. Brazilian cities pull live emissions-inventory and + climate-risk data from CityCatalyst; other cities use the latest verified inventories + and risk assessments from official sources. Every figure and success story links to its + source — look for the “CityCatalyst live” vs “External source” badge.

diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py index 21f6096..9845e27 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py @@ -1,9 +1,11 @@ -"""Green/cheap LLM localizer sidecar. +"""Green/cheap LLM generation sidecar for the Civic Climate Action workspace. -Turns a chosen CityCatalyst HIAP action + a city's climate profile into concrete, -localized, executable next steps (EN/ES/PT) using a low-carbon open-weight model -through an OpenAI-compatible API, and reports the per-call carbon footprint via -EcoLogits. Runs in mock mode with zero secrets so the demo always works. +Given a city's climate profile + a chosen action, generates one of several +"lenses" — concrete next steps, a draft proposal to the town hall, evidence to +back the concern, short→long-term pathways, or a Futures-Design "vision of the +future" — and can refine any of them from a free-text instruction. Uses a +low-carbon open-weight model via an OpenAI-compatible API and reports the +per-call carbon footprint with EcoLogits. Runs in mock mode with zero secrets. Run: uvicorn main:app --port 8000 """ @@ -20,11 +22,23 @@ import providers import ecolog -from schemas import LocalizeRequest, LocalizeResponse +from schemas import GenerateRequest, GenerateResponse -app = FastAPI(title="Civic Climate Action — LLM Localizer") +app = FastAPI(title="Civic Climate Action — Generation Service") ecolog.init() +_LANG_NAME = {"en": "English", "es": "Spanish", "pt": "Brazilian Portuguese"} + +# Per-task completion budgets (the future vision is one short paragraph). +_MAX_TOKENS = { + "next_steps": 500, + "draft_proposal": 800, + "evidence": 700, + "pathways": 800, + "future_vision": 380, + "refine": 800, +} + @app.get("/health") def health(): @@ -37,143 +51,238 @@ def health(): } -@app.post("/localize", response_model=LocalizeResponse) -def localize(req: LocalizeRequest): +@app.post("/generate", response_model=GenerateResponse) +def generate(req: GenerateRequest): provider, base_url, model, api_key = providers.get_config() + task = req.task if req.task in _MAX_TOKENS else "next_steps" if providers.is_mock(): - return LocalizeResponse( - localizedSteps=mock_steps(req), + return GenerateResponse( + content=mock_content(req, task), model=model or "mock-small", provider=provider, mock=True, **ecolog.estimate(), ) - # Real path: OpenAI-compatible call, wrapped by EcoLogits. from openai import OpenAI client = OpenAI(base_url=base_url, api_key=api_key) resp = client.chat.completions.create( model=model, messages=[ - {"role": "system", "content": _system(req.language)}, - {"role": "user", "content": _prompt(req)}, + {"role": "system", "content": _system(task, req.language)}, + {"role": "user", "content": _user(req, task)}, ], - temperature=0.4, - max_tokens=500, + temperature=0.5 if task == "future_vision" else 0.4, + max_tokens=_MAX_TOKENS[task], ) - text = resp.choices[0].message.content or "" + content = _strip_fence((resp.choices[0].message.content or "").strip()) impacts = ecolog.measure(resp) - return LocalizeResponse( - localizedSteps=_parse_steps(text), - model=model, - provider=provider, - mock=False, - **impacts, + return GenerateResponse( + content=content, model=model, provider=provider, mock=False, **impacts ) # --------------------------------------------------------------------------- -# Prompt construction +# Prompts # --------------------------------------------------------------------------- -_LANG_NAME = {"en": "English", "es": "Spanish", "pt": "Brazilian Portuguese"} +_GUARDRAILS = ( + "Use plain, global-standard language and minimal jargon. " + "Never invent specific counts, quantities, dates, deadlines, budgets, percentages, named " + "officials, ordinance numbers, or report titles — not even inside proposals, asks, or " + "targets. Describe scope qualitatively instead (e.g. 'the hottest bus stops', 'priority " + "neighborhoods', 'within one council term'). The ONLY numbers you may use are those in the " + "provided facts, quoted exactly. Only name civic channels that appear in the provided list; " + "if none fits, use a clearly bracketed placeholder. Keep local program/channel names in " + "their original language. Output plain GitHub-flavored Markdown — do NOT wrap the whole " + "answer in a code block or ``` fences." +) - -def _system(language: str) -> str: - lang = _LANG_NAME.get(language, "English") - return ( - f"You are a civic-engagement assistant for city residents. Reply ONLY in {lang}. " - "Turn a city climate action into a short plan of 4-6 concrete, executable next steps an " - "ordinary resident can take over the coming weeks. Each step: one imperative sentence, " - "specific and doable, no preamble. Where a step involves contacting government or joining " - "a group, name a real local channel from the context when one is provided. " - "Return ONLY a numbered list — no title, no closing remarks." - ) +_SYSTEMS = { + "next_steps": ( + "You are a civic-engagement assistant for city residents. Produce a short plan of 4-6 " + "concrete next steps an ordinary resident can take over the coming weeks to push this " + "action forward (join a group, attend a meeting, submit a public comment, start something " + "small). Each step: one imperative sentence; where a step involves government or a group, " + "name a real local channel from the context. Return ONLY a numbered Markdown list." + ), + "draft_proposal": ( + "You are helping a resident draft a first proposal letter to their town hall or council " + "requesting this action. Write a copy-pasteable letter, under ~350 words, in this exact " + "Markdown order:\n" + "# {short concrete title naming the action and city}\n" + "To: {the single best-fitting local channel/body} \nRe: {one-line subject}\n" + "## Why this matters here\n2-4 sentences of rationale that quote the provided facts (hazard " + "severity and/or top-sector share) closely. No new numbers.\n" + "## What we ask\n1-3 bullets, each a clear, checkable ask a council member could say " + "yes/no to — describe scope qualitatively (e.g. 'plant and maintain trees at the hottest " + "bus stops and squares'). Do NOT invent counts, dates, or budgets.\n" + "## Expected benefits\n3-5 qualitative bullets: the climate benefit + co-benefits (health, " + "cost, comfort, equity, jobs).\n" + "## A note on getting started\n1-3 sentences on a simple, low-cost first step (a pilot, a " + "map, a working group).\n" + "## How to submit this\nName the single most appropriate local channel and one line on why " + "it fits (a spending request → the participatory-budget channel; a policy/oversight request " + "→ the relevant municipal council; a hazard report → civil defense).\n" + "Close with a line and the placeholders [Your name], [Neighborhood], [Date]." + ), + "evidence": ( + "You are helping a resident back their climate concern with credible evidence. Output " + "Markdown in this order:\n" + "## Your city's facts\n2-4 bullets drawn ONLY from the provided facts, quoted closely.\n" + "## Widely-known context\n1-3 bullets of general, NON-numeric climate knowledge that frames " + "why the action matters.\n" + "## Sources to cite\n3-5 bullets naming source TYPES to pull real numbers from — the city's " + "own emissions inventory (via CityCatalyst), its climate-risk assessment, the national " + "statistics office, and 1-2 recognized bodies (IPCC, WRI, C40, World Bank) — each with a " + "one-line 'what you'll find here'. Do not fabricate report titles, URLs, or years.\n" + "## Talking points\n2-3 short sentences a resident can say in a meeting, each fusing one " + "city fact with one benefit, with no invented numbers.\n" + "Keep the city-fact vs general-knowledge distinction visible; never attach a number to a " + "general claim." + ), + "pathways": ( + "You are mapping implementation alternatives for this action, escalating from most " + "feasible/short-term to most ambitious/long-term. Output Markdown with three subsections, " + "in this fixed order and nothing else:\n" + "## Now (most feasible, weeks)\n## Next (a few months)\n## Long-term (most ambitious, a year+)\n" + "Under each, the SAME four labeled lines:\n" + "- **What it is:** 1-2 sentences for this ambition level.\n" + "- **Effort / cost:** a qualitative band (low / volunteer time; medium / small grant or " + "council line item; high / capital budget) — no invented amounts.\n" + "- **Who's involved:** the people/bodies needed, naming a real local channel where relevant.\n" + "- **First move:** one concrete thing the resident can do this week.\n" + "Make the three levels genuinely escalate (solo/pilot → funded neighborhood program → " + "citywide policy or investment). End with one short line noting they escalate." + ), + "future_vision": ( + "You are a futures designer using Experiential Futures (\"a day in the life\"). Write ONE " + "short, vivid, hopeful-but-plausible vision of this city in the NEAR future (about 3-7 " + "years) AFTER this action has taken hold. Output Markdown, ~150-220 words, in exactly three " + "parts and nothing else:\n" + "1. A short **bold title** (6-10 words) naming the changed place/feeling — no 'Vision:' label.\n" + "2. One present-tense paragraph (~110-160 words) from one ordinary resident's point of view " + "during a normal moment of their day (a bus stop, a school run, a market). Make it sensory " + "and human; show 2-3 of the city's real hazards/sectors visibly easing. Keep it partial and " + "local ('this block', 'your corner'), the result of residents and named local channels — " + "not a miracle. Introduce no hazards, places, or numbers not in the context.\n" + "3. One closing line, italicized, starting 'First ripple:' — a single concrete knock-on " + "effect that plausibly follows. One sentence.\n" + "No other headings, no bullet lists, no statistics." + ), + "refine": ( + "You are refining a resident's existing draft. Revise the PRIOR content according to the " + "INSTRUCTION, keeping the EXACT same Markdown structure, sections and field labels. Return " + "ONLY the revised content — no preamble, no 'here is your revised...' line. Preserve every " + "grounded fact, channel name and bracketed placeholder; do not introduce new statistics or " + "new channels. If the instruction needs facts that aren't provided, keep what's grounded and " + "add a bracketed note like '[verify before submitting]' rather than inventing support." + ), +} -def _prompt(req: LocalizeRequest) -> str: - c = req.cityContext - hazards = ", ".join(c.topHazards[:3]) or "n/a" - sectors = ", ".join(c.topSectors[:3]) or "n/a" - channels = ", ".join(c.localSources[:5]) or "n/a" - return ( - f"City: {c.name}, {c.country}\n" - f"Top climate hazards: {hazards}\n" - f"Top emitting sectors: {sectors}\n" - f"Local civic channels: {channels}\n" - f"Action ({req.action.type}): {req.action.name}\n" - f"Description: {req.action.description[:400]}\n\n" - "Write 4-6 concrete next steps a resident of this city can take to push this action " - "forward (join a group, attend a meeting, submit a public comment, start something small). " - "Ground them in the city's hazards/sectors, and when a step involves contacting government " - "or joining a group, name one of the local civic channels above explicitly." - ) +def _strip_fence(text: str) -> str: + """Remove a wrapping ```markdown / ``` code fence the model sometimes adds.""" + import re + t = text.strip() + m = re.match(r"^```[a-zA-Z]*\s*\n(.*)\n```$", t, re.DOTALL) + return m.group(1).strip() if m else t -def _parse_steps(text: str) -> list[str]: - import re - lines = [l.strip() for l in text.splitlines() if l.strip()] - steps = [re.sub(r"^\s*(?:\d+[\.\)]|[-*•])\s*", "", l) for l in lines] - steps = [s for s in steps if len(s) > 8] - return steps[:6] if steps else [text.strip()] +def _system(task: str, language: str) -> str: + lang = _LANG_NAME.get(language, "English") + return f"{_SYSTEMS[task]}\n\n{_GUARDRAILS} Reply ONLY in {lang}." -# --------------------------------------------------------------------------- -# Mock localization (no key) — mirrors the Next.js route fallback. -# --------------------------------------------------------------------------- -_FOCUS = { - "heat": ("las olas de calor", "as ondas de calor"), - "landslide": ("los deslizamientos", "os deslizamentos"), - "flood": ("las inundaciones", "as inundações"), - "drought": ("la sequía", "a seca"), - "disease": ("las enfermedades", "as doenças"), - "sea-level": ("el aumento del nivel del mar", "a elevação do nível do mar"), - "storm": ("las tormentas", "as tempestades"), - "wildfire": ("los incendios", "os incêndios"), - "transport": ("el transporte", "o transporte"), - "energy": ("la energía", "a energia"), - "waste": ("los residuos", "os resíduos"), - "stationary": ("la energía", "a energia"), -} +def _context_block(req: GenerateRequest) -> str: + c = req.cityContext + lines = [ + f"City: {c.name}, {c.country}", + f"Top climate hazards: {', '.join(c.topHazards[:4]) or 'n/a'}", + f"Top emitting sectors: {', '.join(c.topSectors[:4]) or 'n/a'}", + ] + if c.facts: + lines.append("Key facts about this city (use these exactly; invent no others):") + lines += [f"- {f}" for f in c.facts[:8]] + lines.append(f"Local civic channels: {', '.join(c.localSources[:6]) or 'n/a'}") + lines.append(f"Action ({req.action.type}): {req.action.name}") + if req.action.description: + lines.append(f"Action description: {req.action.description[:400]}") + return "\n".join(lines) -def _focus(raw: str, lang: str) -> str: - s = raw.lower() - if lang == "en": - return s - for key, (es, pt) in _FOCUS.items(): - if key in s: - return es if lang == "es" else pt - return s +def _user(req: GenerateRequest, task: str) -> str: + if task == "refine": + return ( + f"{_context_block(req)}\n\n" + f"PRIOR CONTENT:\n{req.prior[:4000]}\n\n" + f"INSTRUCTION: {req.instruction or 'Improve clarity and concreteness.'}\n\n" + "Return the revised content only." + ) + return f"{_context_block(req)}\n\nNow produce the requested output." -def mock_steps(req: LocalizeRequest) -> list[str]: +# --------------------------------------------------------------------------- +# Mock content (no key) — concise templated markdown per task. +# --------------------------------------------------------------------------- +def mock_content(req: GenerateRequest, task: str) -> str: c = req.cityContext - lang = req.language - raw = (c.topHazards[0] if req.action.type == "adaptation" else None) or ( - c.topSectors[0] if c.topSectors else "climate" + a = req.action.name + channel = c.localSources[0] if c.localSources else "your city council" + hazard = c.topHazards[0] if c.topHazards else "local climate risk" + if task == "future_vision": + return ( + f"**A cooler, calmer corner of {c.name}**\n\n" + f"A few years from now you walk your usual block in {c.name} and it simply feels " + f"better cared for — more shade, cleaner air, fewer worries when the rain comes hard. " + f"The change started small, pushed by neighbors through {channel}, and it shows: " + f"{a.lower()} has quietly reshaped the everyday. It isn't finished, but your corner " + f"feels looked after.\n\n" + f"*First ripple: the next block asks for the same, and the idea spreads.*" + ) + if task == "draft_proposal": + return ( + f"# Proposal: {a} in {c.name}\n\n" + f"To: {channel} \nRe: {a}\n\n" + f"## Why this matters here\n{hazard} is a top concern for our city, and this action " + f"helps address it directly.\n\n" + f"## What we ask\n- Pilot **{a.lower()}** in our neighborhood\n\n" + f"## Expected benefits\n- A safer, healthier, more comfortable neighborhood\n\n" + f"## A note on getting started\nBegin with a small, low-cost pilot on one block.\n\n" + f"## How to submit this\nSubmit through **{channel}**.\n\n" + f"Sincerely, [Your name], [Neighborhood], [Date]" + ) + if task == "evidence": + facts = "\n".join(f"- {f}" for f in (c.facts[:3] or [f"{hazard} affects our city."])) + return ( + f"## Your city's facts\n{facts}\n\n" + f"## Widely-known context\n- Local action on this issue improves health and comfort.\n\n" + f"## Sources to cite\n- Your city's emissions inventory (via CityCatalyst)\n" + f"- Your city's climate-risk assessment\n- IPCC / WRI / C40 city briefs\n\n" + f"## Talking points\n- Our own city data shows {hazard.lower()} matters here — this " + f"action is a practical response." + ) + if task == "pathways": + return ( + f"## Now (most feasible, weeks)\n- **What it is:** A resident-led first step on {a.lower()}.\n" + f"- **Effort / cost:** low / volunteer time\n- **Who's involved:** neighbors\n" + f"- **First move:** Gather a few neighbors this week.\n\n" + f"## Next (a few months)\n- **What it is:** A funded neighborhood version.\n" + f"- **Effort / cost:** medium\n- **Who's involved:** {channel}\n" + f"- **First move:** Propose it through {channel}.\n\n" + f"## Long-term (most ambitious, a year+)\n- **What it is:** A citywide policy or investment.\n" + f"- **Effort / cost:** high\n- **Who's involved:** the city council\n" + f"- **First move:** Ask your council to take it up.\n\n" + f"These escalate — start at Now and build toward Long-term." + ) + if task == "refine": + return req.prior or "_(nothing to refine yet)_" + # next_steps + return ( + f"1. Find a neighborhood group in {c.name} already working on this.\n" + f"2. Bring **{a}** to **{channel}** as a proposal or public comment.\n" + f"3. Back it with your city's own climate data.\n" + f"4. Invite three neighbors to join and share progress." ) - focus = _focus(raw, lang) - action = req.action.name - if lang == "es": - return [ - f"Identifica en {c.name} a un grupo vecinal o colectivo que ya trabaje en {focus}.", - f'Asiste a la próxima sesión del consejo municipal donde se discuta "{action}".', - "Presenta esta acción como propuesta o comentario público, citando el riesgo local.", - "Invita a tres vecinos a sumarse y comparte el avance en tu comunidad.", - ] - if lang == "pt": - return [ - f"Identifique em {c.name} um grupo de bairro ou coletivo que já atue em {focus}.", - f'Participe da próxima sessão do conselho municipal onde "{action}" for discutida.', - "Apresente esta ação como proposta ou comentário público, citando o risco local.", - "Convide três vizinhos para participar e compartilhe o progresso na sua comunidade.", - ] - return [ - f"Find a neighborhood group or collective in {c.name} already working on {focus}.", - f'Attend the next city-council session where "{action}" is on the agenda.', - "Submit this action as a proposal or public comment, citing the local risk.", - "Invite three neighbors to join and share progress in your community.", - ] diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py index dec28d5..3ac96db 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py @@ -1,4 +1,4 @@ -"""Request/response models for the localizer service.""" +"""Request/response models for the generation service.""" from pydantic import BaseModel, Field @@ -11,19 +11,24 @@ class ActionIn(BaseModel): class CityContext(BaseModel): name: str country: str = "" - topHazards: list[str] = Field(default_factory=list) - topSectors: list[str] = Field(default_factory=list) - localSources: list[str] = Field(default_factory=list) + topHazards: list[str] = Field(default_factory=list) # e.g. "Heatwaves (Very High)" + topSectors: list[str] = Field(default_factory=list) # e.g. "Transportation (81%)" + localSources: list[str] = Field(default_factory=list) # real civic channel names + facts: list[str] = Field(default_factory=list) # plain factual lines from city data -class LocalizeRequest(BaseModel): +# task: next_steps | draft_proposal | evidence | pathways | future_vision | refine +class GenerateRequest(BaseModel): + task: str = "next_steps" action: ActionIn cityContext: CityContext language: str = "en" # en | es | pt + prior: str = "" # prior content (for refine) + instruction: str = "" # refinement instruction (for refine) -class LocalizeResponse(BaseModel): - localizedSteps: list[str] +class GenerateResponse(BaseModel): + content: str # markdown energyWh: float gCO2e: float model: str From 8a76cae386ab84bc7683ace1fc7d965d4b3a1bab Mon Sep 17 00:00:00 2001 From: Carlos Octavio Graffi Date: Sun, 14 Jun 2026 22:53:47 -0300 Subject: [PATCH 6/8] Rework Futures lens into data-backed foresight; scope pilot to Brazil MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Futures Design lens (future_vision task) is no longer a sensory "day in the life" vignette. Grounded in the Future Design + Futures Cone methodologies, it now produces structured, data-backed foresight from the city's real numbers: - Where today's trends point (trajectory read from the city's risk/emissions) - A plausible future history to ~2050 (future-generations standpoint, with the necessary transitions and honest trade-offs) - Two futures side by side (probable vs preferable, + systemic ripple effects) - closing on the present trade-off future generations would thank us for Qualitative trends only; the sole numbers are the provided city facts. Scope the prototype to the Brazilian use-case cities: the explorer/map now shows only São Paulo, Porto Alegre, Curitiba, Rio (pilots first; São Paulo default). Other cities stay in `allCities` behind a one-line filter, easily re-enabled. Worldwide success stories are kept as inspiration/examples. Footer copy updated. Co-Authored-By: Claude Opus 4.8 --- .../app/src/app/api/generate/route.ts | 6 +-- .../app/src/app/components/AiWorkspace.tsx | 14 +++-- .../app/src/app/data/cities.ts | 10 +++- .../civic-climate-action/app/src/app/page.tsx | 9 ++-- .../civic-climate-action/llm-service/main.py | 53 +++++++++++-------- 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts index e85d295..5ce0b90 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts @@ -66,9 +66,9 @@ function fallbackContent(b: Body): string { if (b.task === "future_vision") { return T( - `**A cooler, calmer corner of ${c.name}**\n\nA few years from now, your block in ${c.name} simply feels better cared for — more shade, cleaner air, fewer worries when the rain comes hard. Neighbors pushed it through ${channel}, and "${a.toLowerCase()}" has quietly reshaped the everyday. It isn't finished, but your corner feels looked after.\n\n*First ripple: the next block asks for the same, and the idea spreads.*`, - `**Un rincón más fresco de ${c.name}**\n\nDentro de unos años, tu cuadra en ${c.name} se siente mejor cuidada — más sombra, aire más limpio, menos preocupación cuando llueve fuerte. Los vecinos lo impulsaron a través de ${channel}, y "${a.toLowerCase()}" cambió el día a día. No está terminado, pero tu rincón se siente atendido.\n\n*Primer efecto: la cuadra de al lado pide lo mismo y la idea se extiende.*`, - `**Um canto mais fresco de ${c.name}**\n\nDaqui a alguns anos, a sua rua em ${c.name} parece mais bem cuidada — mais sombra, ar mais limpo, menos preocupação quando chove forte. Os vizinhos levaram isso adiante pelo ${channel}, e "${a.toLowerCase()}" transformou o dia a dia. Não está pronto, mas o seu canto parece cuidado.\n\n*Primeiro efeito: a rua vizinha pede o mesmo e a ideia se espalha.*` + `## Where today's trends point\nOn its current path, ${c.name} faces growing climate pressure. Without sustained action, those pressures compound.\n\n## A plausible future history (to ~2050)\nLooking back from 2050, "${a.toLowerCase()}" started small — pushed by residents through ${channel} — then scaled as results showed and held.\n\n## Two futures, side by side\n- **If little changes (probable):** the same risks, unevenly felt.\n- **If this action takes hold (preferable):** a more resilient, livable city, with gains in health and cost of living.\n\n_What it asks of us now: a modest, shared effort today for a city future generations inherit._`, + `## Hacia dónde apuntan las tendencias\nEn su trayectoria actual, ${c.name} enfrenta una presión climática creciente. Sin acción sostenida, esas presiones se acumulan.\n\n## Una historia futura plausible (hacia ~2050)\nMirando atrás desde 2050, "${a.toLowerCase()}" empezó pequeño — impulsado por vecinos a través de ${channel} — y luego escaló al mostrar resultados.\n\n## Dos futuros, lado a lado\n- **Si poco cambia (probable):** los mismos riesgos, de forma desigual.\n- **Si esta acción se afianza (preferible):** una ciudad más resiliente y habitable, con mejoras en salud y costo de vida.\n\n_Lo que nos pide ahora: un esfuerzo compartido hoy por una ciudad que heredarán las próximas generaciones._`, + `## Para onde apontam as tendências\nNo caminho atual, ${c.name} enfrenta pressão climática crescente. Sem ação sustentada, essas pressões se acumulam.\n\n## Uma história futura plausível (até ~2050)\nOlhando de 2050 para trás, "${a.toLowerCase()}" começou pequeno — levado por moradores pelo ${channel} — e depois escalou ao mostrar resultados.\n\n## Dois futuros, lado a lado\n- **Se pouco muda (provável):** os mesmos riscos, de forma desigual.\n- **Se esta ação se firma (preferível):** uma cidade mais resiliente e habitável, com ganhos em saúde e custo de vida.\n\n_O que isso nos pede agora: um esforço compartilhado hoje por uma cidade que as próximas gerações herdarão._` ); } if (b.task === "draft_proposal") { diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx index 1ee301d..e7d9243 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx @@ -79,11 +79,11 @@ const LENSES: { { key: "future_vision", llm: true, - label: { en: "Future vision", es: "Visión de futuro", pt: "Visão de futuro" }, + label: { en: "Futures", es: "Futuros", pt: "Futuros" }, desc: { - en: "Picture your city once this takes hold.", - es: "Imagina tu ciudad cuando esto se afiance.", - pt: "Imagine sua cidade quando isto se firmar.", + en: "Data-backed plausible futures if this scales — trends, not guesses.", + es: "Futuros plausibles con base en datos — tendencias, no conjeturas.", + pt: "Futuros plausíveis com base em dados — tendências, não palpites.", }, }, ]; @@ -102,7 +102,11 @@ const t = { refine: { en: "Refine", es: "Refinar", pt: "Refinar" }, where: { en: "Where to engage locally", es: "Dónde participar localmente", pt: "Onde participar localmente" }, estimated: { en: "est.", es: "est.", pt: "est." }, - futureLabel: { en: "An imagined near future", es: "Un futuro cercano imaginado", pt: "Um futuro próximo imaginado" }, + futureLabel: { + en: "Plausible futures · grounded in this city's data (Futures Design)", + es: "Futuros plausibles · con base en los datos de la ciudad (Futures Design)", + pt: "Futuros plausíveis · com base nos dados da cidade (Futures Design)", + }, noExamples: { en: "No close examples yet — browse the Inspiration gallery below.", es: "Aún sin ejemplos cercanos — mira la galería de Inspiración abajo.", pt: "Ainda sem exemplos próximos — veja a galeria de Inspiração abaixo." }, }; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts index 5659895..f592cbd 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/cities.ts @@ -1,4 +1,5 @@ import type { City } from "./types"; +import { PILOT_CITY_IDS } from "../lib/pilots"; // Shared note for the Brazilian inventories: the CityCatalyst territorial // totals don't yet capture every sector (notably grid electricity / scope 2), @@ -11,7 +12,7 @@ const BR_PARTIAL_NOTE = // UN/LOCODE — the same key CityCatalyst uses — so a city can later be wired // to live GHGI / CCRA / HIAP data from the CityCatalyst Global API. -export const cities: City[] = [ +const allCities: City[] = [ { id: "medellin", name: "Medellín", @@ -559,3 +560,10 @@ export const cities: City[] = [ }, }, ]; + +// The prototype is scoped to our Brazilian use-case cities (live CityCatalyst +// data). The other cities above remain in `allCities` and can be re-enabled by +// widening this filter. Pilots (full AI workspace) are surfaced first. +export const cities: City[] = allCities + .filter((c) => c.country === "Brazil") + .sort((a, b) => Number(PILOT_CITY_IDS.has(b.id)) - Number(PILOT_CITY_IDS.has(a.id))); diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx index 4181eb3..a187087 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx @@ -84,10 +84,11 @@ export default function Home() {

- Built for OEF Hackday 26Q2. Brazilian cities pull live emissions-inventory and - climate-risk data from CityCatalyst; other cities use the latest verified inventories - and risk assessments from official sources. Every figure and success story links to its - source — look for the “CityCatalyst live” vs “External source” badge. + Built for OEF Hackday 26Q2. This pilot is scoped to Brazilian cities, which pull live + emissions-inventory and climate-risk data from CityCatalyst. The AI workspace runs a + small open-weight model on a low-carbon grid; its carbon figure is an estimate. + Inspiration stories from around the world are independently sourced — every figure and + story links to its source.

diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py index 9845e27..fbe9e47 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py @@ -35,7 +35,7 @@ "draft_proposal": 800, "evidence": 700, "pathways": 800, - "future_vision": 380, + "future_vision": 650, "refine": 800, } @@ -157,19 +157,26 @@ def generate(req: GenerateRequest): "citywide policy or investment). End with one short line noting they escalate." ), "future_vision": ( - "You are a futures designer using Experiential Futures (\"a day in the life\"). Write ONE " - "short, vivid, hopeful-but-plausible vision of this city in the NEAR future (about 3-7 " - "years) AFTER this action has taken hold. Output Markdown, ~150-220 words, in exactly three " - "parts and nothing else:\n" - "1. A short **bold title** (6-10 words) naming the changed place/feeling — no 'Vision:' label.\n" - "2. One present-tense paragraph (~110-160 words) from one ordinary resident's point of view " - "during a normal moment of their day (a bus stop, a school run, a market). Make it sensory " - "and human; show 2-3 of the city's real hazards/sectors visibly easing. Keep it partial and " - "local ('this block', 'your corner'), the result of residents and named local channels — " - "not a miracle. Introduce no hazards, places, or numbers not in the context.\n" - "3. One closing line, italicized, starting 'First ripple:' — a single concrete knock-on " - "effect that plausibly follows. One sentence.\n" - "No other headings, no bullet lists, no statistics." + "You are a foresight practitioner using Futures Design and Future Design methodology. " + "Produce a SHORT, DATA-BACKED exploration of plausible futures for this city if the action " + "is taken up and scaled — grounded in the city's real data, reasoning from trends, the " + "Futures Cone (probable vs preferable futures), and Future Design's future-generations " + "standpoint. This is structured foresight, NOT a sensory 'day in the life' anecdote. Output " + "Markdown in exactly these sections:\n" + "## Where today's trends point\n2-3 sentences reading the city's current trajectory from its " + "real risk and emissions data (use the provided facts by name) — the qualitative direction " + "things head if nothing changes. No invented numbers.\n" + "## A plausible future history (to ~2050)\nFrom the standpoint of a resident in ~2050 looking " + "back: the realistic pathway and the necessary transitions if this action is adopted and " + "scaled — what changed, roughly in what order, and why it held. Plausible and partial, not " + "utopian; acknowledge the effort and trade-offs involved.\n" + "## Two futures, side by side\n" + "- **If little changes (probable):** where the current trend lands without sustained action.\n" + "- **If this action takes hold (preferable):** the better-but-plausible outcome, plus one or " + "two systemic ripple effects it unlocks (health, mobility, equity, cost of living).\n" + "Close with one italicized line starting '_What it asks of us now:_' — the present trade-off " + "that future generations would thank us for. Keep the whole thing tight (~200-280 words). " + "Qualitative trends only; the only numbers allowed are the provided facts." ), "refine": ( "You are refining a resident's existing draft. Revise the PRIOR content according to the " @@ -234,13 +241,17 @@ def mock_content(req: GenerateRequest, task: str) -> str: hazard = c.topHazards[0] if c.topHazards else "local climate risk" if task == "future_vision": return ( - f"**A cooler, calmer corner of {c.name}**\n\n" - f"A few years from now you walk your usual block in {c.name} and it simply feels " - f"better cared for — more shade, cleaner air, fewer worries when the rain comes hard. " - f"The change started small, pushed by neighbors through {channel}, and it shows: " - f"{a.lower()} has quietly reshaped the everyday. It isn't finished, but your corner " - f"feels looked after.\n\n" - f"*First ripple: the next block asks for the same, and the idea spreads.*" + f"## Where today's trends point\n" + f"On its current path, {c.name} faces growing pressure from {hazard.lower()} and its " + f"main emitting sectors. Without sustained action, those pressures compound.\n\n" + f"## A plausible future history (to ~2050)\n" + f"Looking back from 2050, {a.lower()} started small — championed by residents through " + f"{channel} — then scaled neighborhood by neighborhood as results showed and held.\n\n" + f"## Two futures, side by side\n" + f"- **If little changes (probable):** the same risks, unevenly felt.\n" + f"- **If this action takes hold (preferable):** a measurably more resilient, livable city, " + f"with knock-on gains in health and cost of living.\n\n" + f"_What it asks of us now: a modest, shared effort today for a city future generations inherit._" ) if task == "draft_proposal": return ( From 7a3adeb4a2b2ca4587be8107c2f6bbf319fdaca6 Mon Sep 17 00:00:00 2001 From: Carlos Octavio Graffi Date: Sun, 14 Jun 2026 23:22:04 -0300 Subject: [PATCH 7/8] =?UTF-8?q?Make=20the=20money=20thesis=20real:=20captu?= =?UTF-8?q?red=20participation=20=E2=86=92=20funder=20engagement=20metric?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hackday's "unlock the money / trust layer" test was answered only in copy. This builds the surface end-to-end: - Capture participation: a server-side pledge store (file-backed, seeded demo baseline, rate-guarded) + /api/pledge + /api/metrics; a "I'll act on this" button in the workspace, aggregated across visitors via a PledgeProvider. - Civic Engagement Readiness: a transparent per-city index (engagementScore.ts) — resident commitments + the actions' stakeholder-engagement co-benefit (the HIAP signal funders score, finally surfaced) + local civic channels + proven precedent — shown as a "For funders" card with a no-black-box breakdown and a live tally that ticks up as residents pledge. - Funder export: a static, fabrication-free Markdown one-pager (funderBrief.ts), downloadable. - Footer "Why it pays" repointed to the metric. Bundled trust fixes (so the numbers we show funders hold up): - Stop feeding the overstated transport % to the LLM — cityFacts presents the dominant sector qualitatively with the partial-inventory caveat when set, and the caveat is threaded into the model context (cityContext.dataCaveat). - "AI draft — verify before submitting" disclaimer under generated content. Everything stays honest: index labeled a prototype over demo data; brief is static (no LLM); pledge store is a demo single-process file (DB for production). Co-Authored-By: Claude Opus 4.8 --- .gitignore | 2 + .../app/src/app/api/generate/route.ts | 1 + .../app/src/app/api/metrics/route.ts | 10 ++ .../app/src/app/api/pledge/route.ts | 37 ++++++ .../app/src/app/components/AiWorkspace.tsx | 15 ++- .../app/src/app/components/CityActions.tsx | 14 ++- .../app/src/app/components/CityExplorer.tsx | 3 + .../app/components/EngagementReadiness.tsx | 117 ++++++++++++++++++ .../app/src/app/components/PledgeButton.tsx | 47 +++++++ .../app/src/app/layout.tsx | 7 +- .../app/src/app/lib/cityFacts.ts | 17 ++- .../app/src/app/lib/engagementScore.ts | 102 +++++++++++++++ .../app/src/app/lib/funderBrief.ts | 76 ++++++++++++ .../app/src/app/lib/pledgeContext.tsx | 50 ++++++++ .../app/src/app/lib/pledgeStore.ts | 57 +++++++++ .../app/src/app/lib/useGenerate.ts | 1 + .../civic-climate-action/app/src/app/page.tsx | 8 +- .../civic-climate-action/llm-service/main.py | 2 + .../llm-service/schemas.py | 1 + 19 files changed, 552 insertions(+), 15 deletions(-) create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts diff --git a/.gitignore b/.gitignore index 56870e7..8dea6d3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ dist/ *.log *.tsbuildinfo + +.data/ diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts index 5ce0b90..7817f1f 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts @@ -19,6 +19,7 @@ type Body = { topSectors: string[]; localSources: string[]; facts: string[]; + dataCaveat?: string; }; language: Lang; prior?: string; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts new file mode 100644 index 0000000..433fdeb --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts @@ -0,0 +1,10 @@ +// Per-city pledge counts for the live engagement tally + readiness score. + +import { NextResponse } from "next/server"; +import { getCounts } from "../../lib/pledgeStore"; + +export const runtime = "nodejs"; + +export async function GET() { + return NextResponse.json({ counts: getCounts() }); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts new file mode 100644 index 0000000..d761560 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts @@ -0,0 +1,37 @@ +// Capture a resident's "I'll act on this" pledge. Aggregated server-side so the +// engagement metric reflects real commitment across visitors. + +import { NextResponse } from "next/server"; +import { increment, getCount } from "../../lib/pledgeStore"; + +export const runtime = "nodejs"; + +// Light per-process rate guard so the live tally can't be trivially inflated on +// stage (a real deployment would rate-limit per IP / require a token). +const WINDOW_MS = 60_000; +const MAX_PER_WINDOW = 60; +let hits: number[] = []; + +function rateLimited(): boolean { + const now = Date.now(); + hits = hits.filter((t) => now - t < WINDOW_MS); + if (hits.length >= MAX_PER_WINDOW) return true; + hits.push(now); + return false; +} + +export async function POST(req: Request) { + let body: { cityId?: string }; + try { + body = await req.json(); + } catch { + return NextResponse.json({ error: "invalid body" }, { status: 400 }); + } + const cityId = typeof body.cityId === "string" ? body.cityId.slice(0, 64) : ""; + if (!cityId) return NextResponse.json({ error: "cityId required" }, { status: 400 }); + + if (rateLimited()) { + return NextResponse.json({ cityId, count: getCount(cityId), throttled: true }); + } + return NextResponse.json({ cityId, count: increment(cityId) }); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx index e7d9243..3d585d1 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx @@ -9,6 +9,7 @@ import { stories } from "../data/stories"; import { matchStories } from "../lib/matchStories"; import { categoryMeta } from "../data/types"; import Markdown from "./Markdown"; +import PledgeButton from "./PledgeButton"; type LensKey = GenTask | "examples"; @@ -102,6 +103,11 @@ const t = { refine: { en: "Refine", es: "Refinar", pt: "Refinar" }, where: { en: "Where to engage locally", es: "Dónde participar localmente", pt: "Onde participar localmente" }, estimated: { en: "est.", es: "est.", pt: "est." }, + disclaimer: { + en: "AI-generated draft — check the facts and local details before submitting.", + es: "Borrador generado por IA — verifica los datos y detalles locales antes de enviarlo.", + pt: "Rascunho gerado por IA — confira os fatos e detalhes locais antes de enviar.", + }, futureLabel: { en: "Plausible futures · grounded in this city's data (Futures Design)", es: "Futuros plausibles · con base en los datos de la ciudad (Futures Design)", @@ -114,12 +120,14 @@ const typeColor = { adaptation: "var(--accent)", mitigation: "#d97706" } as cons export default function AiWorkspace({ ranked, + cityId, cityName, cityContext, localSources, lang, }: { ranked: RankedAction; + cityId: string; cityName: string; cityContext: CityContext; localSources: LocalSource[]; @@ -216,7 +224,8 @@ export default function AiWorkspace({ {action.actionType} -

{action.name[lang]}

+

{action.name[lang]}

+
{/* Lens tabs */} @@ -266,6 +275,10 @@ export default function AiWorkspace({ )} {result.content} +

+ {t.disclaimer[lang]} +

+ {/* Refine bar */}
r.action.actionId === selectedActionId) ?? ranked[0]; + // When the inventory is partial, sector shares are overstated — present them + // qualitatively (no precise %) so the model never cites an unreliable number. + const partial = Boolean(city.emissions?.note); const cityContext = { country: city.country, - topHazards: (city.risk?.topHazards ?? []).map( - (h) => `${h.hazard} (${h.level})` - ), + topHazards: (city.risk?.topHazards ?? []).map((h) => `${h.hazard} (${h.level})`), topSectors: - city.emissions?.sectors?.map((s) => `${s.sector} (${Math.round(s.sharePct)}%)`) ?? - (city.emissions?.topSector ? [city.emissions.topSector] : []), + city.emissions?.sectors?.map((s) => + partial ? s.sector : `${s.sector} (${Math.round(s.sharePct)}%)` + ) ?? (city.emissions?.topSector ? [city.emissions.topSector] : []), localSources: localSourceNamesByCity[city.id] ?? [], facts: cityFacts(city, lang), + dataCaveat: city.emissions?.note ?? "", }; const localSources = localSourcesByCity[city.id] ?? []; @@ -103,6 +106,7 @@ export default function CityActions({ city }: { city: City }) { + + {isPilot(selected.id) && } {selectedStories.length > 0 && ( diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx new file mode 100644 index 0000000..466c8f1 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx @@ -0,0 +1,117 @@ +"use client"; + +import { useMemo } from "react"; +import type { City } from "../data/types"; +import { usePledges } from "../lib/pledgeContext"; +import { engagementReadiness, type ReadinessBand } from "../lib/engagementScore"; +import { funderBrief } from "../lib/funderBrief"; + +const bandColor: Record = { + Strong: "#15803d", + Developing: "#d97706", + Emerging: "#6b7280", +}; + +export default function EngagementReadiness({ city }: { city: City }) { + const { count, loaded } = usePledges(); + const pledges = count(city.id); + const readiness = useMemo(() => engagementReadiness(city, pledges), [city, pledges]); + + function download() { + const md = funderBrief(city, readiness); + const blob = new Blob([md], { type: "text/markdown;charset=utf-8" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `engagement-readiness-${city.id}.md`; + document.body.appendChild(a); + a.click(); + a.remove(); + URL.revokeObjectURL(url); + } + + return ( +
+
+
+
For funders · Civic engagement readiness
+

+ The civic-participation co-benefit funders already score (MDBs · IDB · philanthropy), + made visible — so “is this city engaged?” becomes something you can see and export. +

+
+
+
+ {readiness.score} + / 100 +
+
+ {readiness.band} +
+
prototype index
+
+
+ +
+ {pledges.toLocaleString()} resident commitments captured here + {!loaded && · loading…} +
+ +
How the score is built
+
+ {readiness.inputs.map((i) => ( +
+
+ + {i.label.en} · {i.value} + + + {i.contribution}/{i.weight} + +
+
+
+
+
+ ))} +
+ +
+ + + Prototype index over demo participation data — not an audited metric. + +
+
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx new file mode 100644 index 0000000..26bec70 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { useState } from "react"; +import type { Lang } from "../data/climateActions"; +import { usePledges } from "../lib/pledgeContext"; + +const t = { + cta: { en: "I'll act on this", es: "Me comprometo", pt: "Vou agir nisto" }, + done: { en: "Counted — thank you", es: "Registrado — gracias", pt: "Registrado — obrigado" }, + tally: { en: "resident commitments here", es: "compromisos de residentes aquí", pt: "compromissos de moradores aqui" }, +}; + +export default function PledgeButton({ cityId, lang }: { cityId: string; lang: Lang }) { + const { pledge, count } = usePledges(); + const [pledged, setPledged] = useState(false); + + function onClick() { + if (pledged) return; + setPledged(true); + pledge(cityId); + } + + return ( +
+ + + {count(cityId).toLocaleString()} {t.tally[lang]} + +
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx index bc04510..bf361ad 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import "./globals.css"; import { CarbonProvider } from "./lib/carbonContext"; +import { PledgeProvider } from "./lib/pledgeContext"; import CarbonCounter from "./components/CarbonCounter"; export const metadata: Metadata = { @@ -14,8 +15,10 @@ export default function RootLayout({ children }: { children: React.ReactNode }) - {children} - + + {children} + + diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts index 42aadc3..5de28ad 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts @@ -61,16 +61,25 @@ export function cityFacts(city: City, lang: Lang): string[] { else facts.push(`${hz} are rated ${lv} climate risk in ${city.name}.`); } - // Dominant emitting sector by share. + // Dominant emitting sector. When the inventory is partial (emissions.note set), + // the share is known to be overstated, so we DON'T present it as a precise fact — + // we frame it qualitatively and attach the caveat, so the LLM can't cite a bare %. const e = city.emissions; if (e?.sectors?.length) { const top = [...e.sectors].sort((a, b) => b.sharePct - a.sharePct)[0]; const key = normalizeSector(top.sector); const word = key ? SECTOR_WORD[key][lang] : top.sector; const pct = Math.round(top.sharePct); - if (lang === "es") facts.push(`${word} es cerca del ${pct}% de las emisiones medidas de ${city.name}.`); - else if (lang === "pt") facts.push(`${word} é cerca de ${pct}% das emissões medidas de ${city.name}.`); - else facts.push(`${word} is about ${pct}% of ${city.name}'s measured emissions.`); + if (e.note) { + // Partial inventory → qualitative only, no precise share. + if (lang === "es") facts.push(`${word} es la mayor fuente de emisiones medidas de ${city.name} (inventario parcial; la proporción está probablemente sobrestimada).`); + else if (lang === "pt") facts.push(`${word} é a maior fonte de emissões medidas de ${city.name} (inventário parcial; a proporção está provavelmente superestimada).`); + else facts.push(`${word} is the largest measured emissions source in ${city.name} (partial inventory; this share is likely overstated).`); + } else { + if (lang === "es") facts.push(`${word} es cerca del ${pct}% de las emisiones medidas de ${city.name}.`); + else if (lang === "pt") facts.push(`${word} é cerca de ${pct}% das emissões medidas de ${city.name}.`); + else facts.push(`${word} is about ${pct}% of ${city.name}'s measured emissions.`); + } } else if (e?.topSector) { const key = normalizeSector(e.topSector); const word = key ? SECTOR_WORD[key][lang] : e.topSector; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts new file mode 100644 index 0000000..94ad04e --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts @@ -0,0 +1,102 @@ +// Civic Engagement Readiness — a transparent, per-city prototype index that turns +// a funder's hardest question ("is this city engaged?") into a visible, sourced +// number. NO black box: every input and its point contribution is exposed. +// +// Inputs (all already in the repo): +// - Resident commitments (pledges, captured via /api/pledge) +// - Engagement co-benefit of the city's top actions (HIAP stakeholder_engagement, +// the signal funders already score, −2..+2) +// - Local civic infrastructure (curated official/community channels) +// - Proven precedent (matched real success stories) + +import type { City } from "../data/types"; +import type { Lang as L } from "../data/climateActions"; +import { climateActions } from "../data/climateActions"; +import { prioritizeActions } from "./prioritize"; +import { localSourcesByCity } from "../data/localSources"; +import { matchStories } from "./matchStories"; +import { stories } from "../data/stories"; + +export type ReadinessBand = "Emerging" | "Developing" | "Strong"; + +export type ReadinessInput = { + label: Record; + value: string; + contribution: number; // points out of `weight` + weight: number; +}; + +export type Readiness = { + score: number; // 0-100 + band: ReadinessBand; + inputs: ReadinessInput[]; + pledgeCount: number; + coBenefitAvg: number; // −2..+2 +}; + +const WEIGHTS = { pledges: 40, coBenefit: 25, infra: 20, precedent: 15 }; + +const clamp01 = (n: number) => Math.max(0, Math.min(1, n)); +const mean = (xs: number[]) => (xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0); + +export function engagementReadiness(city: City, pledgeCount: number): Readiness { + const ranked = prioritizeActions(city, climateActions, { topN: 6 }); + + // 1. Participation — log-scaled (≈200 pledges saturates). + const pledgeScore = clamp01(Math.log10(pledgeCount + 1) / Math.log10(201)); + + // 2. Engagement co-benefit of the prioritized actions (−2..+2 → 0..1). + const seVals = ranked.map((r) => r.action.coBenefits?.stakeholder_engagement ?? 0); + const coBenefitAvg = mean(seVals); + const coBenefitScore = clamp01((coBenefitAvg + 2) / 4); + + // 3. Local civic infrastructure (official weighted higher). + const srcs = localSourcesByCity[city.id] ?? []; + const official = srcs.filter((s) => s.type === "official").length; + const community = srcs.length - official; + const infraScore = clamp01((official + community * 0.5) / 6); + + // 4. Proven precedent — distinct success stories matched across the top actions. + const matched = new Set(); + for (const r of ranked.slice(0, 3)) { + for (const s of matchStories(r.action, stories)) matched.add(s.id); + } + const precedent = matched.size; + const precedentScore = clamp01(precedent / 4); + + const inputs: ReadinessInput[] = [ + { + label: { en: "Resident commitments", es: "Compromisos de residentes", pt: "Compromissos de moradores" }, + value: `${pledgeCount}`, + contribution: Math.round(WEIGHTS.pledges * pledgeScore), + weight: WEIGHTS.pledges, + }, + { + label: { + en: "Engagement co-benefit of top actions", + es: "Co-beneficio de participación de las acciones", + pt: "Co-benefício de participação das ações", + }, + value: `${coBenefitAvg >= 0 ? "+" : ""}${coBenefitAvg.toFixed(1)} / +2`, + contribution: Math.round(WEIGHTS.coBenefit * coBenefitScore), + weight: WEIGHTS.coBenefit, + }, + { + label: { en: "Local civic channels", es: "Canales cívicos locales", pt: "Canais cívicos locais" }, + value: `${official} official · ${community} community`, + contribution: Math.round(WEIGHTS.infra * infraScore), + weight: WEIGHTS.infra, + }, + { + label: { en: "Proven precedent", es: "Precedentes probados", pt: "Precedentes comprovados" }, + value: `${precedent} ${precedent === 1 ? "story" : "stories"}`, + contribution: Math.round(WEIGHTS.precedent * precedentScore), + weight: WEIGHTS.precedent, + }, + ]; + + const score = inputs.reduce((a, i) => a + i.contribution, 0); + const band: ReadinessBand = score >= 66 ? "Strong" : score >= 40 ? "Developing" : "Emerging"; + + return { score, band, inputs, pledgeCount, coBenefitAvg }; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts new file mode 100644 index 0000000..33928d7 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts @@ -0,0 +1,76 @@ +// Assemble a one-page "Civic Engagement Readiness" brief for funders, purely +// from real app data + the transparent readiness score. STATIC (no LLM) so this +// headline funder artifact carries zero fabrication risk. English (the working +// language for MDB / IDB / philanthropy partners). + +import type { City } from "../data/types"; +import { climateActions } from "../data/climateActions"; +import { prioritizeActions } from "./prioritize"; +import { localSourcesByCity } from "../data/localSources"; +import { matchStories } from "./matchStories"; +import { stories } from "../data/stories"; +import type { Readiness } from "./engagementScore"; + +export function funderBrief(city: City, readiness: Readiness): string { + const ranked = prioritizeActions(city, climateActions, { topN: 6 }); + const topActions = ranked.slice(0, 3); + + const matched = new Map(); + for (const r of topActions) for (const s of matchStories(r.action, stories)) matched.set(s.id, s); + + const srcs = localSourcesByCity[city.id] ?? []; + + const rows = readiness.inputs + .map((i) => `| ${i.label.en} | ${i.value} | ${i.contribution} / ${i.weight} |`) + .join("\n"); + + const actionLines = topActions + .map((r) => { + const se = r.action.coBenefits?.stakeholder_engagement ?? 0; + return `- **${r.action.name.en}** — engagement co-benefit ${se >= 0 ? "+" : ""}${se} / +2`; + }) + .join("\n"); + + const channelLines = srcs.length + ? srcs.map((s) => `- ${s.name} (${s.type}) — ${s.url}`).join("\n") + : "- (none curated yet)"; + + const storyLines = matched.size + ? [...matched.values()].map((s) => `- ${s.title} — ${s.city}, ${s.country} (${s.sourceName})`).join("\n") + : "- (no close precedent matched)"; + + return `# Civic Engagement Readiness — ${city.name}, ${city.country} + +**Readiness: ${readiness.score} / 100 (${readiness.band})** · prototype index + +> A transparent proxy for how ready ${city.name} is for citizen-backed climate action — the +> civic-participation co-benefit that MDBs, the IDB and philanthropy already score (HIAP rates +> stakeholder engagement on a −2..+2 scale). This operationalizes "is this city engaged?" into +> something visible and exportable that de-risks city climate projects and helps capital flow. + +## How the score is built (no black box) + +| Signal | Value | Points | +|---|---|---| +${rows} + +## Top recommended actions (with engagement co-benefit) + +${actionLines} + +## Local civic channels residents can use + +${channelLines} + +## Proven precedent (real success stories) + +${storyLines} + +## Caveats + +- Prototype index over **demo participation data** — not an audited metric. +- Brazilian emissions come from a partial territorial inventory; sector shares are conservative and + some are overstated. Climate-risk levels are from CityCatalyst's risk assessment. +- Generated for OEF Hackday 26Q2 by the Civic Climate Action module. +`; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx new file mode 100644 index 0000000..851b5ab --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx @@ -0,0 +1,50 @@ +"use client"; + +import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react"; + +type Ctx = { + count: (cityId: string) => number; + pledge: (cityId: string) => Promise; + loaded: boolean; +}; + +const PledgeCtx = createContext(null); + +export function PledgeProvider({ children }: { children: React.ReactNode }) { + const [counts, setCounts] = useState>({}); + const [loaded, setLoaded] = useState(false); + + useEffect(() => { + fetch("/api/metrics") + .then((r) => r.json()) + .then((d) => setCounts(d.counts ?? {})) + .catch(() => {}) + .finally(() => setLoaded(true)); + }, []); + + const pledge = useCallback(async (cityId: string) => { + setCounts((c) => ({ ...c, [cityId]: (c[cityId] ?? 0) + 1 })); // optimistic + try { + const res = await fetch("/api/pledge", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ cityId }), + }); + const d = await res.json(); + if (typeof d.count === "number") setCounts((c) => ({ ...c, [cityId]: d.count })); + } catch { + /* keep optimistic value */ + } + }, []); + + const count = useCallback((cityId: string) => counts[cityId] ?? 0, [counts]); + + const value = useMemo(() => ({ count, pledge, loaded }), [count, pledge, loaded]); + return {children}; +} + +export function usePledges(): Ctx { + const ctx = useContext(PledgeCtx); + if (!ctx) throw new Error("usePledges must be used within "); + return ctx; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts new file mode 100644 index 0000000..4a5654f --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts @@ -0,0 +1,57 @@ +// Server-only participation store. Captures resident "I'll act on this" pledges +// per city so the funder-facing engagement metric reflects real, aggregated +// commitment (not per-browser localStorage). +// +// This is a DEMO store: a JSON file under the app root, single-process, seeded +// with a small clearly-labelled baseline. Production path = a real database. + +import fs from "node:fs"; +import path from "node:path"; + +const FILE = path.join(process.cwd(), ".data", "pledges.json"); + +// Clearly-labelled demo baseline so the metric isn't empty on first run. +const SEED: Record = { + "sao-paulo": 128, + "porto-alegre": 86, + "curitiba": 41, + "rio-de-janeiro": 73, +}; + +type Store = { counts: Record }; +let cache: Store | null = null; + +function load(): Store { + if (cache) return cache; + try { + cache = JSON.parse(fs.readFileSync(FILE, "utf8")) as Store; + } catch { + cache = { counts: { ...SEED } }; + persist(); + } + return cache; +} + +function persist(): void { + try { + fs.mkdirSync(path.dirname(FILE), { recursive: true }); + fs.writeFileSync(FILE, JSON.stringify(cache), "utf8"); + } catch { + /* read-only fs (e.g. serverless) — counts stay in-memory for the session */ + } +} + +export function getCounts(): Record { + return { ...load().counts }; +} + +export function getCount(cityId: string): number { + return load().counts[cityId] ?? 0; +} + +export function increment(cityId: string): number { + const s = load(); + s.counts[cityId] = (s.counts[cityId] ?? 0) + 1; + persist(); + return s.counts[cityId]; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts index 7184cf0..66cec0f 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts @@ -22,6 +22,7 @@ export type GenerateRequest = { topSectors: string[]; localSources: string[]; facts: string[]; + dataCaveat?: string; }; language: Lang; prior?: string; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx index a187087..40d657b 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx @@ -78,9 +78,11 @@ export default function Home() {
Why it pays

Civic participation is a co-benefit funders (MDBs, the IDB, philanthropy) already - score. This module operationalizes it — turning “is this city engaged?” - into something visible and measurable that de-risks city climate projects and helps - capital flow. + score. This module operationalizes it: each city carries a transparent{" "} + Civic Engagement Readiness score — + built from resident commitments, the actions’ engagement co-benefit, local civic + channels, and proven precedent — that you can read at a glance and export as a funder + brief. “Is this city engaged?” becomes visible, sourced, and exportable.

diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py index fbe9e47..101a527 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/main.py @@ -213,6 +213,8 @@ def _context_block(req: GenerateRequest) -> str: if c.facts: lines.append("Key facts about this city (use these exactly; invent no others):") lines += [f"- {f}" for f in c.facts[:8]] + if c.dataCaveat: + lines.append(f"Data caveat (do NOT cite sector shares as precise): {c.dataCaveat}") lines.append(f"Local civic channels: {', '.join(c.localSources[:6]) or 'n/a'}") lines.append(f"Action ({req.action.type}): {req.action.name}") if req.action.description: diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py index 3ac96db..b42014f 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/llm-service/schemas.py @@ -15,6 +15,7 @@ class CityContext(BaseModel): topSectors: list[str] = Field(default_factory=list) # e.g. "Transportation (81%)" localSources: list[str] = Field(default_factory=list) # real civic channel names facts: list[str] = Field(default_factory=list) # plain factual lines from city data + dataCaveat: str = "" # e.g. "partial inventory — share overstated" # task: next_steps | draft_proposal | evidence | pathways | future_vision | refine From 43ea36ca19461b0adfb4efff162b572351256001 Mon Sep 17 00:00:00 2001 From: Carlos Octavio Graffi Date: Mon, 15 Jun 2026 13:04:15 -0300 Subject: [PATCH 8/8] Rework into a Porto Alegre "one real move" civic engagement tool Refocus the app from a sprawling multi-city explorer into a single, honest spine for one pilot city (Porto Alegre), and build out the funder story. Resident flow: - Two-tap intake (worry -> appetite) -> one concrete, real move with the actual local channel, a "Why this helps" explainer, and "what happens next" - AI toolkit tabbed two ways: a clean ready-to-send message, and a "Guide me" civic-coach chat (what/how/why), both grounded in real channels + orgs - "I care about this" signature (name + neighborhood, optional email) -> personalizes the message, tracks Committed -> Sent -> Got a response, and issues a saveable receipt - Real partner organizations as next steps (volunteer / attend / campaign / donate), web-verified for Porto Alegre Engagement signal + funder view: - Public commitment wall, most-backed-actions ranking, and a Leaflet map of engagement by neighborhood - /funders page: the co-benefit/de-risk/readiness thesis + a live readout by climate priority and neighborhood, who can deliver, and what it unlocks - pledgeStore reworked to named, status-tracked signatures with consistent seeded baselines; new /api/wall and /api/funders; emails never exposed Green AI: open-weight Mistral Small on Scaleway's low-carbon grid, per-call EcoLogits energy/CO2e tracking, templated fallback when offline. Removes the old multi-city machinery (explorer, map picker, HIAP action prioritization, readiness score, funder-brief) and adds a /stories page, top nav, and a demo script. Co-Authored-By: Claude Opus 4.8 --- .../civic-climate-action/DEMO_SCRIPT.md | 79 +++ .../app/src/app/api/funders/route.ts | 13 + .../app/src/app/api/generate/route.ts | 22 +- .../app/src/app/api/metrics/route.ts | 10 +- .../app/src/app/api/pledge/route.ts | 57 +- .../app/src/app/api/wall/route.ts | 17 + .../app/src/app/components/ActionRow.tsx | 53 -- .../app/src/app/components/AiWorkspace.tsx | 411 ------------ .../app/src/app/components/CityActions.tsx | 118 ---- .../app/src/app/components/CityExplorer.tsx | 216 ------- .../app/src/app/components/CityMap.tsx | 63 -- .../app/src/app/components/CitySnapshot.tsx | 187 ------ .../app/src/app/components/CommitmentWall.tsx | 115 ++++ .../app/components/EngagementReadiness.tsx | 117 ---- .../app/src/app/components/FunderReadout.tsx | 107 +++ .../app/components/LocalEngagementPanel.tsx | 83 --- .../app/src/app/components/PledgeButton.tsx | 47 -- .../src/app/components/PoaEngagementMap.tsx | 62 ++ .../app/src/app/components/PoaMapInner.tsx | 37 ++ .../app/src/app/components/TakeAction.tsx | 176 ----- .../app/src/app/components/YourMove.tsx | 609 ++++++++++++++++++ .../app/src/app/data/actions.ts | 79 --- .../app/src/app/data/localSources.ts | 2 +- .../app/src/app/data/partnerOrgs.ts | 115 ++++ .../app/src/app/data/poaNeighborhoods.ts | 44 ++ .../app/src/app/funders/page.tsx | 151 +++++ .../app/src/app/globals.css | 5 +- .../app/src/app/layout.tsx | 21 +- .../app/src/app/lib/cityFacts.ts | 100 --- .../app/src/app/lib/engagementScore.ts | 102 --- .../app/src/app/lib/funderBrief.ts | 76 --- .../app/src/app/lib/hazardNormalize.ts | 45 -- .../app/src/app/lib/matchStories.ts | 48 -- .../app/src/app/lib/myCommitments.ts | 90 +++ .../app/src/app/lib/pledgeContext.tsx | 56 +- .../app/src/app/lib/pledgeStore.ts | 266 +++++++- .../app/src/app/lib/poaMoves.ts | 237 +++++++ .../app/src/app/lib/prioritize.ts | 166 ----- .../app/src/app/lib/profileHeadline.ts | 89 --- .../app/src/app/lib/useGenerate.ts | 2 + .../civic-climate-action/app/src/app/page.tsx | 215 +++++-- .../app/src/app/stories/page.tsx | 24 + .../civic-climate-action/llm-service/main.py | 78 ++- 43 files changed, 2314 insertions(+), 2296 deletions(-) create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/DEMO_SCRIPT.md create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/funders/route.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/wall/route.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityMap.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CitySnapshot.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CommitmentWall.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/FunderReadout.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaEngagementMap.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaMapInner.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/YourMove.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/actions.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/partnerOrgs.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/poaNeighborhoods.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/funders/page.tsx delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/myCommitments.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/poaMoves.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts delete mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts create mode 100644 events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/stories/page.tsx diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/DEMO_SCRIPT.md b/events/2026-06-11-unlock-the-money/civic-climate-action/DEMO_SCRIPT.md new file mode 100644 index 0000000..6f6ae07 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/DEMO_SCRIPT.md @@ -0,0 +1,79 @@ +# Civic Climate Action — Demo Script + +**What it is (one line):** A citizen-facing companion to CityCatalyst that turns top-down city climate data into one real, doable civic action — and turns that participation into a measurable, fundable engagement signal. Pilot: **Porto Alegre**. + +--- + +## 1. Problem & who feels the pain (30s) + +CityCatalyst tells **city governments** what to do about climate. But two groups are stuck: + +- **Residents** can see their city is at risk but have no idea how to actually act. Generic advice ("join a group", "contact the council") stops exactly where the hard part — *where do I start, what do I say?* — begins. +- **Funders** (MDBs, the IDB, philanthropy) need proof a city's community is engaged before they release money. Today that proof is anecdotal, so good projects stall. + +Same gap, both sides: civic engagement is real but **invisible and unusable**. + +--- + +## 2. Demo — show, don't tell (≈3 min) + +> Live at `localhost:3001`. Pilot city: Porto Alegre. + +1. **Home → "What's at stake"** (~20s): Porto Alegre's real risk, straight from CityCatalyst — **Floods & Landslides: Very High**, transport = 77% of emissions. This is the city's own data, in plain language. +2. **"Your move" → pick *Flooding* → *Quick & online*** (~30s): Instead of vague advice, **one concrete move**: *"Report a flooding or drainage problem on your street to Defesa Civil"* — the **real channel** (working link), a time estimate (~10 min), **Why this helps**, and **What happens next**. +3. **The AI toolkit — two tabs** (~45s): + - **✉️ Ready-to-send message:** an AI-written, copy-ready message in PT (toggle EN), grounded in the real channel — no filler, no lecturing the recipient. + - **🧭 Guide me:** a civic-coach **chat** that builds a *toolkit* from all the available next steps + partner orgs — **what to do, how, and why** — and answers follow-ups ("how do I run a block meeting?", "what if I get no reply?"). It's constrained to the real local channels/orgs only — it won't invent contacts. + - Point at the **carbon figure** (~0.01–0.03 g CO₂e per reply) — see the green-AI note below. +4. **"Team up with people already doing this"** (~15s): real Porto Alegre / RS organizations — **Parceiros Voluntários, BrazilFoundation, AGAPAN, Bike Anjo** — with concrete plug-ins: **Volunteer / Attend / Back a campaign / Donate**. Not just a contact link. +5. **"I care about this"** (~30s): add name + neighborhood (email optional). The message **auto-fills with your details** (it's now genuinely yours), and you get a **tracker** — *Committed → Sent → Got a response* — plus a dated **receipt**. A signature, not a throwaway click. +6. **"On the record"** (~25s): a **map of Porto Alegre** with engagement by neighborhood, a **"Most-backed actions" ranking** (Flooding 33 · Heat 19 · Landslides 15…), and a live **commitment wall** of named residents. +7. **"For funders" page** (~30s): the punchline — the **live readout**: total signed commitments, **follow-through rate**, demand **by climate priority** (mapped to the CCRA risk levels) and **by neighborhood**, the local orgs who can **deliver**, and **what each theme could unlock**. + +### Under the hood — green AI, measured (≈15s aside) + +- **Model choice:** an **open-weight ~24B model (Mistral Small)** — small and capable enough for grounded, templated writing; we don't need a frontier model. Provider is swappable by env (Scaleway / GreenPT / Mistral / Salamandra). +- **Hosting:** served on **Scaleway's low-carbon EU grid** (~52 gCO₂e/kWh) — green by default, not as an afterthought. +- **Carbon tracking:** every call is measured with **EcoLogits** (by the GenAI Impact non-profit) — energy (Wh) + emissions (gCO₂e) shown **per reply** and totalled in the session **carbon counter**. Honest caveats: figures are estimates (it falls back to a token-based estimate for models outside EcoLogits' registry), and if the model is offline the app serves a **graceful templated fallback** so the demo never breaks. + +--- + +## 3. Business value — who pays / premium feature / funder trust / 💰 + +**The unlock:** civic participation is a co-benefit funders **already score** (CityCatalyst's HIAP rates *stakeholder engagement* −2..+2). We make it **visible, sourced, and continuous** — which is exactly what moves money: + +- **Raises the co-benefit score** → a more fundable project. +- **De-risks disbursement** → named, located demand + follow-through answers a credit committee's "will the community actually use this?" +- **Satisfies the readiness/consultation gate** → produces the stakeholder-engagement record many funds *require*, continuously instead of as a one-off survey. + +**Who pays / how it makes money:** + +- **Premium CityCatalyst add-on:** free public citizen view; **paid white-label civic dashboards** for cities & consultancies. +- **Grant-funded pilots:** 3–5 cities already on CityCatalyst (Brazil-first). +- **MDB / IDB co-financing:** sold as the **"community-engagement component"** inside climate project-preparation programs. +- **Differentiation:** most city-climate tools serve governments only — this serves **citizens**, differentiating CityCatalyst across the **IDB Cities Network (300+ LAC cities)**. + +--- + +## 4. What's left to reach prod (honest) + +- **Data (the real cost):** local channels + partner orgs are **hand-curated for Porto Alegre only**. Scaling = per-city research + link verification + neighborhood geocoding. Some themes (e.g. energy) have thin org coverage today. +- **Integration:** swap baked-in CityCatalyst figures for **live API fetch**; replace the file-backed pledge store with a **real database**; add **identity/auth + anti-abuse** so the tally is trustworthy; wire **email follow-up**; ideally connect to real consultation platforms (Participe+, Orçamento Participativo). +- **Trust/verification:** follow-through is currently **self-reported** (a proxy MRV) and demo numbers include a clearly-labelled seeded baseline — production needs verified signals. +- **Effort:** ~weeks to harden one city end-to-end; the multi-city onboarding pipeline is the larger lift. + +--- + +## 5. The ask — what we need to keep going + +- **One pilot city** already on CityCatalyst (Porto Alegre or another BR municipality) as a design partner. +- **An intro to an MDB / IDB contact** to validate the co-benefit-as-fundable-evidence framing with a real appraisal process. +- **Eng time** to wire live CityCatalyst data + a real datastore + auth. +- **A small grant / owner** for local-org curation across the first 3–5 cities. +- **A decision:** does this become a supported **CityCatalyst module**? + +--- + +## 6. The hardest part of this hackday for me + + diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/funders/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/funders/route.ts new file mode 100644 index 0000000..28e9aab --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/funders/route.ts @@ -0,0 +1,13 @@ +// Funder readout: engagement aggregated by theme + neighborhood for a city. +// No personal data (no emails, no names) — only counts. + +import { NextResponse } from "next/server"; +import { getFunderReadout } from "../../lib/pledgeStore"; + +export const runtime = "nodejs"; + +export async function GET(req: Request) { + const { searchParams } = new URL(req.url); + const city = (searchParams.get("city") || "porto-alegre").slice(0, 64); + return NextResponse.json({ city, readout: getFunderReadout(city) }); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts index 7817f1f..0b97322 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/generate/route.ts @@ -65,6 +65,20 @@ function fallbackContent(b: Body): string { const lang = b.language; const T = (en: string, es: string, pt: string) => (lang === "es" ? es : lang === "pt" ? pt : en); + if (b.task === "civic_guide") { + return T( + `**Start with one small step.**\n\n1. **What:** the easiest entry here is **${channel}**.\n2. **How:** open ${channel}, describe your street or spot in a line or two (a photo helps), and send.\n3. **Why:** documented, located voices are what move this up the city's priority list.\n\nWant help with what to say, or how to bring a few neighbours in?`, + `**Empieza con un primer paso pequeño.**\n\n1. **Qué:** la vía más fácil aquí es **${channel}**.\n2. **Cómo:** abre ${channel}, describe tu calle o el punto en una o dos líneas (una foto ayuda) y envíalo.\n3. **Por qué:** las voces concretas y localizadas son las que suben esto en la lista de prioridades de la ciudad.\n\n¿Quieres ayuda con qué decir o cómo sumar a tus vecinos?`, + `**Comece com um primeiro passo pequeno.**\n\n1. **O quê:** o caminho mais fácil aqui é o **${channel}**.\n2. **Como:** abra o ${channel}, descreva sua rua ou o ponto em uma ou duas linhas (uma foto ajuda) e envie.\n3. **Por quê:** vozes concretas e localizadas são o que faz isso subir na lista de prioridades da cidade.\n\nQuer ajuda com o que dizer ou como envolver alguns vizinhos?` + ); + } + if (b.task === "local_message") { + return T( + `Hello ${channel},\n\nI'm a resident and I'd like to ask for your help to: ${a.toLowerCase()}. It's a practical, local response to a real concern in our neighbourhood, and it would make the area safer and healthier. Could we talk about a first step?\n\nThank you, [Your name], [Neighbourhood]`, + `Hola ${channel}:\n\nSoy vecino y quisiera pedir su ayuda para: ${a.toLowerCase()}. Es una respuesta local y práctica a una preocupación real de nuestro barrio, y haría la zona más segura y saludable. ¿Podríamos hablar de un primer paso?\n\nGracias, [Tu nombre], [Barrio]`, + `Olá, ${channel},\n\nSou morador e gostaria de pedir apoio para: ${a.toLowerCase()}. É uma resposta local e prática a uma preocupação real do nosso bairro, e tornaria a região mais segura e saudável. Podemos conversar sobre um primeiro passo?\n\nObrigado(a), [Seu nome], [Bairro]` + ); + } if (b.task === "future_vision") { return T( `## Where today's trends point\nOn its current path, ${c.name} faces growing climate pressure. Without sustained action, those pressures compound.\n\n## A plausible future history (to ~2050)\nLooking back from 2050, "${a.toLowerCase()}" started small — pushed by residents through ${channel} — then scaled as results showed and held.\n\n## Two futures, side by side\n- **If little changes (probable):** the same risks, unevenly felt.\n- **If this action takes hold (preferable):** a more resilient, livable city, with gains in health and cost of living.\n\n_What it asks of us now: a modest, shared effort today for a city future generations inherit._`, @@ -102,10 +116,10 @@ function fallbackContent(b: Body): string { ); return (b.prior || "_(nothing to refine yet)_") + note; } - // next_steps + // next_steps — concrete next steps + a ready-to-send message return T( - `1. Find a neighborhood group in ${c.name} already working on this.\n2. Bring **${a}** to **${channel}** as a proposal or public comment.\n3. Back it with your city's own climate data.\n4. Invite three neighbors to join and share progress.`, - `1. Busca un grupo vecinal en ${c.name} que ya trabaje en esto.\n2. Lleva **${a}** a **${channel}** como propuesta o comentario público.\n3. Respáldalo con los datos climáticos de tu ciudad.\n4. Invita a tres vecinos a sumarse y comparte el avance.`, - `1. Procure um grupo de bairro em ${c.name} que já atue nisso.\n2. Leve **${a}** ao **${channel}** como proposta ou comentário público.\n3. Embase com os dados climáticos da sua cidade.\n4. Convide três vizinhos e compartilhe o progresso.` + `## Next steps\n1. Find a neighborhood group in ${c.name} already working on this.\n2. Bring **${a}** to **${channel}** as a proposal or public comment.\n3. Back it with your city's own climate data.\n4. Invite three neighbors to join and share progress.\n\n## Ready-to-send message\nHello, I'm a resident writing to ask **${channel}** to support **${a.toLowerCase()}** in our neighborhood. It's a practical, local response to our city's top climate concerns and would make our area safer and healthier. Could we discuss a small first step? Thank you, [Your name], [Neighborhood]`, + `## Próximos pasos\n1. Busca un grupo vecinal en ${c.name} que ya trabaje en esto.\n2. Lleva **${a}** a **${channel}** como propuesta o comentario público.\n3. Respáldalo con los datos climáticos de tu ciudad.\n4. Invita a tres vecinos a sumarse y comparte el avance.\n\n## Mensaje listo para enviar\nHola, soy un vecino y escribo para pedir a **${channel}** que apoye **${a.toLowerCase()}** en nuestro barrio. Es una respuesta local y práctica a las principales preocupaciones climáticas de la ciudad, y haría nuestra zona más segura y saludable. ¿Podríamos hablar de un primer paso? Gracias, [Tu nombre], [Barrio]`, + `## Próximos passos\n1. Procure um grupo de bairro em ${c.name} que já atue nisso.\n2. Leve **${a}** ao **${channel}** como proposta ou comentário público.\n3. Embase com os dados climáticos da sua cidade.\n4. Convide três vizinhos e compartilhe o progresso.\n\n## Mensagem pronta para enviar\nOlá, sou morador e escrevo para pedir ao **${channel}** que apoie **${a.toLowerCase()}** no nosso bairro. É uma resposta local e prática às principais preocupações climáticas da cidade e tornaria nossa região mais segura e saudável. Podemos conversar sobre um primeiro passo? Obrigado, [Seu nome], [Bairro]` ); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts index 433fdeb..f4d69d2 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/metrics/route.ts @@ -1,10 +1,14 @@ -// Per-city pledge counts for the live engagement tally + readiness score. +// Per-city commitment aggregates (total signed · reported sent · responded) for +// the live engagement signal. import { NextResponse } from "next/server"; -import { getCounts } from "../../lib/pledgeStore"; +import { getCityAggregate } from "../../lib/pledgeStore"; export const runtime = "nodejs"; +const CITIES = ["porto-alegre"]; + export async function GET() { - return NextResponse.json({ counts: getCounts() }); + const cities = Object.fromEntries(CITIES.map((id) => [id, getCityAggregate(id)])); + return NextResponse.json({ cities }); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts index d761560..5a79509 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/pledge/route.ts @@ -1,13 +1,14 @@ -// Capture a resident's "I'll act on this" pledge. Aggregated server-side so the -// engagement metric reflects real commitment across visitors. +// Capture a resident's signed commitment to act (POST) and track it through to +// done (PATCH). Aggregated server-side so the live "N residents committed · M +// reported sent" signal reflects real, named, followed-through participation. import { NextResponse } from "next/server"; -import { increment, getCount } from "../../lib/pledgeStore"; +import { createPledge, setStatus, getCityAggregate, type PledgeStatus } from "../../lib/pledgeStore"; export const runtime = "nodejs"; -// Light per-process rate guard so the live tally can't be trivially inflated on -// stage (a real deployment would rate-limit per IP / require a token). +// Light per-process rate guard so the tally can't be trivially inflated on stage +// (a real deployment would rate-limit per IP / require a token). const WINDOW_MS = 60_000; const MAX_PER_WINDOW = 60; let hits: number[] = []; @@ -20,18 +21,54 @@ function rateLimited(): boolean { return false; } +const str = (v: unknown, max: number) => (typeof v === "string" ? v.slice(0, max).trim() : ""); + export async function POST(req: Request) { - let body: { cityId?: string }; + let body: Record; try { body = await req.json(); } catch { return NextResponse.json({ error: "invalid body" }, { status: 400 }); } - const cityId = typeof body.cityId === "string" ? body.cityId.slice(0, 64) : ""; - if (!cityId) return NextResponse.json({ error: "cityId required" }, { status: 400 }); + const cityId = str(body.cityId, 64); + const actionId = str(body.actionId, 64); + const firstName = str(body.firstName, 60); + const neighborhood = str(body.neighborhood, 80); + if (!cityId || !actionId || !firstName) { + return NextResponse.json({ error: "cityId, actionId, firstName required" }, { status: 400 }); + } if (rateLimited()) { - return NextResponse.json({ cityId, count: getCount(cityId), throttled: true }); + return NextResponse.json({ aggregate: getCityAggregate(cityId), throttled: true }, { status: 429 }); + } + + const pledge = createPledge({ + cityId, + actionId, + worryLabel: str(body.worryLabel, 80), + headline: str(body.headline, 240), + firstName, + neighborhood, + email: str(body.email, 160) || undefined, + }); + return NextResponse.json({ pledge, aggregate: getCityAggregate(cityId) }); +} + +const VALID: PledgeStatus[] = ["committed", "sent", "responded"]; + +export async function PATCH(req: Request) { + let body: { id?: string; status?: string }; + try { + body = await req.json(); + } catch { + return NextResponse.json({ error: "invalid body" }, { status: 400 }); + } + const id = str(body.id, 64); + const status = body.status as PledgeStatus; + if (!id || !VALID.includes(status)) { + return NextResponse.json({ error: "id and valid status required" }, { status: 400 }); } - return NextResponse.json({ cityId, count: increment(cityId) }); + const pledge = setStatus(id, status); + if (!pledge) return NextResponse.json({ error: "not found" }, { status: 404 }); + return NextResponse.json({ pledge, aggregate: getCityAggregate(pledge.cityId) }); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/wall/route.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/wall/route.ts new file mode 100644 index 0000000..f068790 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/api/wall/route.ts @@ -0,0 +1,17 @@ +// Public commitment wall: recent signed commitments for a city. Returns +// first-name + neighborhood + worry + status only — never emails. + +import { NextResponse } from "next/server"; +import { getRecent, getCityAggregate, getActionRanking } from "../../lib/pledgeStore"; + +export const runtime = "nodejs"; + +export async function GET(req: Request) { + const { searchParams } = new URL(req.url); + const city = (searchParams.get("city") || "porto-alegre").slice(0, 64); + return NextResponse.json({ + recent: getRecent(city, 12), + aggregate: getCityAggregate(city), + ranking: getActionRanking(city), + }); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx deleted file mode 100644 index 23597d0..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/ActionRow.tsx +++ /dev/null @@ -1,53 +0,0 @@ -"use client"; - -import type { Lang } from "../data/climateActions"; -import type { RankedAction } from "../lib/prioritize"; - -const typeMeta = { - adaptation: { label: { en: "Adaptation", es: "Adaptación", pt: "Adaptação" }, color: "var(--accent)" }, - mitigation: { label: { en: "Mitigation", es: "Mitigación", pt: "Mitigação" }, color: "#d97706" }, -} as const; - -export default function ActionRow({ - ranked, - lang, - selected, - onSelect, -}: { - ranked: RankedAction; - lang: Lang; - selected: boolean; - onSelect: () => void; -}) { - const { action, sourceSignals } = ranked; - const meta = typeMeta[action.actionType]; - const why = sourceSignals[0]?.cityValue; - - return ( - - ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx deleted file mode 100644 index 3d585d1..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/AiWorkspace.tsx +++ /dev/null @@ -1,411 +0,0 @@ -"use client"; - -import { useEffect, useMemo, useState } from "react"; -import type { Lang } from "../data/climateActions"; -import type { LocalSource } from "../data/localEngagement"; -import type { RankedAction } from "../lib/prioritize"; -import { useGenerate, type GenResult, type GenTask } from "../lib/useGenerate"; -import { stories } from "../data/stories"; -import { matchStories } from "../lib/matchStories"; -import { categoryMeta } from "../data/types"; -import Markdown from "./Markdown"; -import PledgeButton from "./PledgeButton"; - -type LensKey = GenTask | "examples"; - -type CityContext = { - country: string; - topHazards: string[]; - topSectors: string[]; - localSources: string[]; - facts: string[]; -}; - -const LENSES: { - key: LensKey; - llm: boolean; - label: Record; - desc: Record; -}[] = [ - { - key: "next_steps", - llm: true, - label: { en: "Next steps", es: "Próximos pasos", pt: "Próximos passos" }, - desc: { - en: "Concrete moves you can make in the coming weeks.", - es: "Acciones concretas para las próximas semanas.", - pt: "Ações concretas para as próximas semanas.", - }, - }, - { - key: "draft_proposal", - llm: true, - label: { en: "Draft a proposal", es: "Redactar propuesta", pt: "Redigir proposta" }, - desc: { - en: "A ready-to-send draft for your town hall.", - es: "Un borrador listo para enviar a tu municipio.", - pt: "Um rascunho pronto para enviar à prefeitura.", - }, - }, - { - key: "evidence", - llm: true, - label: { en: "Back it with data", es: "Respáldalo con datos", pt: "Embase com dados" }, - desc: { - en: "Facts and sources to make your case.", - es: "Datos y fuentes para sustentar tu caso.", - pt: "Dados e fontes para embasar seu caso.", - }, - }, - { - key: "pathways", - llm: true, - label: { en: "Pathways", es: "Rutas", pt: "Caminhos" }, - desc: { - en: "From a quick first move to citywide change.", - es: "De un primer paso a un cambio en toda la ciudad.", - pt: "De um primeiro passo à mudança em toda a cidade.", - }, - }, - { - key: "examples", - llm: false, - label: { en: "Examples", es: "Ejemplos", pt: "Exemplos" }, - desc: { - en: "Where this has already worked.", - es: "Dónde ya ha funcionado.", - pt: "Onde isto já funcionou.", - }, - }, - { - key: "future_vision", - llm: true, - label: { en: "Futures", es: "Futuros", pt: "Futuros" }, - desc: { - en: "Data-backed plausible futures if this scales — trends, not guesses.", - es: "Futuros plausibles con base en datos — tendencias, no conjeturas.", - pt: "Futuros plausíveis com base em dados — tendências, não palpites.", - }, - }, -]; - -const t = { - generate: { en: "Generate", es: "Generar", pt: "Gerar" }, - regenerate: { en: "Regenerate", es: "Regenerar", pt: "Regenerar" }, - working: { en: "Working…", es: "Generando…", pt: "Gerando…" }, - copy: { en: "Copy", es: "Copiar", pt: "Copiar" }, - copied: { en: "Copied", es: "Copiado", pt: "Copiado" }, - refinePh: { - en: "Refine — e.g. shorter, more formal, focus on flooding…", - es: "Refinar — p. ej. más corto, más formal, enfocar en inundaciones…", - pt: "Refinar — ex. mais curto, mais formal, focar em enchentes…", - }, - refine: { en: "Refine", es: "Refinar", pt: "Refinar" }, - where: { en: "Where to engage locally", es: "Dónde participar localmente", pt: "Onde participar localmente" }, - estimated: { en: "est.", es: "est.", pt: "est." }, - disclaimer: { - en: "AI-generated draft — check the facts and local details before submitting.", - es: "Borrador generado por IA — verifica los datos y detalles locales antes de enviarlo.", - pt: "Rascunho gerado por IA — confira os fatos e detalhes locais antes de enviar.", - }, - futureLabel: { - en: "Plausible futures · grounded in this city's data (Futures Design)", - es: "Futuros plausibles · con base en los datos de la ciudad (Futures Design)", - pt: "Futuros plausíveis · com base nos dados da cidade (Futures Design)", - }, - noExamples: { en: "No close examples yet — browse the Inspiration gallery below.", es: "Aún sin ejemplos cercanos — mira la galería de Inspiración abajo.", pt: "Ainda sem exemplos próximos — veja a galeria de Inspiração abaixo." }, -}; - -const typeColor = { adaptation: "var(--accent)", mitigation: "#d97706" } as const; - -export default function AiWorkspace({ - ranked, - cityId, - cityName, - cityContext, - localSources, - lang, -}: { - ranked: RankedAction; - cityId: string; - cityName: string; - cityContext: CityContext; - localSources: LocalSource[]; - lang: Lang; -}) { - const { action } = ranked; - const { run } = useGenerate(); - const [active, setActive] = useState("next_steps"); - const [cache, setCache] = useState>>({}); - const [pendingSet, setPendingSet] = useState>(new Set()); - const [refineText, setRefineText] = useState(""); - const [copied, setCopied] = useState(false); - - // Reset transient input/feedback when the lens changes (don't carry a refine - // instruction or a "Copied" flag across lenses). - useEffect(() => { - setRefineText(""); - setCopied(false); - }, [active]); - - const exampleStories = useMemo(() => matchStories(action, stories), [action]); - - const lens = LENSES.find((l) => l.key === active)!; - const result = cache[active]; - - async function generate(task: GenTask, opts: { prior?: string; instruction?: string } = {}) { - const lensKey = active; // capture: the lens this generation belongs to - setPendingSet((p) => new Set(p).add(lensKey)); - const res = await run({ - task, - action: { name: action.name[lang], description: action.description[lang], type: action.actionType }, - cityContext: { name: cityName, ...cityContext }, - language: lang, - ...opts, - }); - setPendingSet((p) => { - const n = new Set(p); - n.delete(lensKey); - return n; - }); - if (res) setCache((c) => ({ ...c, [lensKey]: res })); - } - - function onRefine() { - if (!result || !refineText.trim()) return; - generate("refine", { prior: result.content, instruction: refineText.trim() }); - setRefineText(""); - } - - function copy() { - if (!result) return; - const done = () => { - setCopied(true); - setTimeout(() => setCopied(false), 1500); - }; - if (navigator.clipboard?.writeText) { - navigator.clipboard.writeText(result.content).then(done).catch(fallbackCopy); - } else { - fallbackCopy(); - } - function fallbackCopy() { - try { - const ta = document.createElement("textarea"); - ta.value = result!.content; - ta.style.position = "fixed"; - ta.style.opacity = "0"; - document.body.appendChild(ta); - ta.select(); - document.execCommand("copy"); - document.body.removeChild(ta); - done(); - } catch { - /* clipboard unavailable */ - } - } - } - - const isLoading = pendingSet.has(active); - - return ( -

- {/* Action header */} -
- - {action.actionType} - -

{action.name[lang]}

- -
- - {/* Lens tabs */} -
- {LENSES.map((l) => ( - - ))} -
- - {/* Lens body */} -
-

- {lens.desc[lang]} -

- - {active === "examples" ? ( - - ) : isLoading ? ( -
{t.working[lang]}
- ) : !result ? ( - - ) : ( -
- {active === "future_vision" && ( -
- {t.futureLabel[lang]} -
- )} - {result.content} - -

- {t.disclaimer[lang]} -

- - {/* Refine bar */} -
- setRefineText(e.target.value)} - onKeyDown={(e) => e.key === "Enter" && onRefine()} - placeholder={t.refinePh[lang]} - style={{ - flex: 1, - padding: "0.5rem 0.7rem", - border: "1px solid var(--line)", - borderRadius: 8, - fontSize: "0.85rem", - background: "var(--bg)", - outlineColor: "var(--accent)", - }} - /> - -
- - {/* Actions + carbon */} -
- - - {isLoading ? ( - {t.working[lang]} - ) : ( - - ~{result.gCO2e.toFixed(3)} g CO₂e ({t.estimated[lang]}) · {result.model} - - )} -
-
- )} -
- - {/* Local sources footer */} - {localSources.length > 0 && ( -
-
- {t.where[lang]} -
-
- {localSources.slice(0, 8).map((s) => ( - - {s.name} ↗ - - ))} -
-
- )} -
- ); -} - -function ExamplesList({ stories, lang }: { stories: ReturnType; lang: Lang }) { - if (stories.length === 0) { - return

{t.noExamples[lang]}

; - } - return ( -
- {stories.map((s) => { - const m = categoryMeta[s.category]; - return ( -
-
- {m.label} - - {s.city}, {s.country} - -
-
{s.title}
-

{s.outcome}

- - {s.sourceName} ↗ - -
- ); - })} -
- ); -} - -const ctaStyle: React.CSSProperties = { - font: "inherit", - fontSize: "0.9rem", - fontWeight: 650, - cursor: "pointer", - color: "#fff", - background: "var(--accent)", - border: "none", - borderRadius: 8, - padding: "0.6rem 1rem", -}; - -const smallBtn: React.CSSProperties = { - font: "inherit", - fontSize: "0.78rem", - fontWeight: 600, - cursor: "pointer", - color: "var(--accent)", - background: "var(--accent-soft)", - border: "none", - borderRadius: 8, - padding: "0.35rem 0.7rem", -}; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx deleted file mode 100644 index 70a74a7..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityActions.tsx +++ /dev/null @@ -1,118 +0,0 @@ -"use client"; - -import { useMemo, useState } from "react"; -import type { City } from "../data/types"; -import type { Lang } from "../data/climateActions"; -import { climateActions } from "../data/climateActions"; -import { prioritizeActions } from "../lib/prioritize"; -import { localSourcesByCity, localSourceNamesByCity } from "../data/localSources"; -import { cityFacts } from "../lib/cityFacts"; -import ActionRow from "./ActionRow"; -import AiWorkspace from "./AiWorkspace"; - -const LANGS: { key: Lang; label: string }[] = [ - { key: "en", label: "EN" }, - { key: "es", label: "ES" }, - { key: "pt", label: "PT" }, -]; - -const defaultLang = (country: string): Lang => { - if (country === "Brazil") return "pt"; - if (["Colombia", "Mexico", "Argentina", "Chile", "Peru"].includes(country)) return "es"; - return "en"; -}; - -const copy = { - heading: { en: "Develop an action for", es: "Desarrolla una acción para", pt: "Desenvolva uma ação para" }, - intro: { - en: "Recommended climate actions for this city, from CityCatalyst. Pick one and build a concrete, local plan.", - es: "Acciones climáticas recomendadas para esta ciudad, según CityCatalyst. Elige una y crea un plan local concreto.", - pt: "Ações climáticas recomendadas para esta cidade, segundo o CityCatalyst. Escolha uma e crie um plano local concreto.", - }, -}; - -export default function CityActions({ city }: { city: City }) { - const [lang, setLang] = useState(defaultLang(city.country)); - const ranked = useMemo(() => prioritizeActions(city, climateActions, { topN: 4 }), [city]); - const [selectedActionId, setSelectedActionId] = useState(ranked[0]?.action.actionId ?? null); - - if (ranked.length === 0) return null; - const selected = ranked.find((r) => r.action.actionId === selectedActionId) ?? ranked[0]; - - // When the inventory is partial, sector shares are overstated — present them - // qualitatively (no precise %) so the model never cites an unreliable number. - const partial = Boolean(city.emissions?.note); - const cityContext = { - country: city.country, - topHazards: (city.risk?.topHazards ?? []).map((h) => `${h.hazard} (${h.level})`), - topSectors: - city.emissions?.sectors?.map((s) => - partial ? s.sector : `${s.sector} (${Math.round(s.sharePct)}%)` - ) ?? (city.emissions?.topSector ? [city.emissions.topSector] : []), - localSources: localSourceNamesByCity[city.id] ?? [], - facts: cityFacts(city, lang), - dataCaveat: city.emissions?.note ?? "", - }; - const localSources = localSourcesByCity[city.id] ?? []; - - return ( -
-
-
-
- {copy.heading[lang]} {city.name} -
-

- {copy.intro[lang]} -

-
-
- {LANGS.map((l) => ( - - ))} -
-
- -
-
- {ranked.map((r) => ( - setSelectedActionId(r.action.actionId)} - /> - ))} -
- - -
-
- ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx deleted file mode 100644 index ce47fc0..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityExplorer.tsx +++ /dev/null @@ -1,216 +0,0 @@ -"use client"; - -import { useMemo, useState } from "react"; -import dynamic from "next/dynamic"; -import type { City, Story } from "../data/types"; -import { categoryMeta } from "../data/types"; -import CitySnapshot from "./CitySnapshot"; -import CityActions from "./CityActions"; -import EngagementReadiness from "./EngagementReadiness"; -import { isPilot } from "../lib/pilots"; -import { profileHeadline } from "../lib/profileHeadline"; - -const CityMap = dynamic(() => import("./CityMap"), { - ssr: false, - loading: () => ( -
- Loading map… -
- ), -}); - -function CategoryDot({ category }: { category: Story["category"] }) { - const m = categoryMeta[category]; - return ( - - - {m.label} - - ); -} - -export default function CityExplorer({ cities, stories }: { cities: City[]; stories: Story[] }) { - const [query, setQuery] = useState(""); - const [selectedId, setSelectedId] = useState(cities[0]?.id ?? null); - - const filtered = useMemo(() => { - const q = query.trim().toLowerCase(); - if (!q) return cities; - return cities.filter( - (c) => - c.name.toLowerCase().includes(q) || - c.country.toLowerCase().includes(q) || - c.summary.toLowerCase().includes(q) - ); - }, [query, cities]); - - const selected = cities.find((c) => c.id === selectedId) ?? null; - const selectedStories = selected - ? stories.filter((s) => selected.storyIds.includes(s.id)) - : []; - - function pick(id: string) { - setSelectedId(id); - } - - const headline = selected ? profileHeadline(selected, "en") : null; - - return ( -
- {/* Top row: search + list | map */} -
- {/* Left: search + list */} -
- setQuery(e.target.value)} - placeholder={`Search ${cities.length} cities…`} - aria-label="Search cities" - style={{ - width: "100%", - padding: "0.7rem 0.9rem", - border: "1px solid var(--line)", - borderRadius: 10, - fontSize: "0.95rem", - outlineColor: "var(--accent)", - marginBottom: "0.75rem", - }} - /> -
- {filtered.length === 0 && ( -

- No cities match “{query}”. -

- )} - {filtered.map((c) => { - const active = c.id === selectedId; - return ( - - ); - })} -
-
- - {/* Right: map */} -
- -
-
- - {/* Full-width detail for the selected city */} - {selected && ( -
-

- {selected.name}, {selected.country} -

- {headline && ( -

{headline}

- )} -

- {selected.summary} -

- - - - - - {isPilot(selected.id) && } - - {selectedStories.length > 0 && ( -
-
- Citizens have done this -
-
- {selectedStories.map((s) => ( -
-
- - {s.year} -
-
{s.title}
-

- {s.outcome} -

- - Source: {s.sourceName} ↗ - -
- ))} -
-
- )} -
- )} -
- ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityMap.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityMap.tsx deleted file mode 100644 index 4caaa59..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CityMap.tsx +++ /dev/null @@ -1,63 +0,0 @@ -"use client"; - -import { CircleMarker, MapContainer, TileLayer, Tooltip, useMap } from "react-leaflet"; -import { useEffect } from "react"; -import type { City } from "../data/types"; - -function FlyTo({ city }: { city: City | null }) { - const map = useMap(); - useEffect(() => { - if (city) map.flyTo([city.lat, city.lng], 5, { duration: 0.8 }); - }, [city, map]); - return null; -} - -export default function CityMap({ - cities, - selectedId, - onSelect, -}: { - cities: City[]; - selectedId: string | null; - onSelect: (id: string) => void; -}) { - const selected = cities.find((c) => c.id === selectedId) ?? null; - - return ( - - - - {cities.map((c) => { - const active = c.id === selectedId; - return ( - onSelect(c.id) }} - > - - {c.name}, {c.country} - - - ); - })} - - ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CitySnapshot.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CitySnapshot.tsx deleted file mode 100644 index ba12e01..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CitySnapshot.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import type { City, RiskLevel } from "../data/types"; - -const riskColor: Record = { - Low: "#16a34a", - Medium: "#d97706", - High: "#dc2626", - "Very High": "#991b1b", -}; - -const sectorColor: Record = { - "Stationary Energy": "#2563eb", - Transportation: "#0ea5e9", - Waste: "#7c3aed", - IPPU: "#d97706", - AFOLU: "#15803d", - "Buildings/Energy": "#2563eb", - Buildings: "#2563eb", - Energy: "#2563eb", -}; - -function formatCo2e(tonnes: number): string { - if (tonnes >= 1_000_000) return `${(tonnes / 1_000_000).toFixed(1)} Mt`; - if (tonnes >= 1_000) return `${Math.round(tonnes / 1_000).toLocaleString()} kt`; - return `${Math.round(tonnes).toLocaleString()} t`; -} - -function ProvenanceBadge({ provenance }: { provenance: City["dataProvenance"] }) { - const live = provenance === "CityCatalyst"; - return ( - - {live ? "CityCatalyst live" : "External source"} - - ); -} - -export default function CitySnapshot({ city }: { city: City }) { - const { emissions, risk } = city; - if (!emissions && !risk) return null; - - return ( -
- {/* Emissions */} - {emissions && ( -
-
- Emissions - -
-
- - {formatCo2e(emissions.totalTonnesCo2e)} - - - CO₂e / year - -
-
- Inventory {emissions.inventoryYear} - {emissions.perCapitaTonnes - ? ` · ${emissions.perCapitaTonnes.toFixed(1)} t per person` - : ""} -
- {emissions.note && ( -
- {emissions.note} -
- )} - - {emissions.sectors && - emissions.sectors.slice(0, 5).map((s) => ( -
-
- {s.sector} - {s.sharePct}% -
-
-
-
-
- ))} - - {!emissions.sectors && emissions.topSector && ( -
- Largest source: - {emissions.topSector} -
- )} - - - {emissions.source} ↗ - -
- )} - - {/* Risk */} - {risk && ( -
-
- Climate risk - -
- - {risk.summary && ( -

- {risk.summary} -

- )} - -
- {risk.topHazards.map((h) => ( -
- - {h.hazard} - {h.keyImpact ? ( - · {h.keyImpact} - ) : null} - - - {h.level} - -
- ))} -
- - - {risk.source} ↗ - -
- )} -
- ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CommitmentWall.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CommitmentWall.tsx new file mode 100644 index 0000000..aa7b0d8 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/CommitmentWall.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { useEffect, useState } from "react"; +import type { PublicPledge, CityAggregate, ActionRank } from "../lib/pledgeStore"; +import { worryByRecId } from "../lib/poaMoves"; + +const CITY_ID = "porto-alegre"; + +function timeAgo(iso: string): string { + const diff = Date.now() - new Date(iso).getTime(); + const m = Math.round(diff / 60000); + if (m < 1) return "just now"; + if (m < 60) return `${m}m ago`; + const h = Math.round(m / 60); + if (h < 24) return `${h}h ago`; + const d = Math.round(h / 24); + return `${d}d ago`; +} + +const statusMeta: Record = { + committed: { label: "committed", color: "var(--ink-soft)" }, + sent: { label: "✅ sent", color: "var(--accent)" }, + responded: { label: "✅ got a response", color: "var(--accent)" }, +}; + +export default function CommitmentWall() { + const [recent, setRecent] = useState([]); + const [agg, setAgg] = useState(null); + const [ranking, setRanking] = useState([]); + + useEffect(() => { + let alive = true; + const fetchWall = () => + fetch(`/api/wall?city=${CITY_ID}`) + .then((r) => r.json()) + .then((d) => { + if (!alive) return; + setRecent(d.recent ?? []); + setAgg(d.aggregate ?? null); + setRanking(d.ranking ?? []); + }) + .catch(() => {}); + fetchWall(); + // refresh when the tab regains focus, so a fresh signature shows up + const onFocus = () => fetchWall(); + window.addEventListener("focus", onFocus); + return () => { + alive = false; + window.removeEventListener("focus", onFocus); + }; + }, []); + + return ( +
+ {agg && ( +

+ {agg.total.toLocaleString()}{" "} + residents have signed a commitment ·{" "} + {agg.sent.toLocaleString()}{" "} + reported they followed through. +

+ )} + + {ranking.length > 0 && ( +
+
Most-backed actions in Porto Alegre
+
+ {ranking.slice(0, 5).map((a, i) => { + const w = worryByRecId(a.actionId); + const max = Math.max(1, ranking[0].count); + return ( +
+ #{i + 1} + {w?.icon ?? "•"} +
+
+ {w?.label ?? a.actionId} + + {a.count.toLocaleString()} committed · {a.sent} acted + +
+
+
+
+
+
+ ); + })} +
+
+ )} + +
Recent commitments
+
+ {recent.map((p) => { + const s = statusMeta[p.status] ?? statusMeta.committed; + return ( +
+ {p.firstName} + {p.neighborhood} + + committed to {p.worryLabel.toLowerCase()} action + + {s.label} + {timeAgo(p.createdAt)} +
+ ); + })} +
+
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx deleted file mode 100644 index 466c8f1..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/EngagementReadiness.tsx +++ /dev/null @@ -1,117 +0,0 @@ -"use client"; - -import { useMemo } from "react"; -import type { City } from "../data/types"; -import { usePledges } from "../lib/pledgeContext"; -import { engagementReadiness, type ReadinessBand } from "../lib/engagementScore"; -import { funderBrief } from "../lib/funderBrief"; - -const bandColor: Record = { - Strong: "#15803d", - Developing: "#d97706", - Emerging: "#6b7280", -}; - -export default function EngagementReadiness({ city }: { city: City }) { - const { count, loaded } = usePledges(); - const pledges = count(city.id); - const readiness = useMemo(() => engagementReadiness(city, pledges), [city, pledges]); - - function download() { - const md = funderBrief(city, readiness); - const blob = new Blob([md], { type: "text/markdown;charset=utf-8" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = `engagement-readiness-${city.id}.md`; - document.body.appendChild(a); - a.click(); - a.remove(); - URL.revokeObjectURL(url); - } - - return ( -
-
-
-
For funders · Civic engagement readiness
-

- The civic-participation co-benefit funders already score (MDBs · IDB · philanthropy), - made visible — so “is this city engaged?” becomes something you can see and export. -

-
-
-
- {readiness.score} - / 100 -
-
- {readiness.band} -
-
prototype index
-
-
- -
- {pledges.toLocaleString()} resident commitments captured here - {!loaded && · loading…} -
- -
How the score is built
-
- {readiness.inputs.map((i) => ( -
-
- - {i.label.en} · {i.value} - - - {i.contribution}/{i.weight} - -
-
-
-
-
- ))} -
- -
- - - Prototype index over demo participation data — not an audited metric. - -
-
- ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/FunderReadout.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/FunderReadout.tsx new file mode 100644 index 0000000..423742e --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/FunderReadout.tsx @@ -0,0 +1,107 @@ +"use client"; + +import { useEffect, useState } from "react"; +import type { FunderReadout as Readout, FunderTheme } from "../lib/pledgeStore"; + +const themeColor: Record = { + Resilience: "var(--accent)", + Greening: "#15803d", + Mobility: "#2563eb", + Energy: "#d97706", +}; + +// CCRA / priority framing per theme, so a funder reads engagement against risk. +const themeRisk: Record = { + Resilience: "Floods & landslides — Very High (CCRA)", + Greening: "Heatwaves", + Mobility: "Transport — 77% of emissions", + Energy: "Residential energy & comfort", +}; + +export default function FunderReadout() { + const [r, setR] = useState(null); + + useEffect(() => { + let alive = true; + const load = () => + fetch("/api/funders?city=porto-alegre") + .then((res) => res.json()) + .then((d) => alive && setR(d.readout ?? null)) + .catch(() => {}); + load(); + const onFocus = () => load(); + window.addEventListener("focus", onFocus); + return () => { + alive = false; + window.removeEventListener("focus", onFocus); + }; + }, []); + + if (!r) return

Loading live engagement…

; + + const pct = Math.round(r.responseRate * 100); + const themeMax = Math.max(1, ...r.byTheme.map((t) => t.total)); + const hoodMax = Math.max(1, ...r.byNeighborhood.map((h) => h.count)); + + return ( +
+ {/* Headline numbers */} +
+ + + +
+ +
+ {/* By theme */} +
+
Demand by climate priority
+
+ {r.byTheme.map((t) => ( +
+
+ {t.theme} + {t.total} committed · {t.sent} acted +
+
+
+
+
{themeRisk[t.theme]}
+
+ ))} + {r.byTheme.length === 0 &&

No recorded commitments yet.

} +
+
+ + {/* By neighborhood */} +
+
Where it’s happening
+
+ {r.byNeighborhood.slice(0, 8).map((h) => ( +
+ {h.name} +
+
+
+ {h.count} +
+ ))} + {r.byNeighborhood.length === 0 &&

No neighborhoods recorded yet.

} +
+

+ Theme & neighborhood breakdowns reflect named, recorded commitments (the headline total also includes the historical baseline). +

+
+
+
+ ); +} + +function Metric({ value, label }: { value: string; label: string }) { + return ( +
+
{value}
+
{label}
+
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx deleted file mode 100644 index adc8d98..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/LocalEngagementPanel.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { portoAlegreEngagementRecommendations } from "../data/localEngagement"; - -export default function LocalEngagementPanel({ cityId }: { cityId: string }) { - if (cityId !== "porto-alegre") return null; - - const topRecommendations = portoAlegreEngagementRecommendations.slice(0, 3); - const sourceMap = new Map( - portoAlegreEngagementRecommendations - .flatMap((recommendation) => recommendation.sources) - .map((source) => [source.id, source]) - ); - const sources = Array.from(sourceMap.values()).slice(0, 8); - - return ( -
-
- Local action sources -
-

- A Porto Alegre-specific data layer connects the risk profile above to real engagement - channels residents can use now. -

- -
- {topRecommendations.map((recommendation) => ( -
-
- {recommendation.title} - - {recommendation.priority} - -
-

- {recommendation.firstActions[0]?.label} -

-
- ))} -
- -
- - View source links - -
- {sources.map((source) => ( - - {source.name} ↗ - - ))} -
-
-
- ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx deleted file mode 100644 index 26bec70..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PledgeButton.tsx +++ /dev/null @@ -1,47 +0,0 @@ -"use client"; - -import { useState } from "react"; -import type { Lang } from "../data/climateActions"; -import { usePledges } from "../lib/pledgeContext"; - -const t = { - cta: { en: "I'll act on this", es: "Me comprometo", pt: "Vou agir nisto" }, - done: { en: "Counted — thank you", es: "Registrado — gracias", pt: "Registrado — obrigado" }, - tally: { en: "resident commitments here", es: "compromisos de residentes aquí", pt: "compromissos de moradores aqui" }, -}; - -export default function PledgeButton({ cityId, lang }: { cityId: string; lang: Lang }) { - const { pledge, count } = usePledges(); - const [pledged, setPledged] = useState(false); - - function onClick() { - if (pledged) return; - setPledged(true); - pledge(cityId); - } - - return ( -
- - - {count(cityId).toLocaleString()} {t.tally[lang]} - -
- ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaEngagementMap.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaEngagementMap.tsx new file mode 100644 index 0000000..b7fbac8 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaEngagementMap.tsx @@ -0,0 +1,62 @@ +"use client"; + +import { useEffect, useState } from "react"; +import dynamic from "next/dynamic"; +import type { FunderReadout } from "../lib/pledgeStore"; +import { neighborhoodCoords } from "../data/poaNeighborhoods"; +import type { MapPoint } from "./PoaMapInner"; + +// Leaflet touches `window`, so the map must not server-render. +const PoaMapInner = dynamic(() => import("./PoaMapInner"), { + ssr: false, + loading: () => ( +
+ Loading map… +
+ ), +}); + +export default function PoaEngagementMap({ height = 360 }: { height?: number }) { + const [points, setPoints] = useState([]); + const [loaded, setLoaded] = useState(false); + + useEffect(() => { + let alive = true; + const load = () => + fetch("/api/funders?city=porto-alegre") + .then((r) => r.json()) + .then((d) => { + if (!alive) return; + const readout: FunderReadout | undefined = d.readout; + const pts: MapPoint[] = (readout?.byNeighborhood ?? []) + .map((h) => { + const c = neighborhoodCoords(h.name); + return c ? { name: h.name, lat: c[0], lng: c[1], count: h.count } : null; + }) + .filter((p): p is MapPoint => p !== null); + setPoints(pts); + setLoaded(true); + }) + .catch(() => setLoaded(true)); + load(); + const onFocus = () => load(); + window.addEventListener("focus", onFocus); + return () => { + alive = false; + window.removeEventListener("focus", onFocus); + }; + }, []); + + return ( +
+
+ +
+

+ {loaded && points.length === 0 + ? "No mappable neighborhoods recorded yet." + : "Circle size = signed commitments per neighborhood. Map © OpenStreetMap, CARTO."} +

+
+ ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaMapInner.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaMapInner.tsx new file mode 100644 index 0000000..0ed2a71 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/PoaMapInner.tsx @@ -0,0 +1,37 @@ +"use client"; + +import { CircleMarker, MapContainer, TileLayer, Tooltip } from "react-leaflet"; +import { POA_CENTER } from "../data/poaNeighborhoods"; + +export type MapPoint = { name: string; lat: number; lng: number; count: number }; + +export default function PoaMapInner({ points }: { points: MapPoint[] }) { + const max = Math.max(1, ...points.map((p) => p.count)); + + return ( + + + {points.map((p) => ( + + + {p.name} · {p.count} commitment{p.count === 1 ? "" : "s"} + + + ))} + + ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx deleted file mode 100644 index 0656912..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/TakeAction.tsx +++ /dev/null @@ -1,176 +0,0 @@ -"use client"; - -import { useMemo, useState } from "react"; -import { actionPathways } from "../data/actions"; -import type { Category } from "../data/types"; -import { categoryMeta } from "../data/types"; - -export default function TakeAction() { - const categories = useMemo(() => { - const present = new Set(); - actionPathways.forEach((a) => a.categories.forEach((c) => present.add(c))); - return Array.from(present); - }, []); - - const [cause, setCause] = useState("All"); - const shown = - cause === "All" ? actionPathways : actionPathways.filter((a) => a.categories.includes(cause)); - - return ( -
-
- setCause("All")} /> - {categories.map((c) => ( - setCause(c)} - /> - ))} -
- -
- {shown.map((a, i) => ( -
-
- - {i + 1} - - - {a.effort} effort - -
- -

{a.title}

-

- {a.what} -

- -
-
- First step -
-

{a.firstStep}

-
-
- ))} -
- - {/* Closing CTA */} -
-
-

- Start where you are. -

-

- Pick your city, see what it’s facing, and take one step this week. Citizen action - is how a city’s plan becomes real — and how funders see it’s ready. -

-
- - Find my city → - -
-
- ); -} - -function Chip({ - label, - color, - selected, - onClick, -}: { - label: string; - color: string; - selected: boolean; - onClick: () => void; -}) { - return ( - - ); -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/YourMove.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/YourMove.tsx new file mode 100644 index 0000000..f4f483a --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/components/YourMove.tsx @@ -0,0 +1,609 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import { useGenerate, type GenResult } from "../lib/useGenerate"; +import { + poaWorries, + appetiteMeta, + getMove, + whyByIntent, + type Appetite, + type WorryKey, + type Worry, +} from "../lib/poaMoves"; +import { usePledges } from "../lib/pledgeContext"; +import { + findMine, + addMine, + updateMineStatus, + receiptText, + type MyCommitment, +} from "../lib/myCommitments"; +import type { PledgeStatus } from "../lib/pledgeStore"; +import { orgsForWorry, actionMeta } from "../data/partnerOrgs"; +import Markdown from "./Markdown"; + +type MsgLang = "pt" | "en"; + +const CITY_ID = "porto-alegre"; +const CITY_NAME = "Porto Alegre"; + +export default function YourMove() { + const [worry, setWorry] = useState(null); + const [appetite, setAppetite] = useState(null); + + function reset() { + setWorry(null); + setAppetite(null); + } + + return ( +
+
+ reset()} /> + + worry && setAppetite(null)} /> + + +
+ + {!worry ? ( + + ) : !appetite ? ( + setWorry(null)} /> + ) : ( + setAppetite(null)} /> + )} +
+ ); +} + +/* ----------------------------------------------------------------- steps */ + +function WorryStep({ onPick }: { onPick: (w: WorryKey) => void }) { + return ( +
+

What worries you most in Porto Alegre?

+

Pick one. We’ll point you to a single real thing you can do about it.

+
+ {poaWorries.map((w) => ( + + ))} +
+
+ ); +} + +function AppetiteStep({ worry, onPick, onBack }: { worry: WorryKey; onPick: (a: Appetite) => void; onBack: () => void }) { + const w = poaWorries.find((x) => x.key === worry)!; + return ( +
+ +

+ {w.icon} {w.label} — how do you want to act? +

+

Be honest about your time and energy. There’s a real first move either way.

+
+ {(["quick", "deeper"] as Appetite[]).map((a) => { + const m = appetiteMeta[a]; + return ( + + ); + })} +
+
+ ); +} + +/* ------------------------------------------------------------- move card */ + +type Phase = "draft" | "signing" | "tracking"; + +function MoveCard({ worry, appetite, onRestart, onBack }: { worry: WorryKey; appetite: Appetite; onRestart: () => void; onBack: () => void }) { + const move = getMove(worry, appetite); + const w = poaWorries.find((x) => x.key === worry)!; + const { run } = useGenerate(); + const { sign, setStatus, aggregate } = usePledges(); + + const [msg, setMsg] = useState(null); + const [loading, setLoading] = useState(false); + const [lang, setLang] = useState("pt"); + const [copied, setCopied] = useState(false); + const [phase, setPhase] = useState("draft"); + const [mine, setMine] = useState(null); + const [tab, setTab] = useState<"message" | "guide">("message"); + + // If this exact move was already signed in this browser, resume the tracker. + useEffect(() => { + const existing = findMine(move.recId, move.headline); + if (existing) { + setMine(existing); + setPhase("tracking"); + } + }, [move.recId, move.headline]); + + async function generate(targetLang: MsgLang) { + setLoading(true); + const res = await run({ + task: "local_message", + action: { name: move.headline, description: move.messageSeed, type: "adaptation" }, + cityContext: { + name: CITY_NAME, + country: "Brazil", + topHazards: [`${w.label}${w.level ? ` (${w.level})` : ""}`], + topSectors: [], + localSources: [move.channelName], + facts: [w.blurb], + }, + language: targetLang, + }); + setLoading(false); + if (res) setMsg(res); + } + + // Fill the [name]/[neighborhood] placeholders once the resident has signed. + function personalize(text: string): string { + if (!mine) return text; + return text + .replace(/\[\s*(seu nome|your name|tu nombre)\s*\]/gi, mine.firstName) + .replace(/\[\s*(bairro|neighbou?rhood|barrio)\s*\]/gi, mine.neighborhood); + } + + const displayedMsg = msg ? (phase === "tracking" ? personalize(msg.content) : msg.content) : ""; + + function copy(text: string) { + const done = () => { setCopied(true); setTimeout(() => setCopied(false), 1500); }; + if (navigator.clipboard?.writeText) navigator.clipboard.writeText(text).then(done).catch(() => {}); + else done(); + } + + const agg = aggregate(CITY_ID); + + return ( +
+ + +
+ {/* Headline band */} +
+
{w.icon} {w.label} · {appetiteMeta[appetite].label}
+

{move.headline}

+
+ +
+ {/* Where + time */} +
+ Open {move.channelName} ↗ + ⏱ {move.time} + + {move.channelType === "official" ? "Official channel" : "Community group"} + +
+ + {/* Toolkit: tabbed — ready-to-send message / guide-me chat */} +
+
+
+ + +
+
+ {(["pt", "en"] as MsgLang[]).map((l) => ( + + ))} +
+
+ + {tab === "message" ? ( + <> + {!msg && !loading && ( + + )} + {loading &&
Writing…
} + {msg && !loading && ( +
+ {displayedMsg} +
+ + + + AI-written · ~{msg.gCO2e.toFixed(3)} g CO₂e{phase !== "tracking" ? " · names fill in when you sign" : ""} + +
+
+ )} + + ) : ( + + )} +
+ + {/* Why it matters (resident-facing — the awareness / demand-signal leverage) */} +
+
Why this helps
+

{whyByIntent[move.intent]}

+
+ + {/* What happens next */} +
+
What happens next
+

{move.whatNext}

+
+ + {/* Team up with organizations already doing this */} + + + {/* Commitment zone: draft CTA / sign form / tracker */} +
+ {phase === "draft" && ( +
+ + + {agg.total.toLocaleString()} residents have committed ·{" "} + {agg.sent.toLocaleString()} reported they sent it + +
+ )} + + {phase === "signing" && ( + setPhase("draft")} + onSign={async (firstName, neighborhood, email) => { + const pledge = await sign({ + cityId: CITY_ID, + actionId: move.recId, + worryLabel: w.label, + headline: move.headline, + firstName, + neighborhood, + email, + }); + const commitment: MyCommitment = { + id: pledge?.id ?? `local_${Date.now().toString(36)}`, + cityId: CITY_ID, + actionId: move.recId, + worryLabel: w.label, + headline: move.headline, + channelName: move.channelName, + channelUrl: move.channelUrl, + firstName, + neighborhood, + createdAt: pledge?.createdAt ?? new Date().toISOString(), + status: "committed", + }; + addMine(commitment); + setMine(commitment); + setPhase("tracking"); + if (!msg) generate(lang); // make sure they leave with a personalized message + }} + /> + )} + + {phase === "tracking" && mine && ( + { + updateMineStatus(mine.id, next); + setStatus(mine.id, CITY_ID, next); + setMine({ ...mine, status: next }); + }} + onCopyReceipt={() => copy(receiptText(mine))} + copied={copied} + /> + )} +
+
+
+ + +
+ ); +} + +/* --------------------------------------------------------------- guide chat */ + +type ChatMsg = { role: "user" | "assistant"; content: string }; + +function GuideChat({ worry, lang }: { worry: Worry; lang: MsgLang }) { + const { run } = useGenerate(); + const orgs = orgsForWorry(worry.key); + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(""); + const [loading, setLoading] = useState(false); + const started = useRef(false); + const scrollRef = useRef(null); + + // Everything the coach is allowed to draw on: both moves + the partner orgs. + const facts = [ + `${worry.label}: ${worry.blurb}`, + `Quick action (${worry.moves.quick.time}): ${worry.moves.quick.headline} — via ${worry.moves.quick.channelName} (${worry.moves.quick.channelUrl})`, + `Deeper action (${worry.moves.deeper.time}): ${worry.moves.deeper.headline} — via ${worry.moves.deeper.channelName} (${worry.moves.deeper.channelUrl})`, + ...orgs.map((o) => `Organization — ${o.name}: ${o.what} Ways to help: ${o.actions.map((a) => a.label).join("; ")}. ${o.url}`), + ]; + const sources = [worry.moves.quick.channelName, worry.moves.deeper.channelName, ...orgs.map((o) => o.name)]; + + async function ask(question: string, opts: { hidden?: boolean } = {}) { + const q = question.trim(); + if (!q || loading) return; + const prior = messages.map((m) => `${m.role === "user" ? "Resident" : "Guide"}: ${m.content}`).join("\n"); + if (!opts.hidden) setMessages((m) => [...m, { role: "user", content: q }]); + setInput(""); + setLoading(true); + const res = await run({ + task: "civic_guide", + action: { name: worry.label, description: `Coaching a resident to act on: ${worry.label}.`, type: "adaptation" }, + cityContext: { name: CITY_NAME, country: "Brazil", topHazards: [worry.label], topSectors: [], localSources: sources, facts }, + language: lang, + prior, + instruction: q, + }); + setLoading(false); + if (res) setMessages((m) => [...m, { role: "assistant", content: res.content }]); + } + + // Auto-build the starter toolkit the first time the tab is opened. + useEffect(() => { + if (started.current) return; + started.current = true; + ask("Give me a short starter toolkit for this — what I can do, how to do it, and why it works. Keep it skimmable.", { hidden: true }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight }); + }, [messages, loading]); + + const chips = ["Where do I start?", "What do I actually say?", "How do I get neighbors involved?", "What if I get no response?"]; + + return ( +
+
+ {messages.length === 0 && loading &&

Building your toolkit…

} + {messages.map((m, i) => + m.role === "assistant" ? ( +
+ {m.content} +
+ ) : ( +
+ {m.content} +
+ ) + )} + {loading && messages.length > 0 &&
Thinking…
} +
+ +
+ {chips.map((c) => ( + + ))} +
+ +
+ setInput(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && ask(input)} + placeholder="Ask anything — e.g. how do I run a block meeting?" + style={{ ...inputStyle, flex: 1 }} + /> + +
+

+ AI civic coach · grounded in this city’s real channels & groups · double-check details before acting. +

+
+ ); +} + +/* ----------------------------------------------------------------- team up */ + +function TeamUp({ worry }: { worry: WorryKey }) { + const orgs = orgsForWorry(worry); + return ( +
+
Team up with people already doing this
+ {orgs.length === 0 ? ( +

+ We haven’t vetted a resident-facing organization for this in Porto Alegre yet — the + official channel above is your route for now. (Know one? It belongs here.) +

+ ) : ( +
+ {orgs.map((o) => ( +
+
+ {o.name} ↗ + {o.theme} +
+

{o.what}

+
+ {o.actions.map((a) => ( + + {actionMeta[a.type].icon} {a.label} ↗ + + ))} +
+
+ ))} +
+ )} +
+ ); +} + +/* --------------------------------------------------------------- sign form */ + +function SignForm({ onSign, onCancel }: { onSign: (firstName: string, neighborhood: string, email?: string) => void; onCancel: () => void }) { + const [firstName, setFirstName] = useState(""); + const [neighborhood, setNeighborhood] = useState(""); + const [email, setEmail] = useState(""); + const valid = firstName.trim().length > 0; + + return ( +
+
Add your name to this
+

+ Signing puts your first name on Porto Alegre’s public engagement record and fills in your + message so it’s ready to send. We never publish your email. +

+
+ setFirstName(e.target.value)} placeholder="First name *" style={inputStyle} /> + setNeighborhood(e.target.value)} placeholder="Neighborhood" style={inputStyle} /> + setEmail(e.target.value)} placeholder="Email (optional — for follow-up)" type="email" style={inputStyle} /> +
+
+ + +
+
+ ); +} + +/* ----------------------------------------------------------------- tracker */ + +const STAGES: { key: PledgeStatus; label: string; cta: string }[] = [ + { key: "committed", label: "Committed", cta: "" }, + { key: "sent", label: "Sent", cta: "I've sent it" }, + { key: "responded", label: "Got a response", cta: "I got a response" }, +]; + +function Tracker({ mine, onAdvance, onCopyReceipt, copied }: { mine: MyCommitment; onAdvance: (s: PledgeStatus) => void; onCopyReceipt: () => void; copied: boolean }) { + const idx = STAGES.findIndex((s) => s.key === mine.status); + const next = STAGES[idx + 1]; + + function saveReceipt() { + try { + const blob = new Blob([receiptText(mine)], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `commitment-${mine.id}.txt`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } catch { + onCopyReceipt(); // fall back to clipboard + } + } + + return ( +
+
+ ✓ You signed this, {mine.firstName} +
+ + {/* Stage stepper */} +
+ {STAGES.map((s, i) => { + const reached = i <= idx; + return ( + + + + {reached ? "✓" : i + 1} + + {s.label} + + {i < STAGES.length - 1 && } + + ); + })} +
+ + {next ? ( + + ) : ( +
+ 🎉 Followed through, start to response. This is what a city’s engagement actually looks like. +
+ )} + + {/* Receipt */} +
+
Commitment receipt
+
+
{mine.firstName} · {mine.neighborhood}, {CITY_NAME}
+
{mine.headline}
+
via {mine.channelName}
+
+ Signed {new Date(mine.createdAt).toLocaleDateString()} · ref {mine.id} +
+
+
+ + +
+
+
+ ); +} + +/* ----------------------------------------------------------------- bits */ + +function Step({ n, label, active, done, onClick }: { n: number; label: string; active: boolean; done: boolean; onClick?: () => void }) { + const color = active ? "var(--accent)" : done ? "var(--ink)" : "var(--ink-faint)"; + return ( + + ); +} + +const Arrow = () => ; +function BackLink({ onClick }: { onClick: () => void }) { + return ; +} + +const cardBtn: React.CSSProperties = { font: "inherit", textAlign: "left", cursor: "pointer", border: "1px solid var(--line)", borderRadius: 14, background: "var(--bg)", padding: "1.1rem 1.2rem" }; +const veryHighBadge: React.CSSProperties = { fontSize: "0.64rem", fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.04em", color: "#b91c1c", background: "#fee2e2", borderRadius: 999, padding: "0.18rem 0.5rem" }; +const channelBtn: React.CSSProperties = { fontSize: "0.9rem", fontWeight: 650, color: "#fff", background: "var(--accent)", borderRadius: 10, padding: "0.55rem 1rem" }; +const timeBadge: React.CSSProperties = { fontSize: "0.8rem", fontWeight: 600, color: "var(--ink-soft)", background: "var(--bg-soft)", border: "1px solid var(--line)", borderRadius: 999, padding: "0.3rem 0.7rem" }; +const generateBtn: React.CSSProperties = { font: "inherit", fontSize: "0.9rem", fontWeight: 650, cursor: "pointer", color: "#fff", background: "var(--accent)", border: "none", borderRadius: 10, padding: "0.6rem 1.1rem" }; +const commitBtn: React.CSSProperties = { font: "inherit", fontSize: "0.9rem", fontWeight: 650, cursor: "pointer", color: "#fff", background: "var(--accent)", border: "none", borderRadius: 999, padding: "0.55rem 1.3rem" }; +const smallBtn: React.CSSProperties = { font: "inherit", fontSize: "0.78rem", fontWeight: 600, cursor: "pointer", color: "var(--accent)", background: "var(--accent-soft)", border: "none", borderRadius: 8, padding: "0.35rem 0.7rem" }; +const inputStyle: React.CSSProperties = { font: "inherit", fontSize: "0.9rem", padding: "0.55rem 0.75rem", border: "1px solid var(--line)", borderRadius: 10, background: "var(--bg)", outlineColor: "var(--accent)" }; +const tabBtn = (active: boolean): React.CSSProperties => ({ + font: "inherit", + fontSize: "0.8rem", + fontWeight: 650, + cursor: "pointer", + padding: "0.35rem 0.75rem", + borderRadius: 999, + border: "1px solid", + borderColor: active ? "var(--accent)" : "var(--line)", + background: active ? "var(--accent)" : "var(--bg)", + color: active ? "#fff" : "var(--ink-soft)", +}); + +const langBtn = (active: boolean): React.CSSProperties => ({ font: "inherit", fontSize: "0.72rem", fontWeight: 700, cursor: "pointer", padding: "0.2rem 0.5rem", borderRadius: 7, border: "1px solid", borderColor: active ? "var(--accent)" : "var(--line)", background: active ? "var(--accent)" : "var(--bg)", color: active ? "#fff" : "var(--ink-soft)" }); +const textLink: React.CSSProperties = { font: "inherit", fontSize: "0.82rem", fontWeight: 600, cursor: "pointer", color: "var(--accent)", background: "none", border: "none", padding: 0 }; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/actions.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/actions.ts deleted file mode 100644 index 9471188..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/actions.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { Category } from "./types"; - -// Universal ways a resident can plug into local climate action — the "Act" -// step. Each pathway is tagged with the causes (story categories) it serves, -// so people can filter to what they care about. - -export type ActionPathway = { - id: string; - title: string; - what: string; - firstStep: string; - effort: "Low" | "Medium"; - categories: Category[]; -}; - -export const actionPathways: ActionPathway[] = [ - { - id: "join-group", - title: "Join a local group", - what: "Find people already working on this and add your hands — almost every win below started with a handful of neighbors.", - firstStep: - "Search for a neighborhood association, climate collective, or co-op near you and show up to one meeting.", - effort: "Low", - categories: ["Greening", "Mobility", "Energy", "Resilience", "Waste", "Participation"], - }, - { - id: "show-up", - title: "Show up to a public meeting", - what: "City councils and planning sessions are open to the public — who is in the room shapes what gets prioritized.", - firstStep: - "Find the next council or planning agenda and attend (or watch) the one item you care about most.", - effort: "Low", - categories: ["Participation", "Mobility", "Resilience"], - }, - { - id: "speak-up", - title: "Speak up in a public comment", - what: "Most plans have a comment window. A few sentences on the record genuinely count toward the decision.", - firstStep: - "Look up an open consultation — transport, budget, zoning — and submit one short comment.", - effort: "Low", - categories: ["Mobility", "Participation", "AirQuality"], - }, - { - id: "vote-budget", - title: "Vote on the budget", - what: "Participatory budgeting lets residents decide how real public money is spent — and fund climate projects directly.", - firstStep: - "Check whether your city runs participatory budgeting, then propose or back a green project.", - effort: "Medium", - categories: ["Participation", "Greening"], - }, - { - id: "start-something", - title: "Start something small", - what: "A community garden, a tree-planting crew, a solar co-op — small, visible projects grow into movements.", - firstStep: "Pick one block-level project and invite three neighbors to join you this week.", - effort: "Medium", - categories: ["Greening", "Energy", "Waste"], - }, - { - id: "measure", - title: "Measure your block", - what: "Citizen science turns an invisible problem — heat, air pollution — into data nobody can ignore.", - firstStep: - "Host a low-cost air-quality or heat sensor and share the readings with your community and council.", - effort: "Medium", - categories: ["AirQuality", "Resilience"], - }, - { - id: "citizens-assembly", - title: "Call for a citizens' assembly", - what: "Randomly selected residents, given time and expert input, can shape climate policy directly — as in Paris.", - firstStep: - "Ask your council to convene a citizens' assembly on climate — or join one if it already exists.", - effort: "Medium", - categories: ["Participation"], - }, -]; diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts index be412ce..455d27e 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/localSources.ts @@ -7,7 +7,7 @@ import type { LocalSource } from "./localEngagement"; import { portoAlegreEngagementRecommendations } from "./localEngagement"; -// Flatten + dedupe POA sources by id (same logic as LocalEngagementPanel). +// Flatten + dedupe POA sources by id. const poaSources: LocalSource[] = Array.from( new Map( portoAlegreEngagementRecommendations.flatMap((r) => r.sources).map((s) => [s.id, s]) diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/partnerOrgs.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/partnerOrgs.ts new file mode 100644 index 0000000..bedbbb2 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/partnerOrgs.ts @@ -0,0 +1,115 @@ +// Real Porto Alegre / Rio Grande do Sul non-profits and volunteer organizations a +// resident can plug into — beyond contacting an official channel. Each org offers +// concrete ways to act: volunteer, attend, back a campaign, or donate. Every URL +// was web-verified (the OEF knowledge base was unreachable when this was built; +// these should be cross-checked there later). Energy has no vetted resident-facing +// org yet — handled with an honest empty state in the UI rather than a fabrication. + +import type { WorryKey } from "../lib/poaMoves"; + +export type OrgActionType = "volunteer" | "attend" | "campaign" | "donate"; +export type OrgTheme = "Resilience" | "Greening" | "Mobility" | "Energy"; + +export type OrgAction = { type: OrgActionType; label: string; url: string }; + +export type PartnerOrg = { + id: string; + name: string; + theme: OrgTheme; + worries: WorryKey[]; + what: string; // one line — what they do + url: string; // homepage + actions: OrgAction[]; +}; + +export const actionMeta: Record = { + volunteer: { label: "Volunteer", icon: "🙋" }, + attend: { label: "Attend", icon: "📅" }, + campaign: { label: "Back a campaign", icon: "📣" }, + donate: { label: "Donate", icon: "💛" }, +}; + +export const partnerOrgs: PartnerOrg[] = [ + // ---- Resilience: flooding + landslides ---- + { + id: "parceiros-voluntarios", + name: "Parceiros Voluntários", + theme: "Resilience", + worries: ["flooding", "landslides"], + what: "Connects residents to volunteer with civil-society groups; its “Construir Juntos” program rebuilds organizations and schools hit by the 2024 floods.", + url: "https://www.parceirosvoluntarios.org.br/", + actions: [ + { type: "volunteer", label: "Become a volunteer", url: "https://parceirosvoluntarios.org.br/voluntario/" }, + { type: "donate", label: "Support their work", url: "https://parceirosvoluntarios.org.br/sojuntos/" }, + ], + }, + { + id: "brazilfoundation-rs", + name: "BrazilFoundation — Rio Grande do Sul", + theme: "Resilience", + worries: ["flooding", "landslides"], + what: "Mobilizes funds for the recovery and resilience of Rio Grande do Sul after its largest-ever flood.", + url: "https://brazilfoundation.org/en/help-rio-grande-do-sul/", + actions: [{ type: "donate", label: "Donate to RS recovery", url: "https://brazilfoundation.org/en/donate-now" }], + }, + + // ---- Greening: heat & shade ---- + { + id: "agapan", + name: "AGAPAN", + theme: "Greening", + worries: ["heat"], + what: "Rio Grande do Sul’s oldest environmental association (1971); runs advocacy and campaigns to protect and expand Porto Alegre’s trees and green space.", + url: "https://www.agapan.org.br/", + actions: [ + { type: "volunteer", label: "Become a member", url: "https://www.agapan.org.br/" }, + { type: "campaign", label: "Back their tree campaigns", url: "https://www.agapan.org.br/" }, + { type: "donate", label: "Donate", url: "https://www.agapan.org.br/" }, + ], + }, + { + id: "arboristas-urbanos", + name: "Arboristas Urbanos", + theme: "Greening", + worries: ["heat"], + what: "A Porto Alegre collective (since 2011) that plants and cares for urban trees through community plantings, a nursery, and education.", + url: "https://www.atados.com.br/ong/penha-verde-1", + actions: [ + { type: "volunteer", label: "Join a planting mutirão", url: "https://www.atados.com.br/ong/penha-verde-1" }, + { type: "attend", label: "Join their actions", url: "https://www.atados.com.br/ong/penha-verde-1" }, + ], + }, + + // ---- Mobility ---- + { + id: "bike-anjo-poa", + name: "Bike Anjo Porto Alegre", + theme: "Mobility", + worries: ["mobility"], + what: "Volunteer urban cyclists who help new riders pedal safely and push for safer streets.", + url: "https://bicianjo.wordpress.com/", + actions: [ + { type: "volunteer", label: "Ride with a Bike Angel", url: "https://bicianjo.wordpress.com/chame-um-bici-anjo/" }, + ], + }, + { + id: "mobicidade", + name: "Mobicidade", + theme: "Mobility", + worries: ["mobility"], + what: "Porto Alegre’s bicycle-mobility association — volunteer-run advocacy and research for safer cycling and active transport.", + url: "https://www.mobicidade.org/", + actions: [ + { type: "campaign", label: "Back their advocacy", url: "https://www.mobicidade.org/" }, + { type: "attend", label: "Get involved", url: "https://www.mobicidade.org/" }, + ], + }, +]; + +export function orgsForWorry(worry: WorryKey): PartnerOrg[] { + return partnerOrgs.filter((o) => o.worries.includes(worry)); +} + +export function orgsByTheme(theme: OrgTheme): PartnerOrg[] { + return partnerOrgs.filter((o) => o.theme === theme); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/poaNeighborhoods.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/poaNeighborhoods.ts new file mode 100644 index 0000000..92e7a93 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/data/poaNeighborhoods.ts @@ -0,0 +1,44 @@ +// Approximate coordinates for Porto Alegre neighborhoods, used to plot where +// engagement is happening on the map. Names are matched accent-insensitively; +// neighborhoods we don't have coordinates for are simply not plotted (they still +// appear in the bar breakdown). + +export const POA_CENTER: [number, number] = [-30.043, -51.2]; + +const COORDS: Record = { + "centro historico": [-30.0277, -51.2287], + "cidade baixa": [-30.0436, -51.2225], + "bom fim": [-30.033, -51.208], + "menino deus": [-30.056, -51.223], + "moinhos de vento": [-30.025, -51.205], + petropolis: [-30.044, -51.185], + partenon: [-30.056, -51.17], + azenha: [-30.051, -51.215], + santana: [-30.049, -51.205], + "santa cecilia": [-30.045, -51.213], + floresta: [-30.015, -51.212], + "sao geraldo": [-30.008, -51.22], + navegantes: [-29.999, -51.21], + sarandi: [-29.976, -51.123], + restinga: [-30.156, -51.145], + "lomba do pinheiro": [-30.11, -51.11], + cavalhada: [-30.095, -51.235], + ipanema: [-30.124, -51.236], + tristeza: [-30.11, -51.248], + "rubem berta": [-29.99, -51.15], + agronomia: [-30.07, -51.12], + gloria: [-30.09, -51.21], + "vila nova": [-30.11, -51.18], + cristal: [-30.08, -51.235], +}; + +// Strip combining diacritics (U+0300–U+036F) without embedding them in source. +const DIACRITICS = new RegExp("[\\u0300-\\u036f]", "g"); + +function norm(s: string): string { + return s.toLowerCase().normalize("NFD").replace(DIACRITICS, "").trim(); +} + +export function neighborhoodCoords(name: string): [number, number] | null { + return COORDS[norm(name)] ?? null; +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/funders/page.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/funders/page.tsx new file mode 100644 index 0000000..a8c6d61 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/funders/page.tsx @@ -0,0 +1,151 @@ +import Link from "next/link"; +import FunderReadout from "../components/FunderReadout"; +import PoaEngagementMap from "../components/PoaEngagementMap"; +import { partnerOrgs, type OrgTheme } from "../data/partnerOrgs"; + +export const metadata = { + title: "For funders — Civic Climate Action", +}; + +const thesis = [ + { + h: "It raises the co-benefit score", + p: "CityCatalyst's HIAP scores stakeholder engagement as a co-benefit (−2..+2). Demonstrated community demand lifts a project's score — the difference between fundable and shelved.", + }, + { + h: "It de-risks disbursement", + p: "The top reason urban climate projects stall is local resistance or low uptake. Named residents demanding and acting on a specific intervention is the evidence a credit committee needs to release capital.", + }, + { + h: "It satisfies the readiness gate", + p: "Many funds require documented stakeholder consultation before approval. This produces that record continuously — timestamped, sourced, by neighborhood — instead of a one-off survey.", + }, +]; + +const unlock: { theme: OrgTheme; line: string }[] = [ + { theme: "Resilience", line: "Standing demand + follow-through across neighborhoods is the engagement co-benefit and demand evidence for drainage & slope-stabilization capital (e.g. POA+Drena Resiliente, MDB project-prep)." }, + { theme: "Greening", line: "Documented demand for shade and trees supports nature-based-solution co-financing — and engaged residents are the maintenance base funders worry about." }, + { theme: "Mobility", line: "Active-mobility demand plus a volunteer base de-risks safe-streets and cycling-infrastructure investment." }, + { theme: "Energy", line: "Household-efficiency demand, especially from low-income, heat-exposed homes, supports retrofit-program funding and equity co-benefit scoring." }, +]; + +const themeColor: Record = { + Resilience: "var(--accent)", + Greening: "#15803d", + Mobility: "#2563eb", + Energy: "#d97706", +}; + +export default function FundersPage() { + const themes: OrgTheme[] = ["Resilience", "Greening", "Mobility", "Energy"]; + + return ( + <> + {/* Headline */} +
+
+
For funders · MDBs · philanthropy
+

+ Engagement you can take to a credit committee. +

+

+ Civic participation is a co-benefit funders already score. Porto Alegre residents are + signing specific, sourced commitments to real climate priorities — here is what that is, + and why it moves money. +

+
+
+ + {/* Why it unlocks money */} +
+
+
Why it unlocks money
+

+ Engagement isn’t soft — it’s a scored, gating input +

+
+ {thesis.map((t, i) => ( +
+
{i + 1}
+

{t.h}

+

{t.p}

+
+ ))} +
+
+
+ + {/* Where it's happening (live) */} +
+
+
Live · Porto Alegre
+

+ Where engagement is happening, right now +

+
+ + +
+
+
+ + {/* Who can deliver */} +
+
+
Who can deliver
+

+ Credible local implementers, already mobilizing +

+

+ Funders deploy through local organizations. These are real Porto Alegre / Rio Grande do + Sul groups residents are being routed to — the absorptive capacity on the ground. +

+
+ {partnerOrgs.map((o) => ( +
+
{o.theme}
+ {o.name} ↗ +

{o.what}

+
+ ))} +
+
+
+ + {/* What this could unlock */} +
+
+
What this could unlock
+

+ From demand signal to capital +

+
+ {unlock.map((u) => ( +
+ {u.theme} + {u.line} +
+ ))} +
+
+
+ + {/* Caveats */} +
+
+
Honest about scope
+

+ This is a hackday pilot scoped to Porto Alegre. Engagement figures include a clearly + labelled demo baseline plus live signed commitments; theme and neighborhood breakdowns + reflect the named records. Risk and emissions data are live from CityCatalyst; partner + organizations are real and linked. The model here is the point: turn civic participation + into a continuous, sourced, fundable signal. +

+

+ ← Back to the resident view +

+
+
+ + ); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css index da2ea3f..c65e9f5 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/globals.css @@ -103,8 +103,9 @@ a:hover { @media (max-width: 760px) { .explorer-top, - .lab-grid { - grid-template-columns: 1fr; + .lab-grid, + .funder-where { + grid-template-columns: 1fr !important; } } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx index bf361ad..0940222 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/layout.tsx @@ -1,4 +1,5 @@ import type { Metadata } from "next"; +import Link from "next/link"; import "./globals.css"; import { CarbonProvider } from "./lib/carbonContext"; import { PledgeProvider } from "./lib/pledgeContext"; @@ -7,7 +8,7 @@ import CarbonCounter from "./components/CarbonCounter"; export const metadata: Metadata = { title: "Civic Climate Action — Your City, Your Move", description: - "A citizen-facing companion to CityCatalyst. Discover what your city is doing on climate, learn what it means, and find concrete ways to engage.", + "A citizen-facing companion to CityCatalyst. See what your city is up against on climate, and get one real thing you can do about it.", }; export default function RootLayout({ children }: { children: React.ReactNode }) { @@ -16,6 +17,24 @@ export default function RootLayout({ children }: { children: React.ReactNode }) + {children} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts deleted file mode 100644 index 5de28ad..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/cityFacts.ts +++ /dev/null @@ -1,100 +0,0 @@ -// Plain factual lines derived from a city's real data, in the user's language. -// These are passed to the LLM as the ONLY numbers it may use, so the generated -// content stays grounded and honest. - -import type { City, RiskLevel } from "../data/types"; -import type { HazardKey, Lang } from "../data/climateActions"; -import { normalizeHazard, normalizeSector } from "./hazardNormalize"; - -const LEVEL_ORDER: Record = { "Very High": 4, High: 3, Medium: 2, Low: 1 }; - -const LEVEL_WORD: Record> = { - "Very High": { en: "Very High", es: "Muy alto", pt: "Muito alto" }, - High: { en: "High", es: "Alto", pt: "Alto" }, - Medium: { en: "Medium", es: "Medio", pt: "Médio" }, - Low: { en: "Low", es: "Bajo", pt: "Baixo" }, -}; - -const HAZARD_WORD: Record> = { - heatwaves: { en: "Heatwaves", es: "Las olas de calor", pt: "As ondas de calor" }, - landslides: { en: "Landslides", es: "Los deslizamientos", pt: "Os deslizamentos" }, - floods: { en: "Flooding", es: "Las inundaciones", pt: "As inundações" }, - droughts: { en: "Drought", es: "La sequía", pt: "A seca" }, - diseases: { en: "Climate-related disease", es: "Las enfermedades", pt: "As doenças" }, - "sea-level-rise": { en: "Sea-level rise", es: "El aumento del nivel del mar", pt: "A elevação do nível do mar" }, - storms: { en: "Storms", es: "Las tormentas", pt: "As tempestades" }, - wildfires: { en: "Wildfire", es: "Los incendios", pt: "Os incêndios" }, -}; - -const SECTOR_WORD: Record> = { - transportation: { en: "Transportation", es: "El transporte", pt: "O transporte" }, - stationary_energy: { en: "Energy use in buildings", es: "La energía en edificios", pt: "A energia em edifícios" }, - waste: { en: "Waste", es: "Los residuos", pt: "Os resíduos" }, - ippu: { en: "Industry", es: "La industria", pt: "A indústria" }, - afolu: { en: "Land use", es: "El uso del suelo", pt: "O uso do solo" }, -}; - -function formatCo2e(t: number, lang: Lang): string { - const unit = (n: number, u: string) => - `${n.toLocaleString(lang === "en" ? "en-US" : lang === "es" ? "es" : "pt-BR")} ${u}`; - if (t >= 1_000_000) return unit(Number((t / 1_000_000).toFixed(1)), "Mt"); - if (t >= 1_000) return unit(Math.round(t / 1_000), "kt"); - return unit(Math.round(t), "t"); -} - -export function cityFacts(city: City, lang: Lang): string[] { - const facts: string[] = []; - - // Top distinct hazards (highest severity), up to 2. - const byKey = new Map(); - for (const h of city.risk?.topHazards ?? []) { - for (const k of normalizeHazard(h.hazard)) { - const prev = byKey.get(k); - if (!prev || LEVEL_ORDER[h.level] > LEVEL_ORDER[prev]) byKey.set(k, h.level); - } - } - for (const [key, level] of [...byKey.entries()].slice(0, 2)) { - const hz = HAZARD_WORD[key][lang]; - const lv = LEVEL_WORD[level][lang]; - if (lang === "es") facts.push(`${hz} tienen un riesgo climático ${lv} en ${city.name}.`); - else if (lang === "pt") facts.push(`${hz} têm risco climático ${lv} em ${city.name}.`); - else facts.push(`${hz} are rated ${lv} climate risk in ${city.name}.`); - } - - // Dominant emitting sector. When the inventory is partial (emissions.note set), - // the share is known to be overstated, so we DON'T present it as a precise fact — - // we frame it qualitatively and attach the caveat, so the LLM can't cite a bare %. - const e = city.emissions; - if (e?.sectors?.length) { - const top = [...e.sectors].sort((a, b) => b.sharePct - a.sharePct)[0]; - const key = normalizeSector(top.sector); - const word = key ? SECTOR_WORD[key][lang] : top.sector; - const pct = Math.round(top.sharePct); - if (e.note) { - // Partial inventory → qualitative only, no precise share. - if (lang === "es") facts.push(`${word} es la mayor fuente de emisiones medidas de ${city.name} (inventario parcial; la proporción está probablemente sobrestimada).`); - else if (lang === "pt") facts.push(`${word} é a maior fonte de emissões medidas de ${city.name} (inventário parcial; a proporção está provavelmente superestimada).`); - else facts.push(`${word} is the largest measured emissions source in ${city.name} (partial inventory; this share is likely overstated).`); - } else { - if (lang === "es") facts.push(`${word} es cerca del ${pct}% de las emisiones medidas de ${city.name}.`); - else if (lang === "pt") facts.push(`${word} é cerca de ${pct}% das emissões medidas de ${city.name}.`); - else facts.push(`${word} is about ${pct}% of ${city.name}'s measured emissions.`); - } - } else if (e?.topSector) { - const key = normalizeSector(e.topSector); - const word = key ? SECTOR_WORD[key][lang] : e.topSector; - if (lang === "es") facts.push(`${word} es la mayor fuente de emisiones de ${city.name}.`); - else if (lang === "pt") facts.push(`${word} é a maior fonte de emissões de ${city.name}.`); - else facts.push(`${word} is the largest emissions source in ${city.name}.`); - } - - // City total emissions. - if (e?.totalTonnesCo2e) { - const v = formatCo2e(e.totalTonnesCo2e, lang); - if (lang === "es") facts.push(`Las emisiones medidas de ${city.name} son de unas ${v} CO₂e al año.`); - else if (lang === "pt") facts.push(`As emissões medidas de ${city.name} são cerca de ${v} CO₂e por ano.`); - else facts.push(`${city.name}'s measured emissions are about ${v} CO₂e per year.`); - } - - return facts; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts deleted file mode 100644 index 94ad04e..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/engagementScore.ts +++ /dev/null @@ -1,102 +0,0 @@ -// Civic Engagement Readiness — a transparent, per-city prototype index that turns -// a funder's hardest question ("is this city engaged?") into a visible, sourced -// number. NO black box: every input and its point contribution is exposed. -// -// Inputs (all already in the repo): -// - Resident commitments (pledges, captured via /api/pledge) -// - Engagement co-benefit of the city's top actions (HIAP stakeholder_engagement, -// the signal funders already score, −2..+2) -// - Local civic infrastructure (curated official/community channels) -// - Proven precedent (matched real success stories) - -import type { City } from "../data/types"; -import type { Lang as L } from "../data/climateActions"; -import { climateActions } from "../data/climateActions"; -import { prioritizeActions } from "./prioritize"; -import { localSourcesByCity } from "../data/localSources"; -import { matchStories } from "./matchStories"; -import { stories } from "../data/stories"; - -export type ReadinessBand = "Emerging" | "Developing" | "Strong"; - -export type ReadinessInput = { - label: Record; - value: string; - contribution: number; // points out of `weight` - weight: number; -}; - -export type Readiness = { - score: number; // 0-100 - band: ReadinessBand; - inputs: ReadinessInput[]; - pledgeCount: number; - coBenefitAvg: number; // −2..+2 -}; - -const WEIGHTS = { pledges: 40, coBenefit: 25, infra: 20, precedent: 15 }; - -const clamp01 = (n: number) => Math.max(0, Math.min(1, n)); -const mean = (xs: number[]) => (xs.length ? xs.reduce((a, b) => a + b, 0) / xs.length : 0); - -export function engagementReadiness(city: City, pledgeCount: number): Readiness { - const ranked = prioritizeActions(city, climateActions, { topN: 6 }); - - // 1. Participation — log-scaled (≈200 pledges saturates). - const pledgeScore = clamp01(Math.log10(pledgeCount + 1) / Math.log10(201)); - - // 2. Engagement co-benefit of the prioritized actions (−2..+2 → 0..1). - const seVals = ranked.map((r) => r.action.coBenefits?.stakeholder_engagement ?? 0); - const coBenefitAvg = mean(seVals); - const coBenefitScore = clamp01((coBenefitAvg + 2) / 4); - - // 3. Local civic infrastructure (official weighted higher). - const srcs = localSourcesByCity[city.id] ?? []; - const official = srcs.filter((s) => s.type === "official").length; - const community = srcs.length - official; - const infraScore = clamp01((official + community * 0.5) / 6); - - // 4. Proven precedent — distinct success stories matched across the top actions. - const matched = new Set(); - for (const r of ranked.slice(0, 3)) { - for (const s of matchStories(r.action, stories)) matched.add(s.id); - } - const precedent = matched.size; - const precedentScore = clamp01(precedent / 4); - - const inputs: ReadinessInput[] = [ - { - label: { en: "Resident commitments", es: "Compromisos de residentes", pt: "Compromissos de moradores" }, - value: `${pledgeCount}`, - contribution: Math.round(WEIGHTS.pledges * pledgeScore), - weight: WEIGHTS.pledges, - }, - { - label: { - en: "Engagement co-benefit of top actions", - es: "Co-beneficio de participación de las acciones", - pt: "Co-benefício de participação das ações", - }, - value: `${coBenefitAvg >= 0 ? "+" : ""}${coBenefitAvg.toFixed(1)} / +2`, - contribution: Math.round(WEIGHTS.coBenefit * coBenefitScore), - weight: WEIGHTS.coBenefit, - }, - { - label: { en: "Local civic channels", es: "Canales cívicos locales", pt: "Canais cívicos locais" }, - value: `${official} official · ${community} community`, - contribution: Math.round(WEIGHTS.infra * infraScore), - weight: WEIGHTS.infra, - }, - { - label: { en: "Proven precedent", es: "Precedentes probados", pt: "Precedentes comprovados" }, - value: `${precedent} ${precedent === 1 ? "story" : "stories"}`, - contribution: Math.round(WEIGHTS.precedent * precedentScore), - weight: WEIGHTS.precedent, - }, - ]; - - const score = inputs.reduce((a, i) => a + i.contribution, 0); - const band: ReadinessBand = score >= 66 ? "Strong" : score >= 40 ? "Developing" : "Emerging"; - - return { score, band, inputs, pledgeCount, coBenefitAvg }; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts deleted file mode 100644 index 33928d7..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/funderBrief.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Assemble a one-page "Civic Engagement Readiness" brief for funders, purely -// from real app data + the transparent readiness score. STATIC (no LLM) so this -// headline funder artifact carries zero fabrication risk. English (the working -// language for MDB / IDB / philanthropy partners). - -import type { City } from "../data/types"; -import { climateActions } from "../data/climateActions"; -import { prioritizeActions } from "./prioritize"; -import { localSourcesByCity } from "../data/localSources"; -import { matchStories } from "./matchStories"; -import { stories } from "../data/stories"; -import type { Readiness } from "./engagementScore"; - -export function funderBrief(city: City, readiness: Readiness): string { - const ranked = prioritizeActions(city, climateActions, { topN: 6 }); - const topActions = ranked.slice(0, 3); - - const matched = new Map(); - for (const r of topActions) for (const s of matchStories(r.action, stories)) matched.set(s.id, s); - - const srcs = localSourcesByCity[city.id] ?? []; - - const rows = readiness.inputs - .map((i) => `| ${i.label.en} | ${i.value} | ${i.contribution} / ${i.weight} |`) - .join("\n"); - - const actionLines = topActions - .map((r) => { - const se = r.action.coBenefits?.stakeholder_engagement ?? 0; - return `- **${r.action.name.en}** — engagement co-benefit ${se >= 0 ? "+" : ""}${se} / +2`; - }) - .join("\n"); - - const channelLines = srcs.length - ? srcs.map((s) => `- ${s.name} (${s.type}) — ${s.url}`).join("\n") - : "- (none curated yet)"; - - const storyLines = matched.size - ? [...matched.values()].map((s) => `- ${s.title} — ${s.city}, ${s.country} (${s.sourceName})`).join("\n") - : "- (no close precedent matched)"; - - return `# Civic Engagement Readiness — ${city.name}, ${city.country} - -**Readiness: ${readiness.score} / 100 (${readiness.band})** · prototype index - -> A transparent proxy for how ready ${city.name} is for citizen-backed climate action — the -> civic-participation co-benefit that MDBs, the IDB and philanthropy already score (HIAP rates -> stakeholder engagement on a −2..+2 scale). This operationalizes "is this city engaged?" into -> something visible and exportable that de-risks city climate projects and helps capital flow. - -## How the score is built (no black box) - -| Signal | Value | Points | -|---|---|---| -${rows} - -## Top recommended actions (with engagement co-benefit) - -${actionLines} - -## Local civic channels residents can use - -${channelLines} - -## Proven precedent (real success stories) - -${storyLines} - -## Caveats - -- Prototype index over **demo participation data** — not an audited metric. -- Brazilian emissions come from a partial territorial inventory; sector shares are conservative and - some are overstated. Climate-risk levels are from CityCatalyst's risk assessment. -- Generated for OEF Hackday 26Q2 by the Civic Climate Action module. -`; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts deleted file mode 100644 index 9f04a31..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/hazardNormalize.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Map a city's hazard / sector strings onto CityCatalyst's canonical keys. -// -// Hazard names are bimodal: the 4 CityCatalyst (Brazilian) hero cities use -// canonical names ("Heatwaves", "Landslides", "Floods", "Diseases") that hit the -// keyword rules cleanly; the 11 external cities use prose ("Storm surge & -// sea-level rise", "Water shortage & drought") that may map to several keys. - -import type { HazardKey, GhgSectorKey } from "../data/climateActions"; - -// Ordered keyword → hazard rules. A single input may match several. -const HAZARD_RULES: [RegExp, HazardKey][] = [ - [/drought|water shortage|water scarcity|water stress/, "droughts"], - [/heat|overheat/, "heatwaves"], - [/sea[-\s]?level|coastal|storm surge|tidal/, "sea-level-rise"], - [/flood|cloudburst|rain|stormwater|deluge|inundation/, "floods"], - [/landslide|mudslide|mudflow/, "landslides"], - [/storm|cyclone|hurricane|wind/, "storms"], - [/wildfire|forest fire|bushfire|dieback|fire/, "wildfires"], - [/disease|vector|epidemic|dengue|malaria/, "diseases"], -]; - -export function normalizeHazard(input: string): HazardKey[] { - const s = input.toLowerCase(); - const out = new Set(); - for (const [re, key] of HAZARD_RULES) { - if (re.test(s)) out.add(key); - } - return [...out]; -} - -const SECTOR_RULES: [RegExp, GhgSectorKey][] = [ - [/transport|mobility|road|vehicle/, "transportation"], - [/stationary|energy|building|electric|power|heat\b/, "stationary_energy"], - [/waste|landfill|wastewater|sanitation/, "waste"], - [/ippu|industrial process|industry|cement|manufactur/, "ippu"], - [/afolu|land use|land-use|forest|agricultur|livestock/, "afolu"], -]; - -export function normalizeSector(input: string): GhgSectorKey | null { - const s = input.toLowerCase(); - for (const [re, key] of SECTOR_RULES) { - if (re.test(s)) return key; - } - return null; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts deleted file mode 100644 index 08f7e0b..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/matchStories.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Match real success stories to a chosen action (data-driven, no LLM) for the -// "Examples" lens — so a resident sees where this kind of action already worked. - -import type { ClimateAction } from "../data/climateActions"; -import type { Story, Category } from "../data/types"; - -function categoriesFor(action: ClimateAction): Set { - const out = new Set(); - for (const s of action.sectors) { - if (/transport|mobil|road/.test(s)) out.add("Mobility"); - if (/energy/.test(s)) out.add("Energy"); - if (/waste/.test(s)) out.add("Waste"); - if (/afolu|land|forest|biodiv|green/.test(s)) out.add("Greening"); - if (/water|flood|geo|disaster|resilien/.test(s)) out.add("Resilience"); - if (/air|health/.test(s)) { - out.add("AirQuality"); - out.add("Resilience"); - } - } - for (const h of action.hazards) { - if (h === "heatwaves" || h === "wildfires") { - out.add("Greening"); - out.add("Resilience"); - } else { - out.add("Resilience"); // floods, landslides, storms, sea-level-rise, droughts, diseases - } - } - if (out.size === 0) out.add(action.actionType === "adaptation" ? "Resilience" : "Participation"); - return out; -} - -export function matchStories(action: ClimateAction, stories: Story[], limit = 4): Story[] { - const cats = categoriesFor(action); - const primary = stories.filter((s) => cats.has(s.category)); - // Always offer at least one "how change happened" participation example. - const participation = stories.filter( - (s) => s.category === "Participation" && !primary.includes(s) - ); - const seen = new Set(); - const out: Story[] = []; - for (const s of [...primary, ...participation]) { - if (out.length >= limit) break; - if (seen.has(s.id)) continue; - seen.add(s.id); - out.push(s); - } - return out; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/myCommitments.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/myCommitments.ts new file mode 100644 index 0000000..41e2df5 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/myCommitments.ts @@ -0,0 +1,90 @@ +// Client-side record of the commitments THIS browser has made. Lets the tracker +// and receipt survive reloads without auth, and lets a move card detect that the +// resident already signed it. The server holds the aggregate + public wall; this +// holds "mine". + +import type { PledgeStatus } from "./pledgeStore"; + +export type MyCommitment = { + id: string; + cityId: string; + actionId: string; + worryLabel: string; + headline: string; + channelName: string; + channelUrl: string; + firstName: string; + neighborhood: string; + createdAt: string; + status: PledgeStatus; +}; + +const KEY = "civic-commitments-v1"; + +function read(): MyCommitment[] { + if (typeof window === "undefined") return []; + try { + const raw = window.localStorage.getItem(KEY); + const parsed = raw ? JSON.parse(raw) : []; + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } +} + +function write(list: MyCommitment[]): void { + try { + window.localStorage.setItem(KEY, JSON.stringify(list)); + } catch { + /* storage unavailable / full — tracker just won't persist this session */ + } +} + +export function getMyCommitments(): MyCommitment[] { + return read(); +} + +// Identify a commitment by the move it belongs to (action + appetite differ by +// headline, so we key on actionId + headline). +export function findMine(actionId: string, headline: string): MyCommitment | undefined { + return read().find((c) => c.actionId === actionId && c.headline === headline); +} + +export function addMine(c: MyCommitment): void { + const list = read().filter((x) => x.id !== c.id); + list.push(c); + write(list); +} + +export function updateMineStatus(id: string, status: PledgeStatus): void { + write(read().map((c) => (c.id === id ? { ...c, status } : c))); +} + +const STATUS_LABEL: Record = { + committed: "Committed", + sent: "Sent", + responded: "Got a response", +}; + +export function receiptText(c: MyCommitment): string { + const date = new Date(c.createdAt).toLocaleString(); + return [ + "CIVIC CLIMATE ACTION — COMMITMENT RECEIPT", + "==========================================", + "", + `Resident: ${c.firstName} · ${c.neighborhood}`, + `City: Porto Alegre`, + `Concern: ${c.worryLabel}`, + "", + `Commitment: ${c.headline}`, + `Channel: ${c.channelName}`, + ` ${c.channelUrl}`, + "", + `Signed: ${date}`, + `Status: ${STATUS_LABEL[c.status]}`, + `Reference: ${c.id}`, + "", + "This is a personal record of a civic commitment. Follow through via the", + "channel above — your action is part of Porto Alegre's public engagement record.", + ].join("\n"); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx index 851b5ab..aae17b4 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeContext.tsx @@ -1,45 +1,79 @@ "use client"; import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react"; +import type { CityAggregate, PublicPledge, PledgeStatus } from "./pledgeStore"; // type-only + +const emptyAggregate = (): CityAggregate => ({ total: 0, sent: 0, responded: 0, actions: [] }); + +export type SignInput = { + cityId: string; + actionId: string; + worryLabel: string; + headline: string; + firstName: string; + neighborhood: string; + email?: string; +}; type Ctx = { - count: (cityId: string) => number; - pledge: (cityId: string) => Promise; + aggregate: (cityId: string) => CityAggregate; + sign: (input: SignInput) => Promise; + setStatus: (id: string, cityId: string, status: PledgeStatus) => Promise; loaded: boolean; }; const PledgeCtx = createContext(null); export function PledgeProvider({ children }: { children: React.ReactNode }) { - const [counts, setCounts] = useState>({}); + const [cities, setCities] = useState>({}); const [loaded, setLoaded] = useState(false); useEffect(() => { fetch("/api/metrics") .then((r) => r.json()) - .then((d) => setCounts(d.counts ?? {})) + .then((d) => setCities(d.cities ?? {})) .catch(() => {}) .finally(() => setLoaded(true)); }, []); - const pledge = useCallback(async (cityId: string) => { - setCounts((c) => ({ ...c, [cityId]: (c[cityId] ?? 0) + 1 })); // optimistic + const sign = useCallback(async (input: SignInput): Promise => { + // optimistic bump + setCities((c) => { + const m = c[input.cityId] ?? emptyAggregate(); + const actions = m.actions.includes(input.actionId) ? m.actions : [...m.actions, input.actionId]; + return { ...c, [input.cityId]: { ...m, total: m.total + 1, actions } }; + }); try { const res = await fetch("/api/pledge", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ cityId }), + body: JSON.stringify(input), + }); + const d = await res.json(); + if (d?.aggregate) setCities((c) => ({ ...c, [input.cityId]: d.aggregate })); + return d?.pledge ?? null; + } catch { + return null; // keep optimistic value + } + }, []); + + const setStatus = useCallback(async (id: string, cityId: string, status: PledgeStatus) => { + try { + const res = await fetch("/api/pledge", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ id, status }), }); const d = await res.json(); - if (typeof d.count === "number") setCounts((c) => ({ ...c, [cityId]: d.count })); + if (d?.aggregate) setCities((c) => ({ ...c, [cityId]: d.aggregate })); } catch { - /* keep optimistic value */ + /* server unreachable — local tracker still advances */ } }, []); - const count = useCallback((cityId: string) => counts[cityId] ?? 0, [counts]); + const aggregate = useCallback((cityId: string) => cities[cityId] ?? emptyAggregate(), [cities]); - const value = useMemo(() => ({ count, pledge, loaded }), [count, pledge, loaded]); + const value = useMemo(() => ({ aggregate, sign, setStatus, loaded }), [aggregate, sign, setStatus, loaded]); return {children}; } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts index 4a5654f..8acc3f8 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/pledgeStore.ts @@ -1,57 +1,265 @@ -// Server-only participation store. Captures resident "I'll act on this" pledges -// per city so the funder-facing engagement metric reflects real, aggregated -// commitment (not per-browser localStorage). +// Server-only participation store. A commitment is a SIGNATURE: a named resident +// (first name + neighborhood, optional email) pledging to take a specific real +// action, then tracking it through to done. This is an honest, weighty engagement +// signal — a public record of who committed and who followed through — not a +// throwaway click. // -// This is a DEMO store: a JSON file under the app root, single-process, seeded -// with a small clearly-labelled baseline. Production path = a real database. +// DEMO store: a JSON file under the app root, single-process, seeded with a small +// clearly-labelled baseline. Production path = a real database. import fs from "node:fs"; import path from "node:path"; const FILE = path.join(process.cwd(), ".data", "pledges.json"); -// Clearly-labelled demo baseline so the metric isn't empty on first run. -const SEED: Record = { - "sao-paulo": 128, - "porto-alegre": 86, - "curitiba": 41, - "rio-de-janeiro": 73, +export type PledgeStatus = "committed" | "sent" | "responded"; + +export type Pledge = { + id: string; + cityId: string; + actionId: string; // rec id, e.g. "poa-flood-resilience" + worryLabel: string; + headline: string; + firstName: string; + neighborhood: string; + email?: string; // stored server-side ONLY — never returned by any read + createdAt: string; // ISO + status: PledgeStatus; +}; + +// What leaves the server (no email). +export type PublicPledge = Omit; + +export type CityAggregate = { + total: number; + sent: number; + responded: number; + actions: string[]; +}; + +// Anonymous historical baseline so the public numbers stay substantial without +// storing a record for every past participant. Displayed totals = baseline + live. +const SEED_BASELINE: Record = { + "porto-alegre": { total: 79, sent: 31, responded: 9 }, }; -type Store = { counts: Record }; -let cache: Store | null = null; +// A few real-looking seeded signatures (most recent last) so the wall isn't empty. +const SEED_PLEDGES: Omit[] = [ + { id: "seed-1", cityId: "porto-alegre", actionId: "poa-flood-resilience", worryLabel: "Flooding", headline: "Report a flooding or drainage problem on your street to Defesa Civil.", firstName: "Mariana", neighborhood: "Cidade Baixa", status: "responded" }, + { id: "seed-2", cityId: "porto-alegre", actionId: "poa-active-mobility", worryLabel: "Getting around safely", headline: "Comment on a street redesign, bike lane, or pedestrian-safety plan to the mobility council.", firstName: "Rafael", neighborhood: "Bom Fim", status: "sent" }, + { id: "seed-3", cityId: "porto-alegre", actionId: "poa-heat-green-infrastructure", worryLabel: "Heat & no shade", headline: "Nominate a hot street, bus stop, school, or plaza that needs shade and trees.", firstName: "Letícia", neighborhood: "Menino Deus", status: "sent" }, + { id: "seed-4", cityId: "porto-alegre", actionId: "poa-landslide-prevention", worryLabel: "Landslides", headline: "Report slope instability or a blocked drain in a risk area to Defesa Civil.", firstName: "Carlos", neighborhood: "Lomba do Pinheiro", status: "committed" }, + { id: "seed-5", cityId: "porto-alegre", actionId: "poa-flood-resilience", worryLabel: "Flooding", headline: "Take flood-drainage priorities to your region's participatory-budget assembly.", firstName: "Beatriz", neighborhood: "Sarandi", status: "committed" }, + { id: "seed-6", cityId: "porto-alegre", actionId: "poa-residential-energy", worryLabel: "Energy bills & comfort", headline: "Ask for home-efficiency help for heat-exposed, low-income homes — citing the city's Climate Action Plan.", firstName: "João", neighborhood: "Restinga", status: "committed" }, +]; + +// Spread seed timestamps over the past few days so "time ago" looks natural. +function seedPledges(): Pledge[] { + const now = Date.now(); + const HOUR = 3_600_000; + const offsets = [72 * HOUR, 28 * HOUR, 9 * HOUR, 5 * HOUR, 2 * HOUR, 40 * 60_000]; + return SEED_PLEDGES.map((p, i) => ({ + ...p, + createdAt: new Date(now - (offsets[i] ?? i * HOUR)).toISOString(), + })); +} +type Store = { pledges: Pledge[] }; + +// Always read the file fresh. In Next dev, route handlers (/api/pledge, +// /api/metrics, /api/wall) don't reliably share module-level state, so an +// in-memory cache makes one route return stale data after another writes. The +// file is the single source of truth; volume is tiny (demo). function load(): Store { - if (cache) return cache; try { - cache = JSON.parse(fs.readFileSync(FILE, "utf8")) as Store; + const parsed = JSON.parse(fs.readFileSync(FILE, "utf8")); + if (!parsed || !Array.isArray(parsed.pledges)) throw new Error("bad shape"); + return parsed as Store; } catch { - cache = { counts: { ...SEED } }; - persist(); + const seeded = { pledges: seedPledges() }; + persist(seeded); + return seeded; } - return cache; } -function persist(): void { +function persist(store: Store): void { try { fs.mkdirSync(path.dirname(FILE), { recursive: true }); - fs.writeFileSync(FILE, JSON.stringify(cache), "utf8"); + fs.writeFileSync(FILE, JSON.stringify(store), "utf8"); } catch { - /* read-only fs (e.g. serverless) — counts stay in-memory for the session */ + /* read-only fs (e.g. serverless) — write is best-effort */ } } -export function getCounts(): Record { - return { ...load().counts }; +const strip = (p: Pledge): PublicPledge => { + const { email: _email, ...rest } = p; + return rest; +}; + +export function getCityAggregate(cityId: string): CityAggregate { + // Baseline = anonymous historical participants, excluding the named records in + // the store; the store's records (seeded + live) are added on top. + const base = SEED_BASELINE[cityId] ?? { total: 0, sent: 0, responded: 0 }; + const live = load().pledges.filter((p) => p.cityId === cityId); + return { + total: base.total + live.length, + sent: base.sent + live.filter((p) => p.status === "sent" || p.status === "responded").length, + responded: base.responded + live.filter((p) => p.status === "responded").length, + actions: Array.from(new Set(live.map((p) => p.actionId))), + }; +} + +// --- Funder readout: aggregate ALL pledges by theme + neighborhood ---------- + +export type FunderTheme = "Resilience" | "Greening" | "Energy" | "Mobility"; + +// Map a rec/action id to a funder theme (rec ids look like "poa-flood-resilience"). +function themeForAction(actionId: string): FunderTheme { + if (actionId.includes("flood") || actionId.includes("landslide")) return "Resilience"; + if (actionId.includes("heat") || actionId.includes("green")) return "Greening"; + if (actionId.includes("energy")) return "Energy"; + if (actionId.includes("mobility")) return "Mobility"; + return "Resilience"; } -export function getCount(cityId: string): number { - return load().counts[cityId] ?? 0; +export type FunderReadout = { + total: number; + sent: number; + responded: number; + responseRate: number; // sent / total, 0..1 + byTheme: { theme: FunderTheme; total: number; sent: number }[]; + byNeighborhood: { name: string; count: number }[]; +}; + +const THEMES: FunderTheme[] = ["Resilience", "Greening", "Energy", "Mobility"]; + +export function getFunderReadout(cityId: string): FunderReadout { + const agg = getCityAggregate(cityId); + const live = load().pledges.filter((p) => p.cityId === cityId); + + const byTheme = THEMES.map((theme) => { + const inTheme = live.filter((p) => themeForAction(p.actionId) === theme); + return { + theme, + total: inTheme.length, + sent: inTheme.filter((p) => p.status === "sent" || p.status === "responded").length, + }; + }).filter((t) => t.total > 0); + + const counts = new Map(); + for (const [name, n] of Object.entries(SEED_NEIGHBORHOOD_BASELINE[cityId] ?? {})) counts.set(name, n); + for (const p of live) { + const n = (p.neighborhood || "").trim(); + if (n) counts.set(n, (counts.get(n) ?? 0) + 1); + } + const byNeighborhood = Array.from(counts, ([name, count]) => ({ name, count })).sort((a, b) => b.count - a.count); + + return { + total: agg.total, + sent: agg.sent, + responded: agg.responded, + responseRate: agg.total > 0 ? agg.sent / agg.total : 0, + byTheme, + byNeighborhood, + }; +} + +// Per-action share of the anonymous baseline (sums to SEED_BASELINE for the city), +// so the "most-backed actions" ranking reads as real popularity, not just the +// handful of named seed records. +const SEED_ACTION_BASELINE: Record> = { + "porto-alegre": { + "poa-flood-resilience": { count: 31, sent: 14 }, + "poa-heat-green-infrastructure": { count: 18, sent: 7 }, + "poa-landslide-prevention": { count: 14, sent: 6 }, + "poa-active-mobility": { count: 11, sent: 3 }, + "poa-residential-energy": { count: 5, sent: 1 }, + }, +}; + +// Per-neighborhood share of the anonymous baseline (sums to SEED_BASELINE.total), +// so the engagement map shows realistic, varied bubbles rather than single dots. +// Names match the coordinate lookup in data/poaNeighborhoods.ts (accent-insensitive). +const SEED_NEIGHBORHOOD_BASELINE: Record> = { + "porto-alegre": { + "Cidade Baixa": 9, + "Centro Histórico": 8, + Sarandi: 8, + Navegantes: 7, + "Menino Deus": 6, + "Bom Fim": 6, + Restinga: 5, + Partenon: 5, + "Lomba do Pinheiro": 5, + Ipanema: 4, + Cavalhada: 4, + Azenha: 3, + "São Geraldo": 3, + "Rubem Berta": 3, + Petrópolis: 3, + }, +}; + +export type ActionRank = { actionId: string; count: number; sent: number }; + +export function getActionRanking(cityId: string): ActionRank[] { + const byId = new Map(); + for (const [id, b] of Object.entries(SEED_ACTION_BASELINE[cityId] ?? {})) byId.set(id, { ...b }); + for (const p of load().pledges.filter((x) => x.cityId === cityId)) { + const cur = byId.get(p.actionId) ?? { count: 0, sent: 0 }; + cur.count += 1; + if (p.status === "sent" || p.status === "responded") cur.sent += 1; + byId.set(p.actionId, cur); + } + return Array.from(byId, ([actionId, v]) => ({ actionId, ...v })).sort((a, b) => b.count - a.count); +} + +export function getRecent(cityId: string, limit = 12): PublicPledge[] { + return load() + .pledges.filter((p) => p.cityId === cityId) + .sort((a, b) => b.createdAt.localeCompare(a.createdAt)) + .slice(0, limit) + .map(strip); +} + +let counter = 0; +function newId(): string { + counter += 1; + return `p_${Date.now().toString(36)}_${counter}`; +} + +export function createPledge(input: { + cityId: string; + actionId: string; + worryLabel: string; + headline: string; + firstName: string; + neighborhood: string; + email?: string; +}): PublicPledge { + const s = load(); + const pledge: Pledge = { + id: newId(), + cityId: input.cityId, + actionId: input.actionId, + worryLabel: input.worryLabel, + headline: input.headline, + firstName: input.firstName, + neighborhood: input.neighborhood, + email: input.email || undefined, + createdAt: new Date().toISOString(), + status: "committed", + }; + s.pledges.push(pledge); + persist(s); + return strip(pledge); } -export function increment(cityId: string): number { +export function setStatus(id: string, status: PledgeStatus): PublicPledge | null { const s = load(); - s.counts[cityId] = (s.counts[cityId] ?? 0) + 1; - persist(); - return s.counts[cityId]; + const p = s.pledges.find((x) => x.id === id); + if (!p) return null; + p.status = status; + persist(s); + return strip(p); } diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/poaMoves.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/poaMoves.ts new file mode 100644 index 0000000..a39cf11 --- /dev/null +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/poaMoves.ts @@ -0,0 +1,237 @@ +// The anti-slop core: for each worry a Porto Alegre resident might have, and each +// level of appetite, ONE concrete next move tied to a REAL, working local channel. +// Channels/URLs are drawn from the curated portoAlegreEngagementRecommendations +// (data/localEngagement.ts) — we only add the imperative framing, the "what happens +// next", and a seed for the AI-written message. Nothing here is generated; the AI +// only fills the message words. + +export type Appetite = "quick" | "deeper"; +export type WorryKey = "flooding" | "landslides" | "heat" | "energy" | "mobility"; + +export type Move = { + recId: string; // commitment actionId — ties the tally to this concern + intent: "report" | "comment" | "propose" | "join"; + headline: string; // a direct imperative, not a category + channelName: string; + channelUrl: string; + channelType: "official" | "community"; + time: string; + whatNext: string; // closes the loop: what the channel does with it + messageSeed: string; // what the ready-to-send message should ask for +}; + +export type Worry = { + key: WorryKey; + label: string; + icon: string; + blurb: string; + level?: string; // CCRA signal, shown as a badge when "Very High" + moves: Record; +}; + +export const poaWorries: Worry[] = [ + { + key: "flooding", + label: "Flooding", + icon: "🌊", + level: "Very High", + blurb: "Drainage and flood risk to homes and streets.", + moves: { + quick: { + recId: "poa-flood-resilience", + intent: "report", + headline: "Report a flooding or drainage problem on your street to Defesa Civil.", + channelName: "Defesa Civil de Porto Alegre", + channelUrl: "https://prefeitura.poa.br/defesa-civil", + channelType: "official", + time: "~10 min", + whatNext: + "Defesa Civil logs the location and routes it to the city's drainage and risk teams — concrete, located reports are what push a street up the investment list.", + messageSeed: + "report a specific flood-prone or blocked-drainage point and ask that it be assessed and prioritised for drainage works", + }, + deeper: { + recId: "poa-flood-resilience", + intent: "propose", + headline: "Take flood-drainage priorities to your region's participatory-budget assembly.", + channelName: "Orçamento Participativo", + channelUrl: "https://prefeitura.poa.br/smgov/orcamento-participativo", + channelType: "official", + time: "1–2 hrs", + whatNext: + "Porto Alegre invented participatory budgeting — proposals voted up in your regional assembly become real funded works. Sewerage here grew from 46% to ~86% of the city this way.", + messageSeed: + "propose that drainage and flood-protection works in your neighbourhood be put forward and voted on at the regional participatory-budget assembly", + }, + }, + }, + { + key: "landslides", + label: "Landslides", + icon: "⛰️", + level: "Very High", + blurb: "Slope and hillside risk to people and infrastructure.", + moves: { + quick: { + recId: "poa-landslide-prevention", + intent: "report", + headline: "Report slope instability or a blocked drain in a risk area to Defesa Civil.", + channelName: "Defesa Civil de Porto Alegre", + channelUrl: "https://prefeitura.poa.br/defesa-civil", + channelType: "official", + time: "~10 min", + whatNext: + "Your observation feeds the civil-defense risk map that decides where stabilization work and early-warning go first.", + messageSeed: + "report signs of slope instability, cracking, or drainage blockage in a hillside area and ask for a risk assessment", + }, + deeper: { + recId: "poa-landslide-prevention", + intent: "comment", + headline: + "Ask the urban-environment council (CMDUA) how landslide-prevention investment is prioritised.", + channelName: "Conselho Municipal de Desenvolvimento Urbano Ambiental (CMDUA)", + channelUrl: "https://prefeitura.poa.br/smamus/planejamento-urbano/cmdua", + channelType: "official", + time: "30–60 min", + whatNext: + "CMDUA reviews land-use and planning decisions in public — a resident question on the record forces prevention onto the agenda.", + messageSeed: + "ask, on the public record, how landslide-prevention maps and investments are prioritised and how residents in exposed areas can be included", + }, + }, + }, + { + key: "heat", + label: "Heat & no shade", + icon: "🌳", + blurb: "Heatwaves and streets that need trees and cooling.", + moves: { + quick: { + recId: "poa-heat-green-infrastructure", + intent: "report", + headline: "Nominate a hot street, bus stop, school, or plaza that needs shade and trees.", + channelName: "Planejamento e cuidado com árvores (Prefeitura)", + channelUrl: "https://prefeitura.poa.br/smamus/planejamento-e-cuidado-com-arvores", + channelType: "official", + time: "~15 min", + whatNext: + "The tree-care service maps requests; clustered nominations are how planting and cooling get scheduled where heat hits hardest.", + messageSeed: + "nominate a specific hot, treeless spot (a bus stop, school, or plaza) for shade trees and explain who is exposed there", + }, + deeper: { + recId: "poa-heat-green-infrastructure", + intent: "join", + headline: "Join AGAPAN to push for equitable tree care and shade with others.", + channelName: "AGAPAN", + channelUrl: "https://www.agapan.org.br/", + channelType: "community", + time: "Ongoing", + whatNext: + "AGAPAN has defended green space in Rio Grande do Sul for decades — joining adds your voice to an organised campaign the environment council already listens to.", + messageSeed: + "introduce yourself as a resident who wants to help protect and expand trees and shade, and ask how to get involved", + }, + }, + }, + { + key: "energy", + label: "Energy bills & comfort", + icon: "🏠", + blurb: "Hot homes and high bills — efficiency and comfort.", + moves: { + quick: { + recId: "poa-residential-energy", + intent: "comment", + headline: + "Ask for home-efficiency help for heat-exposed, low-income homes — citing the city's Climate Action Plan.", + channelName: "Plano de Ação Climática de Porto Alegre", + channelUrl: "https://prefeitura.poa.br/smamus/plano-de-acao-climatica", + channelType: "official", + time: "~15 min", + whatNext: + "Citing the city's own plan turns a personal ask into a policy-aligned one officials can act on.", + messageSeed: + "ask for residential energy-efficiency and retrofit support that prioritises low-income, heat-exposed households, referencing the city's Climate Action Plan", + }, + deeper: { + recId: "poa-residential-energy", + intent: "propose", + headline: "Propose a building-efficiency program for low-income homes at participatory budgeting.", + channelName: "Orçamento Participativo", + channelUrl: "https://prefeitura.poa.br/smgov/orcamento-participativo", + channelType: "official", + time: "1–2 hrs", + whatNext: + "Efficiency upgrades voted through participatory budgeting reach the households that feel heat and bills hardest.", + messageSeed: + "propose a neighbourhood building-efficiency / retrofit program for low-income homes to the regional participatory-budget assembly", + }, + }, + }, + { + key: "mobility", + label: "Getting around safely", + icon: "🚲", + blurb: "Safer walking, cycling, and public-space access.", + moves: { + quick: { + recId: "poa-active-mobility", + intent: "comment", + headline: "Comment on a street redesign, bike lane, or pedestrian-safety plan to the mobility council.", + channelName: "Conselho Municipal de Mobilidade Urbana (COMMU)", + channelUrl: "https://prefeitura.poa.br/catalogo-conselhos/commu", + channelType: "official", + time: "15–30 min", + whatNext: + "COMMU is the consultative body for mobility policy — public comments shape what actually gets built.", + messageSeed: + "comment on a specific street, crossing, or bike-lane that needs to be safer, and ask that active mobility be prioritised there", + }, + deeper: { + recId: "poa-active-mobility", + intent: "join", + headline: "Join Bike Anjo to push for safe streets together.", + channelName: "Bike Anjo", + channelUrl: "https://bikeanjo.org/", + channelType: "community", + time: "Ongoing", + whatNext: + "Bike Anjo's volunteers help new riders and campaign for safer streets — organised numbers are what move mobility decisions.", + messageSeed: + "introduce yourself as a resident who wants safer cycling and walking, and ask how to join the local volunteer network", + }, + }, + }, +]; + +// Resident-facing "why your one action counts" — the awareness / aggregate-demand +// framing. This belongs in the UI (so residents understand the leverage), NOT in +// the message sent to the channel. +export const whyByIntent: Record = { + report: + "On its own, one report flags a single spot. But located reports are data — the city, and the funders behind its budget, decide where money goes by where problems are documented. Reporting is how your street gets counted.", + comment: + "A lone comment is easy to overlook; a visible pattern of residents asking for the same thing is not. Public, on-the-record input is what shifts what councils prioritize — and what funders see as real demand.", + propose: + "Proposals carried by residents, and backed by others, are what budgets respond to. You're not just asking — you're building the documented demand that unlocks funding.", + join: + "Organized numbers move decisions one person can't. Joining adds your voice to a group that stakeholders, and the funders who work through them, already take seriously.", +}; + +export const appetiteMeta: Record = { + quick: { label: "Quick & online", desc: "About 15 minutes, from where you are.", icon: "⚡" }, + deeper: { label: "Deeper, with others", desc: "An hour or two — show up or join people.", icon: "🤝" }, +}; + +export function getMove(worry: WorryKey, appetite: Appetite): Move { + const w = poaWorries.find((x) => x.key === worry)!; + return w.moves[appetite]; +} + +// Each worry's two moves share one recId (the underlying action) — so recId ↔ worry +// is 1:1. Used to label the "most-backed actions" ranking. +export function worryByRecId(recId: string): Worry | undefined { + return poaWorries.find((w) => w.moves.quick.recId === recId || w.moves.deeper.recId === recId); +} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts deleted file mode 100644 index 5ef8496..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/prioritize.ts +++ /dev/null @@ -1,166 +0,0 @@ -// Per-city prioritization of the HIAP action library. -// -// CityCatalyst's climate_actions are city-agnostic; we rank them for a given -// city by matching adaptation actions to the city's top CCRA hazards and -// mitigation actions to its dominant emitting sectors (GHGI). Pure + deterministic. - -import type { City, RiskLevel } from "../data/types"; -import type { - ClimateAction, - HazardKey, - GhgSectorKey, - Effectiveness, -} from "../data/climateActions"; -import { normalizeHazard, normalizeSector } from "./hazardNormalize"; - -export type SourceSignal = { - kind: "hazard" | "sector"; - cityValue: string; // e.g. "Heatwaves (Very High)" or "Transportation (81%)" - matchedOn: string; // the canonical key the action matched on - weight: number; // contribution to the score (for an honest "why") -}; - -export type RankedAction = { - action: ClimateAction; - score: number; - sourceSignals: SourceSignal[]; -}; - -const RISK_WEIGHT: Record = { - "Very High": 1.0, - High: 0.75, - Medium: 0.45, - Low: 0.2, -}; - -const EFF_SCORE: Record = { high: 1, medium: 0.6, low: 0.3 }; - -function effScore(e: Effectiveness | null | undefined): number { - return e ? EFF_SCORE[e] : 0.5; // unknown effectiveness → neutral midpoint -} - -// "20-39" → 0.295 ; "80-100" → 0.9 ; null → 0 -function ghgScore(range: string | null | undefined): number { - if (!range) return 0; - const m = range.match(/(\d+)\s*-\s*(\d+)/); - if (!m) return 0; - return (Number(m[1]) + Number(m[2])) / 2 / 100; -} - -const SECTOR_LABEL: Record = { - stationary_energy: "Stationary Energy", - transportation: "Transportation", - waste: "Waste", - ippu: "IPPU", - afolu: "AFOLU", -}; - -type HazardCtx = { key: HazardKey; level: RiskLevel; label: string }; -type SectorCtx = { key: GhgSectorKey; share: number; label: string }; - -// Deduplicate by canonical key (several prose hazards can map to the same key), -// keeping the highest-severity context so each key is scored once. -function cityHazards(city: City): HazardCtx[] { - const byKey = new Map(); - for (const h of city.risk?.topHazards ?? []) { - for (const key of normalizeHazard(h.hazard)) { - const prev = byKey.get(key); - if (!prev || RISK_WEIGHT[h.level] > RISK_WEIGHT[prev.level]) { - byKey.set(key, { key, level: h.level, label: h.hazard }); - } - } - } - return [...byKey.values()]; -} - -function citySectors(city: City): SectorCtx[] { - const e = city.emissions; - if (!e) return []; - const byKey = new Map(); - if (e.sectors?.length) { - for (const s of e.sectors) { - const key = normalizeSector(s.sector); - if (!key) continue; - const prev = byKey.get(key); - if (!prev || s.sharePct / 100 > prev.share) { - byKey.set(key, { key, share: s.sharePct / 100, label: s.sector }); - } - } - } else if (e.topSector) { - const key = normalizeSector(e.topSector); - if (key) byKey.set(key, { key, share: 0.6, label: e.topSector }); - } - return [...byKey.values()]; -} - -export function prioritizeActions( - city: City, - actions: ClimateAction[], - opts: { topN?: number } = {} -): RankedAction[] { - const topN = opts.topN ?? 6; - const hazards = cityHazards(city); - const sectors = citySectors(city); - - const ranked: RankedAction[] = []; - - for (const action of actions) { - let score = 0; - const signals: SourceSignal[] = []; - - if (action.actionType === "adaptation") { - for (const h of hazards) { - if (!action.hazards.includes(h.key)) continue; - const eff = effScore(action.adaptationPerHazard?.[h.key] ?? action.adaptationEffectiveness); - const contrib = RISK_WEIGHT[h.level] * eff; - score += contrib; - signals.push({ - kind: "hazard", - cityValue: `${h.label} (${h.level})`, - matchedOn: h.key, - weight: contrib, - }); - } - } else { - for (const s of sectors) { - const ghg = action.ghgReductionPotential?.[s.key]; - const matchesSector = action.sectors.includes(s.key); - if (ghg == null && !matchesSector) continue; - const contrib = s.share * (ghgScore(ghg) || 0.5); - score += contrib; - signals.push({ - kind: "sector", - cityValue: `${s.label} (${Math.round(s.share * 100)}%)`, - matchedOn: s.key, - weight: contrib, - }); - } - } - - if (score <= 0) continue; - - // Tie-breaker: reward the stakeholder-engagement co-benefit (the fundable signal). - score += 0.05 * (action.coBenefits?.stakeholder_engagement ?? 0); - - ranked.push({ action, score, sourceSignals: signals }); - } - - ranked.sort((a, b) => b.score - a.score); - - // Balance the result so both adaptation (matches risks) and mitigation - // (matches emissions) are represented — adaptation scores are on a larger - // scale and would otherwise crowd out every mitigation action. - const adapt = ranked.filter((r) => r.action.actionType === "adaptation"); - const mitig = ranked.filter((r) => r.action.actionType === "mitigation"); - const target = Math.ceil(topN / 2); - const out = [...adapt.slice(0, target), ...mitig.slice(0, topN - target)]; - // Backfill if one type was short. - if (out.length < topN) { - const used = new Set(out); - for (const r of ranked) { - if (out.length >= topN) break; - if (!used.has(r)) out.push(r); - } - } - return out; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts deleted file mode 100644 index 90a6b69..0000000 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/profileHeadline.ts +++ /dev/null @@ -1,89 +0,0 @@ -// A one-line, plain-language "at a glance" headline for a city, derived purely -// from its emissions + risk data (no LLM). Localized EN/ES/PT. - -import type { City, RiskLevel } from "../data/types"; -import type { HazardKey, Lang } from "../data/climateActions"; -import { normalizeHazard, normalizeSector } from "./hazardNormalize"; - -const LEVEL_ORDER: Record = { "Very High": 4, High: 3, Medium: 2, Low: 1 }; - -const LEVEL_WORD: Record> = { - "Very High": { en: "Very high", es: "muy alto", pt: "muito alto" }, - High: { en: "High", es: "alto", pt: "alto" }, - Medium: { en: "Medium", es: "medio", pt: "médio" }, - Low: { en: "Low", es: "bajo", pt: "bajo" }, -}; - -const HAZARD_WORD: Record> = { - heatwaves: { en: "heatwaves", es: "olas de calor", pt: "ondas de calor" }, - landslides: { en: "landslides", es: "deslizamientos", pt: "deslizamentos" }, - floods: { en: "flooding", es: "inundaciones", pt: "inundações" }, - droughts: { en: "drought", es: "sequía", pt: "seca" }, - diseases: { en: "disease", es: "enfermedades", pt: "doenças" }, - "sea-level-rise": { en: "sea-level rise", es: "aumento del nivel del mar", pt: "elevação do nível do mar" }, - storms: { en: "storms", es: "tormentas", pt: "tempestades" }, - wildfires: { en: "wildfire", es: "incendios", pt: "incêndios" }, -}; - -const SECTOR_WORD: Record> = { - transportation: { en: "transport", es: "el transporte", pt: "o transporte" }, - stationary_energy: { en: "energy use", es: "la energía", pt: "a energia" }, - waste: { en: "waste", es: "los residuos", pt: "os resíduos" }, - ippu: { en: "industry", es: "la industria", pt: "a indústria" }, - afolu: { en: "land use", es: "el uso del suelo", pt: "o uso do solo" }, -}; - -const JOIN: Record = { en: " & ", es: " y ", pt: " e " }; - -function topHazardWords(city: City, lang: Lang): { word: string; level: RiskLevel } | null { - const hazards = city.risk?.topHazards ?? []; - if (hazards.length === 0) return null; - const keys: HazardKey[] = []; - let level: RiskLevel = "Low"; - for (const h of hazards) { - if (LEVEL_ORDER[h.level] > LEVEL_ORDER[level]) level = h.level; - for (const k of normalizeHazard(h.hazard)) if (!keys.includes(k)) keys.push(k); - } - if (keys.length === 0) return null; - const word = keys.slice(0, 2).map((k) => HAZARD_WORD[k][lang]).join(JOIN[lang]); - return { word, level }; -} - -function sectorClause(city: City, lang: Lang): string | null { - const e = city.emissions; - if (!e) return null; - if (e.sectors?.length) { - const top = [...e.sectors].sort((a, b) => b.sharePct - a.sharePct)[0]; - const key = normalizeSector(top.sector); - const word = key ? SECTOR_WORD[key][lang] : top.sector; - const pct = Math.round(top.sharePct); - if (lang === "es") return `${word} genera el ${pct}% de las emisiones`; - if (lang === "pt") return `${word} gera ${pct}% das emissões`; - return `${word} drives ${pct}% of emissions`; - } - if (e.topSector) { - const key = normalizeSector(e.topSector); - const word = key ? SECTOR_WORD[key][lang] : e.topSector.toLowerCase(); - if (lang === "es") return `${word} es la mayor fuente de emisiones`; - if (lang === "pt") return `${word} é a maior fonte de emissões`; - return `${word} is the largest emissions source`; - } - return null; -} - -export function profileHeadline(city: City, lang: Lang = "en"): string | null { - const hz = topHazardWords(city, lang); - const sec = sectorClause(city, lang); - const riskPart = hz - ? lang === "es" - ? `Riesgo ${LEVEL_WORD[hz.level].es} por ${hz.word}` - : lang === "pt" - ? `Risco ${LEVEL_WORD[hz.level].pt} de ${hz.word}` - : `${LEVEL_WORD[hz.level].en} risk from ${hz.word}` - : null; - - if (riskPart && sec) return `${riskPart}; ${sec}.`; - if (riskPart) return `${riskPart}.`; - if (sec) return `${sec[0].toUpperCase()}${sec.slice(1)}.`; - return null; -} diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts index 66cec0f..46763d0 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/lib/useGenerate.ts @@ -6,6 +6,8 @@ import { useCarbon } from "./carbonContext"; export type GenTask = | "next_steps" + | "local_message" + | "civic_guide" | "draft_proposal" | "evidence" | "pathways" diff --git a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx index 40d657b..eb5aa2e 100644 --- a/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx +++ b/events/2026-06-11-unlock-the-money/civic-climate-action/app/src/app/page.tsx @@ -1,96 +1,207 @@ -import CityExplorer from "./components/CityExplorer"; -import StoriesGallery from "./components/StoriesGallery"; -import TakeAction from "./components/TakeAction"; +import Link from "next/link"; +import YourMove from "./components/YourMove"; +import CommitmentWall from "./components/CommitmentWall"; +import PoaEngagementMap from "./components/PoaEngagementMap"; import { cities } from "./data/cities"; import { stories } from "./data/stories"; +const poa = cities.find((c) => c.id === "porto-alegre")!; + +// Lead with Porto Alegre's own story, then two more proof points. +const teaserIds = ["portoalegre-participatory-budget", "rio-favela-reforestation", "medellin-green-corridors"]; +const teaserStories = teaserIds + .map((id) => stories.find((s) => s.id === id)) + .filter((s): s is (typeof stories)[number] => Boolean(s)); + +const hazards = poa.risk?.topHazards ?? []; +const topSector = poa.emissions?.sectors?.[0]; + export default function Home() { return ( <> {/* Hero */} -
+
-
Civic Climate Action · a CityCatalyst companion
-

- Your city, your move. +
Porto Alegre · pilot city
+

+ Porto Alegre. Your move.

-

- CityCatalyst tells city governments what to do about climate. This is the other - direction — a plain-language way for residents to see what’s happening in their - city and find a real way to take part. +

+ See what your city is up against on climate — then get one + real thing you can actually do this week, with the exact place to do it and the + words to say.

-

- “I, as a citizen, want to know what’s happening in my city and how I could - take better action.” +

+ Built on CityCatalyst data. More cities coming.

- {/* Explore cities */} -
+ {/* What's at stake */} +
-
Explore
-

- What’s happening, city by city +
What’s at stake
+

+ What Porto Alegre is up against

-

- Search a city or pick one on the map to see how residents there are shaping local - climate action — and what you could do in your own. +

+ From the city’s own climate-risk assessment. These are the signals your move pushes on. +

+ +
+ {hazards.map((h) => ( +
+
+ {h.level} risk +
+
{h.hazard}
+
Threatens {h.keyImpact} across the city.
+
+ ))} + {topSector && ( +
+
+ Emissions +
+
+ {topSector.sector} {Math.round(topSector.sharePct)}% +
+
The city’s largest reported emissions source.
+
+ )} +
+ +

+ Source:{" "} + {poa.risk?.sourceUrl ? ( + {poa.risk.source} ↗ + ) : ( + poa.risk?.source + )} + . Porto Alegre is the birthplace of participatory budgeting — residents here have shaped real city spending since 1989.

-
- {/* Success stories */} -
+ {/* Your one move */} +
-
Inspiration
-

- Citizens have done this before +
Your move
+

+ One real step — not a to-do list

- Real, sourced stories of communities that changed their cities — from cooling streets - with trees to rewriting climate law. Every card links to its source. + Answer two quick questions. We’ll hand you a single concrete move, the real local + channel to do it through, and a message ready to send.

- +
- {/* Take action */} -
+ {/* Public commitment wall */} +
-
Take action
-

- Your next step +
On the record
+

+ What Porto Alegre is committing to

-

- You don’t need to be an expert or wait for permission. Pick what you care about, - and start with one concrete move. +

+ Every commitment here is a named resident pledging a real, specific action — and tracking + whether they followed through. This is engagement you can actually count.

- +
+ +
+ +
+
+ + {/* For funders callout */} +
+
+
+
+
For funders
+

+ These commitments are the community-engagement co-benefit MDBs and philanthropy + already score — quantified by theme and neighborhood, with follow-through.{" "} + See how civic engagement unlocks climate finance. +

+
+ + See the funder view → + +
+
+
+ + {/* Proof teaser */} +
+
+
It works
+

+ Residents have changed their cities before +

+

+ Real, sourced stories of ordinary people who moved their city — starting exactly where you are now. +

+ +
+ {teaserStories.map((s) => ( +
+
{s.city}, {s.country} · {s.year}
+
{s.title}
+

{s.outcome}

+
+ ))} +
+ + + Read more real stories → +
{/* Footer */} -