<!-- SOLID CITY · part 2872 -->
ens.roster ? CityCitizens.roster.length : '', songs: '' };
  try { var ps = window.CityPlayer && CityPlayer.state(); if (ps && ps.songs) n.songs = ps.songs; } catch (e) {}
  return String(s).replace(/\{(citizens|songs)\}\s*/g, function (m, k) { return n[k] ? n[k] + ' ' : ''; }).replace(/^./, function (c) { return c.toUpperCase(); });
}
function act(k) {   // in-city actions for the feature list; every one maps to a live module API
  var H = window.CityHyper;
  if (k === 'close') return close();
  if (/^tab:/.test(k)) return tab(k.slice(4));
  close();
  if (k === 'hyper') { if (window.CityHyperFold) CityHyperFold.set(false); return; }
  if (k === 'watch' && window.CityWatch) return CityWatch.open();
  if (k === 'radar' && window.CityCitizens) return CityCitizens.list();
  if (k === 'sable') return A.openTalk();
  if (k === 'soul') return A.openSoul();
  if (/^citizen:/.test(k) && window.CityCitizens) return CityCitizens.open(k.slice(8));
  if (k === 'forge' && window.CityForge) return CityForge.open();
  if (k === 'music' && window.CityPlayer) return CityPlayer.open(true);
  if (k === 'book' && window.CityBook) return CityBook.open(0);
  if (k === 'library' && window.CityCampus) return CityCampus.directory();
  if (/^hyper:/.test(k) && H) { var p = H.pois.filter(function (q) { return q.id === k.slice(6); })[0]; if (p) H.driveTo(p, 'AI DRIVE'); }
}
function load(which) {
  if (which === 'feat') return D.feat ? Promise.resolve(D.feat) : getJSON(FEAT_URL).then(function (j) { D.feat = j; return j; });
  if (which === 'cur') return D.cur ? Promise.resolve(D.cur) : getJSON(CUR_URL).then(function (j) { D.cur = j; return j; });
  return getJSON('/api/beauty?brief=1', true).then(function (j) { D.beauty = j; return j; });
}
function fail(e) { body.innerHTML = '<p class="pd-meta">Could not load this list. Try again in a moment.</p>'; }
function features() {
  load('feat').then(function (F) {
    body.innerHTML = '<p class="pd-meta">' + esc(F.note || '') + '</p>' + F.groups.map(function (g) {
      return '<div class="pd-g"><h4>' + esc(g.title) + '</h4>' + g.items.map(function (it, i) {
        var go = it.city ? '<button type="button" class="pd-go gold" data-a="' + esc(it.city) + '">' + (/^tab:/.test(it.city) ? 'Open' : 'Go') + '</button>' : '';
        var link = it.href && (!it.city || !/^\/city\//.test(it.href)) ? '<a class="pd-go" href="' + esc(it.href) + '"' + (/^\/city\//.test(it.href) ? '' : ' target="_blank" rel="noopener"') + '>' + (it.city ? 'Page' : 'Open') + '</a>' : '';
        return '<div class="pd-i"><div><b>' + esc(it.name) + '</b><small>' + esc(fill(it.line)) + '</small></div>' + go + link + '</div>';
      }).join('') + '</div>';
    }).join('') + '<p class="pd-meta">Updated ' + esc(F.updated || '') + ' \u00b7 also on <a href="/learn" target="_blank" rel="noopener" style="color:#f6dc8e">/learn</a></p>';
    body.querySelectorAll('[data-a]').forEach(function (b) { b.addEventListener('click', function () { act(b.getAttribute('data-a')); }); });
  }).catch(fail);
}
function courses() {
  load('cur').then(function (C) {
    var n = C.campuses.reduce(function (a, c) { return a + c.courses.length; }, 0);
    body.innerHTML = '<p>The University Course Catalog: <b>' + C.campuses.length + ' campuses</b>, <b>' + n + ' courses</b>. Tap a course to open it, or go to its campus.</p>' +
      C.campuses.map(function (c) {
        return '<div class="pd-c"><b>' + esc(c.name) + '</b><div class="pd-row"><button type="button" class="pd-go gold" data-go="' + esc(c.id) + '">\uD83E\uDDED Go there</button><button type="button" class="pd-go" data-cat="' + esc(c.id) + '">\uD83D\uDCDA Catalog</button><a class="pd-go" href="/learn?campus=' + encodeURIComponent(c.id) + '#library" target="_blank" rel="noopener">Library</a></div>' +
          c.courses.map(function (k) { return '<button type="button" class="pd-k" data-c="' + esc(c.id) + '" data-k="' + esc(k.id) + '"><b style="color:#ffd27a">' + esc(k.title) + '</b><br><span class="pd-meta">' + k.lessons.length + ' lessons</span></button>'; }).join('') + '</div>';
      }).join('');
    var U = window.CityCampus;
    body.querySelectorAll('[data-go]').forEach(function (b) { b.addEventListener('click', function () { close(); if (U && U.go) U.go(b.getAttribute('data-go')); }); });
    body.querySelectorAll('[data-cat]').forEach(function (b) { b.addEventListener('click', function () { close(); if (U) U.open(b.getAttribute('data-cat')); }); });
    body.querySelectorAll('[data-k]').forEach(function (b) { b.addEventListener('click', function () { close(); if (U && U.course) U.course(b.getAttribute('data-c'), b.getAttribute('data-k')); }); });
  }).catch(fail);
}
function beauty() {
  load('beauty').then(function (B) {
    var c = B.counts || {}, rows = B.entries || [];
    body.innerHTML = '<p class="pd-q">\u201c' + esc(B.question) + '\u201d</p><p class="pd-meta">' + (c.total || 0) + ' entries \u00b7 ' + (c.open || 0) + ' open \u00b7 ' + (c.ready || 0