actores = FileAttachment("data/instituciones.json").json()
tipos = [...new Set(actores.map(d => d.tipo))]
color_tipo = ({
"Gobierno nacional": "#81337e", "Gobierno territorial": "#00ACA8", "Autoridad ambiental": "#2e8b57",
"Internacional": "#003a70", "Humanitaria": "#e54d23", "Academia nacional": "#b2a142",
"Academia internacional": "#8a7d2a", "Gremio técnico": "#6d4c41", "Organización técnica": "#5c6bc0",
"Sociedad civil": "#c2185b", "Sector privado": "#607d8b"
})
sesion = ({
p: ["Plenaria", "#81337e"], st: ["Sesión temática", "#003a70"], sp: ["Sesión paralela", "#00ACA8"],
se: ["Sesión especial", "#e54d23"], la: ["Laboratorio de aprendizaje", "#a08c1f"],
an: ["Diálogo de alto nivel", "#5c6bc0"], ev: ["Escenario en vivo", "#2e8b57"], pt: ["Póster", "#8d6e63"]
})
rol_orden = ["Anfitriona", "Co-anfitriona", "Ponente", "Autoría"]
norm = s => s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase()
total_part = d3.sum(actores, d => d.trabajos.length)
total_sesiones = new Set(actores.flatMap(d => d.trabajos.map(t => t.slug))).size
html`<div class="dir-stats">
<div class="dir-stat"><b>${actores.length}</b><span>Actores</span></div>
<div class="dir-stat"><b>${total_part}</b><span>Participaciones</span></div>
<div class="dir-stat"><b>${total_sesiones}</b><span>Sesiones y trabajos</span></div>
</div>`Directorio de actores
Organizaciones del orden nacional, territorial, internacional, académico y de la sociedad civil que participaron en la Plataforma Nacional 2026. Cada actor enlaza a las sesiones y trabajos en los que figura como anfitrión, ponente o autor, según los capítulos de estas memorias.
viewof filtros = {
const estado = {q: "", tipo: "Todos", orden: "Más participaciones"};
const raiz = html`<div></div>`;
const buscar = html`<input class="dir-search" type="search" placeholder="Buscar por institución, sigla o título del trabajo…" aria-label="Buscar">`;
const orden = html`<select class="dir-sort" aria-label="Ordenar"><option>Más participaciones</option><option>A–Z</option></select>`;
const chips = html`<div class="dir-chips"></div>`;
const emitir = () => { raiz.value = {...estado}; raiz.dispatchEvent(new Event("input", {bubbles: true})); };
const pintar = () => chips.replaceChildren(...["Todos", ...tipos].map(t => {
const n = t === "Todos" ? actores.length : actores.filter(a => a.tipo === t).length;
const b = html`<button type="button" class="dir-chip ${estado.tipo === t ? "on" : ""}" style="--c:${color_tipo[t] || "#81337e"}"><span class="dot"></span>${t} <b>${n}</b></button>`;
b.onclick = () => { estado.tipo = t; pintar(); emitir(); };
return b;
}));
buscar.oninput = e => { e.stopPropagation(); estado.q = buscar.value; emitir(); };
orden.onchange = () => { estado.orden = orden.value; emitir(); };
raiz.append(html`<div class="dir-tools"></div>`, chips);
raiz.firstChild.append(buscar, orden);
pintar();
raiz.value = {...estado};
return raiz;
}visibles = actores
.filter(d => (filtros.tipo === "Todos" || d.tipo === filtros.tipo) &&
(!filtros.q || norm([d.sigla, d.nombre, ...d.trabajos.map(t => t.titulo)].join(" ")).includes(norm(filtros.q))))
.sort((a, b) => filtros.orden === "A–Z"
? a.sigla.localeCompare(b.sigla, "es")
: b.trabajos.length - a.trabajos.length || a.sigla.localeCompare(b.sigla, "es"))
html`<p style="font-size:.85rem;opacity:.6">${visibles.length} ${visibles.length === 1 ? "actor" : "actores"}</p>
${visibles.length === 0 ? html`<p class="dir-none">Ninguna coincidencia.</p>` : html`<div class="dir-grid">
${visibles.map(d => {
const n = d.trabajos.length;
const items = [...d.trabajos].sort((a, b) => rol_orden.indexOf(a.rol) - rol_orden.indexOf(b.rol) || a.slug.localeCompare(b.slug));
return html`<article class="dir-card" style="--c:${color_tipo[d.tipo]}">
<div class="dir-sigla">${d.sigla}</div>
<h3 class="dir-nombre">${d.nombre}</h3>
<div class="dir-tipo">${d.tipo}</div>
${n ? html`<details ${filtros.q ? "open" : ""}>
<summary><span class="n">${n}</span>${n === 1 ? "participación" : "participaciones"}<span class="chev">▾</span></summary>
<ul class="dir-list">
${items.map(t => { const s = sesion[t.slug.split("-")[0]];
return html`<li>
<span class="dir-code" style="background:${s[1]}" title="${s[0]}">${t.slug.toUpperCase()}</span>
<a href="${t.href.replace(/\.qmd$/, ".html")}">${t.titulo}</a>
<span class="dir-rol">${t.rol}</span></li>`; })}
</ul>
</details>` : html`<p class="dir-vacio">Sin participaciones registradas en estas memorias.</p>`}
</article>`;
})}
</div>`}`