<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Memeroot Catalog · signed components, downloadable in your browser</title>
<style>
:root {
  --bg: #0a0d11; --bg-deep: #06080b; --bg-card: #12161c; --bg-soft: #1a1f26;
  --bg-card-hover: #161c24;
  --ink: #d8dde4; --ink-soft: #a8b0bb; --ink-mute: #5e6770;
  --accent: #d4a574; --accent-2: #8fa9c4; --accent-3: #c97a7a;
  --verify: #7eb87e; --fail: #c97a7a;
  --rule: #232930; --rule-soft: #181c22;
  --mono: 'JetBrains Mono', 'Consolas', 'Menlo', monospace;
  --serif: 'Cormorant Garamond', 'Georgia', serif;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--bg-deep); color: var(--ink); font-family: var(--serif); line-height: 1.55; overflow-x: hidden; }
body::before { content: ''; position: fixed; inset: 0; background: radial-gradient(circle at 20% 30%, rgba(143, 169, 196, 0.04) 0%, transparent 30%), radial-gradient(circle at 80% 70%, rgba(212, 165, 116, 0.03) 0%, transparent 35%); z-index: -2; }
body::after { content: ''; position: fixed; inset: 0; background-image: radial-gradient(circle at center, rgba(143, 169, 196, 0.08) 1px, transparent 1.5px); background-size: 80px 80px; z-index: -1; opacity: .3; pointer-events: none; }
body { padding: 40px 24px 80px; max-width: 1280px; margin: 0 auto; }

header { margin-bottom: 30px; max-width: 980px; }
.eyebrow { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .3em; color: var(--accent-2); margin-bottom: 12px; opacity: .8; }
h1 { font-family: var(--serif); font-weight: 400; font-size: 44px; line-height: 1.05; margin: 0 0 14px; color: var(--accent); letter-spacing: -.01em; font-style: italic; }
h1 .roman { font-style: normal; color: var(--ink); }
.lede { font-size: 17px; color: var(--ink-soft); margin: 0 0 22px; max-width: 720px; }
.lede em { color: var(--accent-2); }

.publisher-bar { display: flex; align-items: center; gap: 12px; padding: 10px 16px; background: var(--bg-card); border: 1px solid var(--rule); border-left: 3px solid var(--verify); font-family: var(--mono); font-size: 11px; margin-bottom: 12px; flex-wrap: wrap; cursor: pointer; transition: background .12s ease; }

.publisher-roster { background: var(--bg-card); border: 1px solid var(--rule); padding: 14px 16px; margin-bottom: 20px; }
.publisher-roster-label { font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: .25em; color: var(--ink-mute); margin-bottom: 10px; }
.publisher-roster-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px; }
.publisher-card { background: var(--bg-deep); border: 1px solid var(--rule); border-left: 2px solid var(--accent-2); padding: 8px 12px; font-family: var(--mono); font-size: 10px; line-height: 1.55; }
.publisher-card-mark { color: var(--verify); font-size: 9px; display: inline-block; margin-right: 4px; vertical-align: 1px; }
.publisher-card-name { color: var(--accent); font-family: var(--serif); font-style: italic; font-size: 13px; display: inline; }
.publisher-card-fp { color: var(--ink-mute); margin-top: 2px; }
.publisher-card-count { color: var(--accent-2); font-size: 9px; text-transform: uppercase; letter-spacing: .15em; margin-top: 4px; }

.card-publisher-badge { display: inline-flex; align-items: center; gap: 5px; font-family: var(--mono); font-size: 9px; color: var(--ink-mute); margin-top: 8px; padding: 4px 8px; background: var(--bg-deep); border-left: 2px solid var(--accent-2); }
.card-publisher-badge .badge-mark { color: var(--accent-2); }
.card-publisher-badge .badge-name { color: var(--accent); font-style: italic; font-family: var(--serif); font-size: 11px; }
.card-publisher-badge .badge-fp { color: var(--ink-mute); }
.publisher-bar:hover { background: var(--bg-card-hover); }
.publisher-bar .mark { color: var(--verify); font-size: 14px; font-weight: bold; }
.publisher-bar .label { color: var(--ink-mute); text-transform: uppercase; letter-spacing: .15em; font-size: 10px; }
.publisher-bar .name { color: var(--accent); font-family: var(--serif); font-size: 14px; font-style: italic; }
.publisher-bar .fp { color: var(--ink-mute); }
.publisher-bar .status { color: var(--verify); margin-left: auto; }
.publisher-bar .status.bad { color: var(--fail); }

.index-bar { display: flex; align-items: center; gap: 20px; padding: 10px 16px; background: var(--bg-card); border: 1px solid var(--rule); border-left: 3px solid var(--accent-2); font-family: var(--mono); font-size: 11px; margin-bottom: 28px; flex-wrap: wrap; }
.index-check { display: flex; align-items: center; gap: 8px; }
.index-check .mark { font-size: 14px; font-weight: bold; min-width: 18px; }
.index-check .mark.unknown { color: var(--ink-mute); }
.index-check .mark.ok { color: var(--verify); }
.index-check .mark.bad { color: var(--fail); }
.index-check .check-label { color: var(--ink-mute); text-transform: uppercase; letter-spacing: .15em; font-size: 10px; }
.index-check .check-status { color: var(--ink); }
.index-actions { margin-left: auto; display: flex; gap: 8px; }
.index-action-btn { background: transparent; border: 1px solid var(--rule); color: var(--ink-soft); padding: 6px 12px; font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: .15em; cursor: pointer; transition: all .12s ease; }
.index-action-btn:hover { border-color: var(--accent-3); color: var(--accent-3); }
.index-action-btn.restore { border-color: var(--verify); color: var(--verify); }
.index-action-btn.restore:hover { background: var(--verify); color: var(--bg-deep); }
.index-tamper-note { font-family: var(--serif); font-style: italic; font-size: 13px; color: var(--accent-3); margin-top: 6px; padding: 8px 12px; background: rgba(201, 122, 122, 0.08); border-left: 2px solid var(--accent-3); display: none; }
.index-tamper-note.shown { display: block; }

.controls { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; margin-bottom: 32px; padding: 12px 14px; background: var(--bg-card); border: 1px solid var(--rule); }
.search-input { flex: 1; min-width: 220px; background: var(--bg-deep); border: 1px solid var(--rule); color: var(--ink); padding: 9px 12px; font-family: var(--mono); font-size: 12px; outline: none; transition: border-color .15s ease; }
.search-input:focus { border-color: var(--accent); }
.search-input::placeholder { color: var(--ink-mute); }
.filter-tabs { display: flex; gap: 2px; flex-wrap: wrap; }
.filter-tab { background: transparent; border: 1px solid var(--rule); color: var(--ink-soft); padding: 8px 14px; font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .15em; cursor: pointer; transition: all .12s ease; }
.filter-tab:hover { border-color: var(--accent); color: var(--accent); }
.filter-tab.active { background: var(--accent); color: var(--bg-deep); border-color: var(--accent); }
.filter-count { color: var(--ink-mute); font-size: 10px; margin-left: 4px; }
.filter-tab.active .filter-count { color: var(--bg-deep); opacity: .7; }

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; }
.card { background: var(--bg-card); border: 1px solid var(--rule); padding: 18px 20px 14px; transition: all .15s ease; position: relative; display: flex; flex-direction: column; min-height: 220px; }
.card:hover { background: var(--bg-card-hover); border-color: var(--rule-soft); transform: translateY(-1px); }
.card.tour { border-left: 3px solid var(--accent); }
.card.tour-commercial { border-left: 3px solid var(--accent-3); }
.card.skill { border-left: 3px solid var(--verify); }
.card.skill-fork { border-left: 3px solid var(--verify); border-left-style: dashed; }
.card.viz { border-left: 3px solid var(--accent-2); }
.card.foundation { border-left: 3px solid var(--ink); }
.card.verified { box-shadow: inset 0 0 0 1px rgba(126, 184, 126, 0.25); }
.card.hidden { display: none; }

.card-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 10px; cursor: pointer; }
.card-icon { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-family: var(--serif); font-size: 18px; background: var(--bg-soft); border: 1px solid var(--rule); color: var(--accent); }
.card.tour-commercial .card-icon { color: var(--accent-3); border-color: rgba(201, 122, 122, 0.3); }
.card.skill .card-icon, .card.skill-fork .card-icon { color: var(--verify); border-color: rgba(126, 184, 126, 0.3); }
.card.viz .card-icon { color: var(--accent-2); border-color: rgba(143, 169, 196, 0.3); }
.card.foundation .card-icon { color: var(--ink); border-color: var(--rule); }
.card-title-block { flex: 1; }
.card-tag { font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: .2em; color: var(--ink-mute); margin-bottom: 4px; }
.card-title { font-family: var(--serif); font-size: 18px; font-weight: 500; color: var(--ink); margin: 0; line-height: 1.25; }
.card.tour-commercial .card-title { color: var(--accent-3); }

.card-tagline { color: var(--ink-soft); font-size: 13px; line-height: 1.55; margin: 4px 0 12px; cursor: pointer; }

.card-tags { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 10px; }
.card-tag-pill { font-family: var(--mono); font-size: 9px; background: var(--bg-soft); padding: 2px 7px; color: var(--ink-mute); border: 1px solid var(--rule-soft); }

.card-actions { display: flex; gap: 6px; align-items: center; margin-top: auto; padding-top: 10px; border-top: 1px dashed var(--rule); }
.card-action-btn { background: transparent; border: 1px solid var(--accent); color: var(--accent); font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .15em; padding: 7px 12px; cursor: pointer; transition: all .12s ease; flex: 1; text-align: center; text-decoration: none; display: inline-block; }
.card-action-btn:hover { background: var(--accent); color: var(--bg-deep); }
.card-action-btn.secondary { border-color: var(--rule); color: var(--ink-soft); flex: 0 0 auto; padding: 7px 10px; }
.card-action-btn.secondary:hover { border-color: var(--accent-2); color: var(--accent-2); background: transparent; }
.card-action-btn.success { border-color: var(--verify); color: var(--verify); background: transparent; }
.card-action-btn.copied { background: var(--verify); color: var(--bg-deep); }

.card-sig-mini { display: flex; align-items: center; gap: 4px; padding-top: 6px; font-family: var(--mono); font-size: 9px; color: var(--ink-mute); }
.card-sig-mini .mark { font-size: 11px; }
.card-sig-mini .mark.unknown { color: var(--ink-mute); }
.card-sig-mini .mark.ok { color: var(--verify); }
.card-sig-mini .mark.bad { color: var(--fail); }
.card-size { margin-left: auto; }

/* Modal */
.modal-backdrop { position: fixed; inset: 0; background: rgba(6, 8, 11, 0.78); display: none; z-index: 100; align-items: center; justify-content: center; padding: 20px; }
.modal-backdrop.shown { display: flex; }
.modal { background: var(--bg-card); border: 1px solid var(--accent); max-width: 680px; width: 100%; max-height: 88vh; overflow-y: auto; padding: 28px 32px; position: relative; }
.modal-close { position: absolute; top: 14px; right: 18px; background: transparent; border: none; color: var(--ink-mute); font-size: 24px; cursor: pointer; padding: 0; line-height: 1; }
.modal-close:hover { color: var(--accent); }
.modal-eyebrow { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .25em; color: var(--ink-mute); margin-bottom: 10px; }
.modal h2 { font-family: var(--serif); font-weight: 400; font-size: 26px; color: var(--accent); margin: 0 0 12px; font-style: italic; letter-spacing: -.005em; }
.modal h2.commercial { color: var(--accent-3); }
.modal-tagline { color: var(--ink-soft); font-size: 15px; margin-bottom: 16px; line-height: 1.6; }
.modal-tags { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 18px; }

.modal-section { margin: 18px 0; }
.modal-section h4 { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .2em; color: var(--ink-mute); margin: 0 0 8px; }
.modal-section .value { font-family: var(--mono); font-size: 11px; color: var(--ink); word-break: break-all; }

.modal-sig-block { background: var(--bg-deep); border: 1px solid var(--rule); border-left: 3px solid var(--ink-mute); padding: 14px 16px; margin: 18px 0; }
.modal-sig-block.ok { border-left-color: var(--verify); }
.modal-sig-block.bad { border-left-color: var(--fail); }
.modal-sig-block .sig-line { font-family: var(--mono); font-size: 11px; margin: 4px 0; color: var(--ink-soft); }
.modal-sig-block .sig-label { color: var(--ink-mute); }
.modal-sig-block .sig-mark { font-size: 14px; font-weight: bold; }
.modal-sig-block.ok .sig-mark { color: var(--verify); }
.modal-sig-block.bad .sig-mark { color: var(--fail); }
.modal-sig-block .sig-mark.unknown { color: var(--ink-mute); }

.skill-preview { background: var(--bg-deep); border: 1px solid var(--rule); border-left: 3px solid var(--verify); padding: 14px 16px; margin: 16px 0; font-family: var(--mono); font-size: 11px; line-height: 1.55; max-height: 220px; overflow-y: auto; white-space: pre-wrap; color: var(--ink-soft); }

.btn-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
button.action, a.action { background: transparent; border: 1px solid var(--rule); color: var(--ink); font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .15em; padding: 8px 14px; cursor: pointer; transition: all .12s ease; text-decoration: none; display: inline-block; }
button.action:hover, a.action:hover { border-color: var(--accent); color: var(--accent); }
button.action.primary, a.action.primary { border-color: var(--accent); color: var(--accent); }
button.action.primary:hover, a.action.primary:hover { background: var(--accent); color: var(--bg-deep); }
button.action.success { border-color: var(--verify); color: var(--verify); }
button.action.success:hover { background: var(--verify); color: var(--bg-deep); }
button.action.danger:hover { border-color: var(--fail); color: var(--fail); }

.fork-link { font-family: var(--mono); font-size: 11px; color: var(--accent-2); margin-bottom: 14px; padding: 8px 12px; background: var(--bg-soft); border-left: 2px solid var(--accent-2); }
.fork-link::before { content: '↳ '; color: var(--ink-mute); }

.toast { display: inline-block; margin-left: 10px; font-family: var(--mono); font-size: 10px; color: var(--ink-mute); opacity: 0; transition: opacity .3s ease; }
.toast.show { opacity: 1; }
.toast.success { color: var(--verify); }
.toast.error { color: var(--fail); }

.empty { text-align: center; padding: 60px 20px; color: var(--ink-mute); font-style: italic; }
.empty.hidden { display: none; }

footer { margin-top: 60px; padding-top: 24px; border-top: 1px solid var(--rule); font-family: var(--mono); font-size: 10px; color: var(--ink-mute); text-transform: uppercase; letter-spacing: .2em; line-height: 1.8; }
footer p { margin: 2px 0; }
footer .delivery-note { color: var(--accent-2); margin-top: 12px; text-transform: none; letter-spacing: 0; font-family: var(--serif); font-style: italic; font-size: 13px; }

@media (max-width: 700px) {
  h1 { font-size: 32px; }
  body { padding: 24px 14px 60px; }
  .grid { grid-template-columns: 1fr; }
  .controls { flex-direction: column; align-items: stretch; }
}
</style>
</head>
<body>

<header>
  <div class="eyebrow">Memeroot · catalog · 27 signed components · 3 publishers · curator-signed index</div>
  <h1>The <em>catalog</em>.</h1>
  <p class="lede">Each component is signed individually by <em>its own publisher</em>. The catalog index — the set of which components are listed, their hashes, and which publisher signed which — is signed by the <em>catalog curator</em>. Three layers: tamper an entry's content and its publisher's signature breaks; reassign an entry to a different publisher and the manifest breaks; add, remove, or swap an entry from the listing and the manifest signature breaks.</p>

  <div class="publisher-bar" id="pubBar">
    <span class="mark" id="pubMark">·</span>
    <span class="label">catalog curated by</span>
    <span class="name">Memeroot Ltd · Catalog Curator</span>
    <span class="fp">fp da4d8e4d5cb5238d</span>
    <span class="status" id="pubStatus">click to re-verify the catalog</span>
  </div>

  <div class="publisher-roster">
    <div class="publisher-roster-label">Publishers contributing to this catalog</div>
    <div class="publisher-roster-grid">
      <div class="publisher-card" data-fp="54f4b2daa1046610">
        <div class="publisher-card-mark">●</div>
        <div class="publisher-card-name">Beta Capital Partners · Compliance Publisher · (demo identity)</div>
        <div class="publisher-card-fp">fp 54f4b2daa1046610</div>
        <div class="publisher-card-count">1 entries</div>
      </div>
      <div class="publisher-card" data-fp="7da98308ba8da466">
        <div class="publisher-card-mark">●</div>
        <div class="publisher-card-name">Memeroot Ltd · Rob Anderson · Founder</div>
        <div class="publisher-card-fp">fp 7da98308ba8da466</div>
        <div class="publisher-card-count">25 entries</div>
      </div>
      <div class="publisher-card" data-fp="ba0e26bf408c1876">
        <div class="publisher-card-mark">●</div>
        <div class="publisher-card-name">Acme Health Inc · Compliance Publisher · (demo identity)</div>
        <div class="publisher-card-fp">fp ba0e26bf408c1876</div>
        <div class="publisher-card-count">1 entries</div>
      </div>
    </div>
  </div>

  <div class="index-bar" id="indexBar">
    <div class="index-check" id="indexCheckManifest">
      <span class="mark unknown" id="indexMarkManifest">·</span>
      <span class="check-label">catalog index</span>
      <span class="check-status" id="indexStatusManifest">manifest of 27 entries · dcb8e7d0db1075c1…</span>
    </div>
    <div class="index-check" id="indexCheckEntries">
      <span class="mark unknown" id="indexMarkEntries">·</span>
      <span class="check-label">per-entry signatures</span>
      <span class="check-status" id="indexStatusEntries">27 entries to verify</span>
    </div>
    <div class="index-actions">
      <button class="index-action-btn" id="btnSimulateRemove">Test index tampering · remove entry</button>
      <button class="index-action-btn" id="btnRestoreIndex" style="display:none">Restore catalog</button>
    </div>
  </div>
</header>

<div class="controls">
  <input type="text" class="search-input" id="searchInput" placeholder="search components — name, tag, vertical…" autocomplete="off"/>
  <div class="filter-tabs" id="filterTabs">
    <button class="filter-tab active" data-cat="all">all <span class="filter-count" id="count-all"></span></button>
    <button class="filter-tab" data-cat="tour">tours <span class="filter-count" id="count-tour"></span></button>
    <button class="filter-tab" data-cat="skill">skills <span class="filter-count" id="count-skill"></span></button>
    <button class="filter-tab" data-cat="viz">visualizations <span class="filter-count" id="count-viz"></span></button>
    <button class="filter-tab" data-cat="foundation">foundation <span class="filter-count" id="count-foundation"></span></button>
  </div>
</div>

<div class="grid" id="grid">
  <div class="card foundation" data-id="doc-ops-playbook" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">◐</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">Operations Playbook · canonical reference</h3>
      </div>
    </div>
    <p class="card-tagline">MEMEROOT-OPS-PLAYBOOK-2026-001 — full instruction set for taking Memeroot forward at production quality. Ten sections covering substrate philosophy, dev environment setup, skills inventory, canvas operations, CLI workflows, tool stack, quality discipline, onboarding, production patterns, and roadmap. Self-contained HTML in the Memeroot style; print-friendly. The setup guide a new hire reads on Day 1.</p>
    <div class="card-tags"><span class="card-tag-pill">playbook</span><span class="card-tag-pill">reference</span><span class="card-tag-pill">setup</span><span class="card-tag-pill">onboarding</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="MEMEROOT-OPS-PLAYBOOK-2026-001.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">64 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="doc-composable-xml-arch" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">⬢</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">Composable XML Architecture · MEMEROOT-ARCH-2026-002</h3>
      </div>
    </div>
    <p class="card-tagline">The structural discipline beneath everything. Six fundamental block kinds (schema · script · template · data · process · projection) with strict separation — no block kind contains elements of another. TABLE_SPECIFICATIONS is the universal projecting spine: any block projects into it; the UNION ALL is the unified addressable view. Direct XML analogue of the MBI_SCRIPT_AS_TABLE_SPEC_V production pattern. Ships ARCHITECTURE.html (12 sections, ~60KB), 8 worked blocks from Rob's real 25-year practice, 6 projection XSL stylesheets, the compose driver, and a 77-row reference spine that demonstrates the self-referencing graph.</p>
    <div class="card-tags"><span class="card-tag-pill">foundation</span><span class="card-tag-pill">XML</span><span class="card-tag-pill">XSL</span><span class="card-tag-pill">spine</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-composable-xml.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">46 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="doc-composable-xml-architecture-html" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">◐</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">Composable XML Architecture · document only</h3>
      </div>
    </div>
    <p class="card-tagline">Just the ARCHITECTURE.html document itself. Open directly in browser for the 12-section canonical reference: thesis, five axioms, six block kinds, strict separation rule, the spine, projections, self-referencing graph, worked example (77 rows), composition into the unit, file inventory, integration with the existing Memeroot stack, roadmap. Print-friendly. For the zip with all blocks and projections, see doc-composable-xml-arch.</p>
    <div class="card-tags"><span class="card-tag-pill">foundation</span><span class="card-tag-pill">reference</span><span class="card-tag-pill">document</span><span class="card-tag-pill">canonical</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="composable-xml-ARCHITECTURE.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">48 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="doc-composable-substrate-2026" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">⬢</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">Composable Substrate · MEMEROOT-SUB-COMPOSABLE-2026-001</h3>
      </div>
    </div>
    <p class="card-tagline">Canonical eight-block-kind substrate. Data · schema · script · process · type · view · identity · address — each in its own XML namespace, absolutely zero crossover. Each block projects to the universal TABLE_SPECIFICATIONS spine via its own XSL stylesheet; the spine is computed by federation, never stored. Ships reference.html (40KB architectural reference in dark forensic style), 8 example block instances, 8 per-kind projection XSL stylesheets + 8 per-kind render stylesheets, the spine projection-shape declaration, the universal absorbing stylesheet, the composition document, a pure-Node compiler, and an interactive spine viewer rendering all 43 projected rows with per-kind filtering. Direct evolution of doc-composable-xml-arch (which had 6 kinds): adds type, identity, and address as first-class kinds; tightens the no-crossover rule; mirrors the production MBI_SCRIPT_AS_TABLE_SPEC_V row shape exactly.</p>
    <div class="card-tags"><span class="card-tag-pill">foundation</span><span class="card-tag-pill">XML</span><span class="card-tag-pill">XSL</span><span class="card-tag-pill">spine</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-composable-substrate.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">53 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="doc-composable-substrate-reference-html" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">◐</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">Composable Substrate · architectural reference document</h3>
      </div>
    </div>
    <p class="card-tagline">Just the MEMEROOT-SUB-COMPOSABLE-2026-001 reference document. Open directly in browser for the eight-section canonical reference: thesis (zero crossover) · the eight block kinds · the spine as universal absorber · per-kind XSL projection pattern · composition and compilation · self-describing recursion · MPP and independent processes · the deliverable shape. Dark forensic style with sidebar navigation. For the zip with all blocks, XSLs, compiler, and spine viewer, see doc-composable-substrate-2026.</p>
    <div class="card-tags"><span class="card-tag-pill">foundation</span><span class="card-tag-pill">reference</span><span class="card-tag-pill">document</span><span class="card-tag-pill">canonical</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="MEMEROOT-SUB-COMPOSABLE-2026-001.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">40 KB</span>
    </div>
  </div>
  <div class="card visualization" data-id="viz-spine-viewer" data-cat="visualization">
    <div class="card-head">
      <div class="card-icon">◑</div>
      <div class="card-title-block">
        <div class="card-tag">visualization</div>
        <h3 class="card-title">Spine viewer · the universal absorbed view</h3>
      </div>
    </div>
    <p class="card-tagline">Interactive viewer for the compiled spine output. Forty-three rows from eight independent blocks, projected through their own XSL stylesheets into the unified TABLE_SPECIFICATIONS shape. Filter by origin block (data/schema/script/process/type/view/identity/address); search across rows; see how each kind tags its rows via spec-source. Shows the no-crossover principle in action: every row identifies its origin block; nothing carries content from any other block. Companion to MEMEROOT-SUB-COMPOSABLE-2026-001.</p>
    <div class="card-tags"><span class="card-tag-pill">visualization</span><span class="card-tag-pill">interactive</span><span class="card-tag-pill">spine</span><span class="card-tag-pill">viewer</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-spine-viewer.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">37 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="mr-canvas-v0.8" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">M</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">MR Canvas v0.8</h3>
      </div>
    </div>
    <p class="card-tagline">The substrate. Single-file HTML that boots into a Memeroot canvas with drop zone, region tree, and reader-mediated rendering.</p>
    <div class="card-tags"><span class="card-tag-pill">canvas</span><span class="card-tag-pill">substrate</span><span class="card-tag-pill">core</span><span class="card-tag-pill">self-contained</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="MR-CANVAS-v0.8.html" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">49 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="memeroot-cli" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">⌘</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">memeroot-cli</h3>
      </div>
    </div>
    <p class="card-tagline">Programmatic bridge between Claude Code and the canvas. Three commands: validate, bundle, package. Closes the loop from &quot;Claude Code produces XML&quot; to &quot;single HTML packet the user opens with content auto-loaded&quot;. Pure Node.js, no runtime dependencies.</p>
    <div class="card-tags"><span class="card-tag-pill">cli</span><span class="card-tag-pill">bridge</span><span class="card-tag-pill">tool</span><span class="card-tag-pill">claude-code</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-cli-showcase.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">24 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="iframe-region-builder" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">◧</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">iframe-region builder</h3>
      </div>
    </div>
    <p class="card-tagline">Standalone tool for authoring iframe-region XML. Live form, live iframe preview with sandboxing, syntax-highlighted XML output, copy/download/validate. Three presets (dashboard, doc embed, strict sandbox).</p>
    <div class="card-tags"><span class="card-tag-pill">tool</span><span class="card-tag-pill">iframe</span><span class="card-tag-pill">builder</span><span class="card-tag-pill">authoring</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="iframe-region-builder.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">34 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="feature-svg-region-renderer" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">◇</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">svg-region renderer · canvas feature</h3>
      </div>
    </div>
    <p class="card-tagline">Canvas feature that registers an svg-region reader. Renders embedded SVG inline (or sandboxed), verifies captured-hash via WebCrypto SHA-256, strips &lt;script&gt;, &lt;foreignObject&gt;, on* handlers, and external xlink:href by default. Three sanitization modes (strict, loose, none).</p>
    <div class="card-tags"><span class="card-tag-pill">feature</span><span class="card-tag-pill">canvas</span><span class="card-tag-pill">svg</span><span class="card-tag-pill">renderer</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="feature-svg-region-renderer.xml" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">8 KB</span>
    </div>
  </div>
  <div class="card foundation" data-id="feature-iframe-region-renderer" data-cat="foundation">
    <div class="card-head">
      <div class="card-icon">◇</div>
      <div class="card-title-block">
        <div class="card-tag">foundation</div>
        <h3 class="card-title">iframe-region renderer · canvas feature</h3>
      </div>
    </div>
    <p class="card-tagline">Canvas feature that registers an iframe-region reader. Renders embedded HTML snapshots via iframe srcdoc (or live URL via src), verifies captured-hash via WebCrypto SHA-256, surfaces full metadata above the rendered iframe.</p>
    <div class="card-tags"><span class="card-tag-pill">feature</span><span class="card-tag-pill">canvas</span><span class="card-tag-pill">iframe</span><span class="card-tag-pill">renderer</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="feature-iframe-region-renderer.xml" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">8 KB</span>
    </div>
  </div>
  <div class="card tour" data-id="stream-research-assistant" data-cat="tour">
    <div class="card-head">
      <div class="card-icon">🔍</div>
      <div class="card-title-block">
        <div class="card-tag">tour</div>
        <h3 class="card-title">Research Assistant</h3>
      </div>
    </div>
    <p class="card-tagline">Eight chunks build you a working AI research loop: signed question, wired endpoint, content-addressed response, forked draft, critic endpoint, bundled session.</p>
    <div class="card-tags"><span class="card-tag-pill">stream</span><span class="card-tag-pill">AI</span><span class="card-tag-pill">invoker</span><span class="card-tag-pill">compose</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-research-assistant.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">87 KB</span>
    </div>
  </div>
  <div class="card tour" data-id="stream-oracle-sql-free" data-cat="tour">
    <div class="card-head">
      <div class="card-icon">⚡</div>
      <div class="card-title-block">
        <div class="card-tag">tour</div>
        <h3 class="card-title">Oracle SQL Free</h3>
      </div>
    </div>
    <p class="card-tagline">Five chunks: AI proposes SQL, you run it on Oracle Live SQL externally, capture results as signed regions. Canvas-as-workspace, external-as-engine.</p>
    <div class="card-tags"><span class="card-tag-pill">stream</span><span class="card-tag-pill">integration</span><span class="card-tag-pill">SQL</span><span class="card-tag-pill">external-service</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-oracle-sql-free.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">84 KB</span>
    </div>
  </div>
  <div class="card tour" data-id="stream-interface-from-xml" data-cat="tour">
    <div class="card-head">
      <div class="card-icon">◫</div>
      <div class="card-title-block">
        <div class="card-tag">tour</div>
        <h3 class="card-title">Interface from XML</h3>
      </div>
    </div>
    <p class="card-tagline">Seven chunks demonstrating that interfaces are data: declarative workflow + XSL stylesheet + signed completion regions. No application code.</p>
    <div class="card-tags"><span class="card-tag-pill">stream</span><span class="card-tag-pill">declarative</span><span class="card-tag-pill">XSL</span><span class="card-tag-pill">workflow</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-interface-from-xml.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">86 KB</span>
    </div>
  </div>
  <div class="card tour" data-id="stream-page-build" data-cat="tour">
    <div class="card-head">
      <div class="card-icon">◊</div>
      <div class="card-title-block">
        <div class="card-tag">tour</div>
        <h3 class="card-title">Page Build</h3>
      </div>
    </div>
    <p class="card-tagline">Six chunks from authored content to a self-contained HTML page that is itself a canvas. The recursive close: canvases produce canvases.</p>
    <div class="card-tags"><span class="card-tag-pill">stream</span><span class="card-tag-pill">publishing</span><span class="card-tag-pill">recursive</span><span class="card-tag-pill">bundle</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-page-build.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">84 KB</span>
    </div>
  </div>
  <div class="card tour" data-id="stream-knowledge-tree" data-cat="tour">
    <div class="card-head">
      <div class="card-icon">⌬</div>
      <div class="card-title-block">
        <div class="card-tag">tour</div>
        <h3 class="card-title">Knowledge Tree</h3>
      </div>
    </div>
    <p class="card-tagline">Six chunks exercising the compose feature: include, fork, diff. Atomic sections become composable books; forks carry cryptographic lineage.</p>
    <div class="card-tags"><span class="card-tag-pill">stream</span><span class="card-tag-pill">compose</span><span class="card-tag-pill">fork</span><span class="card-tag-pill">lineage</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-knowledge-tree.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">83 KB</span>
    </div>
  </div>
  <div class="card tour-commercial" data-id="stream-compliance-audit-trail" data-cat="tour">
    <div class="card-head">
      <div class="card-icon">✓</div>
      <div class="card-title-block">
        <div class="card-tag">tour</div>
        <h3 class="card-title">Compliance Audit Trail</h3>
      </div>
    </div>
    <p class="card-tagline">Six chunks producing a SOX-style audit packet with multi-party sign-offs. External auditor opens bundle.html and verifies in any browser. Replaces the audit-trail layer of GRC platforms.</p>
    <div class="card-tags"><span class="card-tag-pill">stream</span><span class="card-tag-pill">SOX</span><span class="card-tag-pill">compliance</span><span class="card-tag-pill">commercial</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-compliance-audit-trail.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">88 KB</span>
    </div>
  </div>
  <div class="card tour-commercial" data-id="stream-skill-author" data-cat="tour">
    <div class="card-head">
      <div class="card-icon">⚒</div>
      <div class="card-title-block">
        <div class="card-tag">tour</div>
        <h3 class="card-title">Skill Author</h3>
      </div>
    </div>
    <p class="card-tagline">Six chunks for authoring Claude Code skills as signed transferable artifacts. SKILL.md with cryptographic provenance, forkable with lineage.</p>
    <div class="card-tags"><span class="card-tag-pill">stream</span><span class="card-tag-pill">skill</span><span class="card-tag-pill">Claude Code</span><span class="card-tag-pill">ecosystem</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-skill-author.zip" download onclick="event.stopPropagation()">↓ Download</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">88 KB</span>
    </div>
  </div>
  <div class="card skill" data-id="skillpack-regulated-document-author" data-cat="skill">
    <div class="card-head">
      <div class="card-icon">◐</div>
      <div class="card-title-block">
        <div class="card-tag">skill</div>
        <h3 class="card-title">regulated-document-author · production pack</h3>
      </div>
    </div>
    <p class="card-tagline">Production Claude Code skill pack: substantive SKILL.md (10.7 KB), 5 XML templates (SOX control, TOD, TOE, IRB protocol, audit finding, management letter), pre-publication checklist, worked example. 9 files signed by author and counter-signed by reviewer.</p>
    <div class="card-tags"><span class="card-tag-pill">skill</span><span class="card-tag-pill">production</span><span class="card-tag-pill">SOX</span><span class="card-tag-pill">FDA</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="regulated-document-author-bundle.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">26 KB</span>
    </div>
  </div>
  <div class="card skill" data-id="skillpack-memeroot-bridge" data-cat="skill">
    <div class="card-head">
      <div class="card-icon">⤞</div>
      <div class="card-title-block">
        <div class="card-tag">skill</div>
        <h3 class="card-title">memeroot-bridge · production pack</h3>
      </div>
    </div>
    <p class="card-tagline">Production Claude Code skill pack teaching Claude to produce Memeroot-shaped output. Substantive SKILL.md, 7 region templates (note, section, decision, task, reference, iframe-region, svg-region, workspace), 4 worked examples including iframe-region dashboard and svg-region chart with captured-hash, composition pattern with regulated-document-author. 13 files signed by author and counter-signed by reviewer.</p>
    <div class="card-tags"><span class="card-tag-pill">skill</span><span class="card-tag-pill">production</span><span class="card-tag-pill">memeroot</span><span class="card-tag-pill">bridge</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="memeroot-bridge-bundle.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">25 KB</span>
    </div>
  </div>
  <div class="card skill" data-id="skillpack-iframe-snapshot-author" data-cat="skill">
    <div class="card-head">
      <div class="card-icon">◧</div>
      <div class="card-title-block">
        <div class="card-tag">skill</div>
        <h3 class="card-title">iframe-snapshot-author · production pack</h3>
      </div>
    </div>
    <p class="card-tagline">Production Claude Code skill pack for capturing external HTML as audit-grade evidence. Fetches URLs (or reads local files) via the bash tool, computes SHA-256, produces ready-to-sign iframe-region with snapshot embedded inline. Substantive SKILL.md, Node.js capture script + shell variant, template, two worked examples. 6 files signed by author and counter-signed by reviewer.</p>
    <div class="card-tags"><span class="card-tag-pill">skill</span><span class="card-tag-pill">production</span><span class="card-tag-pill">iframe</span><span class="card-tag-pill">snapshot</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="iframe-snapshot-author-bundle.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">15 KB</span>
    </div>
  </div>
  <div class="card skill-fork" data-id="skill-regulated-doc-healthcare" data-cat="skill">
    <div class="card-head">
      <div class="card-icon">◐</div>
      <div class="card-title-block">
        <div class="card-tag">skill</div>
        <h3 class="card-title">regulated-document-author (healthcare) · concept</h3>
      </div>
    </div>
    <p class="card-tagline">Conceptual fork demonstrating healthcare specialization — FDA 21 CFR Part 11, HIPAA, ICH GCP, GAMP 5 priority. Lineage preserved via fork-source reference.</p>
    <div class="card-tags"><span class="card-tag-pill">skill</span><span class="card-tag-pill">fork</span><span class="card-tag-pill">healthcare</span><span class="card-tag-pill">HIPAA</span></div>
    <div class="card-publisher-badge" title="Acme Health Inc · Compliance Publisher · (demo identity)">
      <span class="badge-mark">●</span>
      <span class="badge-name">Acme Health Inc</span>
      <span class="badge-fp">fp ba0e26bf408c…</span>
    </div>
    <div class="card-actions">
      <button class="card-action-btn primary">Copy SKILL.md</button>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">3 KB</span>
    </div>
  </div>
  <div class="card skill-fork" data-id="skill-regulated-doc-finance" data-cat="skill">
    <div class="card-head">
      <div class="card-icon">◐</div>
      <div class="card-title-block">
        <div class="card-tag">skill</div>
        <h3 class="card-title">regulated-document-author (finance) · concept</h3>
      </div>
    </div>
    <p class="card-tagline">Conceptual fork demonstrating financial-services specialization — SOX, Basel III, MAR, FINRA, Dodd-Frank, AML/KYC priority. Lineage preserved via fork-source reference.</p>
    <div class="card-tags"><span class="card-tag-pill">skill</span><span class="card-tag-pill">fork</span><span class="card-tag-pill">finance</span><span class="card-tag-pill">SOX</span></div>
    <div class="card-publisher-badge" title="Beta Capital Partners · Compliance Publisher · (demo identity)">
      <span class="badge-mark">●</span>
      <span class="badge-name">Beta Capital Partners</span>
      <span class="badge-fp">fp 54f4b2daa104…</span>
    </div>
    <div class="card-actions">
      <button class="card-action-btn primary">Copy SKILL.md</button>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">3 KB</span>
    </div>
  </div>
  <div class="card viz" data-id="viz-iframe-region-demo-packet" data-cat="viz">
    <div class="card-head">
      <div class="card-icon">◫</div>
      <div class="card-title-block">
        <div class="card-tag">viz</div>
        <h3 class="card-title">iframe-region demo packet</h3>
      </div>
    </div>
    <p class="card-tagline">Single self-contained HTML demonstrating the iframe-region chain. Two signed captured iframe-regions (operations dashboard + policy document), canvas + renderer feature bundled inline, demo publisher attribution + verify-all button. Auto-verifies on open: publisher signatures + captured-hash — all locally via WebCrypto.</p>
    <div class="card-tags"><span class="card-tag-pill">demo</span><span class="card-tag-pill">iframe-region</span><span class="card-tag-pill">signed</span><span class="card-tag-pill">self-contained</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="iframe-region-demo-packet.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">65 KB</span>
    </div>
  </div>
  <div class="card viz" data-id="viz-mixed-demo-packet" data-cat="viz">
    <div class="card-head">
      <div class="card-icon">◫</div>
      <div class="card-title-block">
        <div class="card-tag">viz</div>
        <h3 class="card-title">iframe + svg demo packet</h3>
      </div>
    </div>
    <p class="card-tagline">Single self-contained HTML with three signed regions: two iframe-regions (dashboard + policy) and one svg-region (chart). Both renderer features bundled. Demonstrates the captured-hash + sanitization model across two region kinds — and the federation pattern of pluggable renderers loaded from features.</p>
    <div class="card-tags"><span class="card-tag-pill">demo</span><span class="card-tag-pill">iframe-region</span><span class="card-tag-pill">svg-region</span><span class="card-tag-pill">signed</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="iframe-and-svg-demo-packet.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">78 KB</span>
    </div>
  </div>
  <div class="card viz" data-id="viz-mitochondria-cell" data-cat="viz">
    <div class="card-head">
      <div class="card-icon">◉</div>
      <div class="card-title-block">
        <div class="card-tag">viz</div>
        <h3 class="card-title">Arias over the substrate</h3>
      </div>
    </div>
    <p class="card-tagline">Interactive SVG: the Memeroot canvas as a living cell with eight specialized mitochondria. Click each organelle to see its part in the architecture.</p>
    <div class="card-tags"><span class="card-tag-pill">viz</span><span class="card-tag-pill">interactive</span><span class="card-tag-pill">metaphor</span><span class="card-tag-pill">architecture</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="mitochondria-cell.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">34 KB</span>
    </div>
  </div>
  <div class="card viz" data-id="viz-signed-skills-showcase" data-cat="viz">
    <div class="card-head">
      <div class="card-icon">◇</div>
      <div class="card-title-block">
        <div class="card-tag">viz</div>
        <h3 class="card-title">Signed skills · interactive showcase</h3>
      </div>
    </div>
    <p class="card-tagline">Live WebCrypto demo of signed Claude Code skills. Real ECDSA-P256 verification, tamper detection, copy SKILL.md, fork-tree visualization.</p>
    <div class="card-tags"><span class="card-tag-pill">viz</span><span class="card-tag-pill">interactive</span><span class="card-tag-pill">WebCrypto</span><span class="card-tag-pill">commercial</span></div>
    <div class="card-publisher-badge" title="Memeroot Ltd · Rob Anderson · Founder">
      <span class="badge-mark">●</span>
      <span class="badge-name">Memeroot Ltd</span>
      <span class="badge-fp">fp 7da98308ba8d…</span>
    </div>
    <div class="card-actions">
      <a class="card-action-btn primary" href="signed-skills-showcase.html" target="_blank" onclick="event.stopPropagation()">↗ Open</a>
      <button class="card-action-btn secondary" title="inspect signature and metadata">⋯</button>
    </div>
    <div class="card-sig-mini">
      <span class="mark unknown">·</span>
      <span class="label">unverified</span>
      <span class="card-size">37 KB</span>
    </div>
  </div>
</div>

<div class="empty hidden" id="empty">no components match your filter</div>

<div class="modal-backdrop" id="modal" onclick="if(event.target===this)closeModal()">
  <div class="modal" id="modalContent"></div>
</div>

<footer>
  <p>Memeroot Catalog v5 · 27 components · 3 publishers · curated by Memeroot Ltd · Catalog Curator</p>
  <p>Three layers of cryptographic integrity · per-entry signatures by individual publishers · publisher-fp recorded in the curator-signed manifest · the curator signs the set of (id, contentHash, publisherFp) triples</p>
  <p>WebCrypto runs locally · no service contacted · no account required · the trust layer is mathematical</p>
  <p class="delivery-note">For downloads to work, the catalog HTML needs the sibling files alongside it. The delivery zip ships catalog + all components together.</p>
</footer>

<script>
const ENTRIES = [{"id":"doc-ops-playbook","category":"foundation","title":"Operations Playbook · canonical reference","tagline":"MEMEROOT-OPS-PLAYBOOK-2026-001 — full instruction set for taking Memeroot forward at production quality. Ten sections covering substrate philosophy, dev environment setup, skills inventory, canvas operations, CLI workflows, tool stack, quality discipline, onboarding, production patterns, and roadmap. Self-contained HTML in the Memeroot style; print-friendly. The setup guide a new hire reads on Day 1.","tags":["playbook","reference","setup","onboarding","production","canonical"],"sizeKB":64,"publishedAt":"2026-05","icon":"◐","iconStyle":"foundation","action":"open","bundlePath":"MEMEROOT-OPS-PLAYBOOK-2026-001.html","publisherFp":"7da98308ba8da466","contentHash":"d8a7e9a5c1e1bb76ee562d5692ee9319b69add1c109413e21c855d970a946a89","signature":"gmSDRuWJhgE4qxSSkRF6+UzEY30lIU8Uiv8qs8Sx5a/DhxCGbqv99lRoAMO3beN5vDdYIk5Zq6bYDIlIz5hdXQ=="},{"id":"doc-composable-xml-arch","category":"foundation","title":"Composable XML Architecture · MEMEROOT-ARCH-2026-002","tagline":"The structural discipline beneath everything. Six fundamental block kinds (schema · script · template · data · process · projection) with strict separation — no block kind contains elements of another. TABLE_SPECIFICATIONS is the universal projecting spine: any block projects into it; the UNION ALL is the unified addressable view. Direct XML analogue of the MBI_SCRIPT_AS_TABLE_SPEC_V production pattern. Ships ARCHITECTURE.html (12 sections, ~60KB), 8 worked blocks from Rob's real 25-year practice, 6 projection XSL stylesheets, the compose driver, and a 77-row reference spine that demonstrates the self-referencing graph.","tags":["foundation","XML","XSL","spine","TABLE_SPECIFICATIONS","block-kinds","composable","self-describing"],"sizeKB":46,"publishedAt":"2026-05","icon":"⬢","iconStyle":"foundation","action":"download","bundlePath":"memeroot-composable-xml.zip","publisherFp":"7da98308ba8da466","contentHash":"eb97f52e4b2c92f55c44f3378604e3f38f85b852c2440440222a3a6729c5844f","signature":"51hRlNpc1JX3hI4yI3utl/Mm7JwejID7YHDg1VByXHnW4pGMieO+7CpjZ4NwOR4aQAFoWkgPO5L+XefqtmqPWg=="},{"id":"doc-composable-xml-architecture-html","category":"foundation","title":"Composable XML Architecture · document only","tagline":"Just the ARCHITECTURE.html document itself. Open directly in browser for the 12-section canonical reference: thesis, five axioms, six block kinds, strict separation rule, the spine, projections, self-referencing graph, worked example (77 rows), composition into the unit, file inventory, integration with the existing Memeroot stack, roadmap. Print-friendly. For the zip with all blocks and projections, see doc-composable-xml-arch.","tags":["foundation","reference","document","canonical"],"sizeKB":48,"publishedAt":"2026-05","icon":"◐","iconStyle":"foundation","action":"open","bundlePath":"composable-xml-ARCHITECTURE.html","publisherFp":"7da98308ba8da466","contentHash":"3e3513518998bb1f6d35a2f4efb12116cf430ae942cd19b12225fe477a25179f","signature":"J7+xHrwMcdx4MB1uuLLyC0Gv1f/SJCEFsbYHOmS3a9cVxDFUsngQi/HMdyfO/Nb4vqXtkIi2+J9sMBU7wGVX5g=="},{"id":"doc-composable-substrate-2026","category":"foundation","title":"Composable Substrate · MEMEROOT-SUB-COMPOSABLE-2026-001","tagline":"Canonical eight-block-kind substrate. Data · schema · script · process · type · view · identity · address — each in its own XML namespace, absolutely zero crossover. Each block projects to the universal TABLE_SPECIFICATIONS spine via its own XSL stylesheet; the spine is computed by federation, never stored. Ships reference.html (40KB architectural reference in dark forensic style), 8 example block instances, 8 per-kind projection XSL stylesheets + 8 per-kind render stylesheets, the spine projection-shape declaration, the universal absorbing stylesheet, the composition document, a pure-Node compiler, and an interactive spine viewer rendering all 43 projected rows with per-kind filtering. Direct evolution of doc-composable-xml-arch (which had 6 kinds): adds type, identity, and address as first-class kinds; tightens the no-crossover rule; mirrors the production MBI_SCRIPT_AS_TABLE_SPEC_V row shape exactly.","tags":["foundation","XML","XSL","spine","TABLE_SPECIFICATIONS","8-block-kinds","composable","self-describing","MPP","no-crossover"],"sizeKB":53,"publishedAt":"2026-05","icon":"⬢","iconStyle":"foundation","action":"download","bundlePath":"memeroot-composable-substrate.zip","publisherFp":"7da98308ba8da466","contentHash":"0d424b8dae1f47e74e87ed44169320b74d5eb86524cb7318621a7f7c02772a8c","signature":"RveTq+Vq5nCG7Or6nfwWfzwGQAs83udOsjl4/ZXcBr2DqHJRPrVzsp6gAlB351LgVJSmLpcMzOuv4UFzoZZgBg=="},{"id":"doc-composable-substrate-reference-html","category":"foundation","title":"Composable Substrate · architectural reference document","tagline":"Just the MEMEROOT-SUB-COMPOSABLE-2026-001 reference document. Open directly in browser for the eight-section canonical reference: thesis (zero crossover) · the eight block kinds · the spine as universal absorber · per-kind XSL projection pattern · composition and compilation · self-describing recursion · MPP and independent processes · the deliverable shape. Dark forensic style with sidebar navigation. For the zip with all blocks, XSLs, compiler, and spine viewer, see doc-composable-substrate-2026.","tags":["foundation","reference","document","canonical","spine","composable"],"sizeKB":40,"publishedAt":"2026-05","icon":"◐","iconStyle":"foundation","action":"open","bundlePath":"MEMEROOT-SUB-COMPOSABLE-2026-001.html","publisherFp":"7da98308ba8da466","contentHash":"40cf890a33865b597261f57abac5e5c4de4ac4a84c833a081ad297b6b62d4b7a","signature":"cgHcDf3iS4G96tGOrdmlaBwVhfKAwKFwkrGnpS3IwGJ1+nXcosh5yatrD+fRwesjmMSeRaEXwrISr6nbOBsmQQ=="},{"id":"viz-spine-viewer","category":"visualization","title":"Spine viewer · the universal absorbed view","tagline":"Interactive viewer for the compiled spine output. Forty-three rows from eight independent blocks, projected through their own XSL stylesheets into the unified TABLE_SPECIFICATIONS shape. Filter by origin block (data/schema/script/process/type/view/identity/address); search across rows; see how each kind tags its rows via spec-source. Shows the no-crossover principle in action: every row identifies its origin block; nothing carries content from any other block. Companion to MEMEROOT-SUB-COMPOSABLE-2026-001.","tags":["visualization","interactive","spine","viewer","composable","TABLE_SPECIFICATIONS"],"sizeKB":37,"publishedAt":"2026-05","icon":"◑","iconStyle":"visualization","action":"open","bundlePath":"memeroot-spine-viewer.html","publisherFp":"7da98308ba8da466","contentHash":"709279ef699651b54c9eb8c9062d4895ef9cc4fac42536e19728eff498501529","signature":"mzzFzAc4re8dgH49y/D6Q8Jw2Jp7K8N1jZGxYwl4po19dv+oLroLwOmW8R6Kb8cop5NHCBFDF3l5f7stB6QCpA=="},{"id":"mr-canvas-v0.8","category":"foundation","title":"MR Canvas v0.8","tagline":"The substrate. Single-file HTML that boots into a Memeroot canvas with drop zone, region tree, and reader-mediated rendering.","tags":["canvas","substrate","core","self-contained"],"sizeKB":49,"publishedAt":"2026-05","icon":"M","iconStyle":"foundation","action":"download","bundlePath":"MR-CANVAS-v0.8.html","publisherFp":"7da98308ba8da466","contentHash":"5aa621c51da4f0b333473815b43ebde6c9bf1e177b349dd19cb8af553f1b1430","signature":"x9Q8QRCiHSoRlw/ULPAwJ+zcXWF2iun+Cl+RLvb+VvCZ3ZMinajq+0AcmEB2Ppz5r2Xdd0ldxBl2crPVWWMiTA=="},{"id":"memeroot-cli","category":"foundation","title":"memeroot-cli","tagline":"Programmatic bridge between Claude Code and the canvas. Three commands: validate, bundle, package. Closes the loop from \"Claude Code produces XML\" to \"single HTML packet the user opens with content auto-loaded\". Pure Node.js, no runtime dependencies.","tags":["cli","bridge","tool","claude-code","foundation"],"sizeKB":24,"publishedAt":"2026-05","icon":"⌘","iconStyle":"foundation","action":"open","bundlePath":"memeroot-cli-showcase.html","publisherFp":"7da98308ba8da466","contentHash":"b3e390c8b7fc148ce8791b47c4dd018d52d2b5537d30fde641cee1ca9efc88b5","signature":"DXkAupjCqMIQj/9NBno+Al8L6HPT65iVnVDzRMZnHG8ShJ1jzK2dJvbKihtEs2T+kC+CSUl9HVz5TSSV8kSnFA=="},{"id":"iframe-region-builder","category":"foundation","title":"iframe-region builder","tagline":"Standalone tool for authoring iframe-region XML. Live form, live iframe preview with sandboxing, syntax-highlighted XML output, copy/download/validate. Three presets (dashboard, doc embed, strict sandbox).","tags":["tool","iframe","builder","authoring","sandbox"],"sizeKB":34,"publishedAt":"2026-05","icon":"◧","iconStyle":"foundation","action":"open","bundlePath":"iframe-region-builder.html","publisherFp":"7da98308ba8da466","contentHash":"f563af919df4078312ba9e4db8cc83e778f74196b975c756b18336ef082b908d","signature":"b80KDE/gOZLewiJZjB4lr0jTNVG7oMqzinvbu4SakZRZ2FsIA7twemZE2rQpN/+lEVC/lLPCWWhKjKJlok39eg=="},{"id":"feature-svg-region-renderer","category":"foundation","title":"svg-region renderer · canvas feature","tagline":"Canvas feature that registers an svg-region reader. Renders embedded SVG inline (or sandboxed), verifies captured-hash via WebCrypto SHA-256, strips <script>, <foreignObject>, on* handlers, and external xlink:href by default. Three sanitization modes (strict, loose, none).","tags":["feature","canvas","svg","renderer","sanitization"],"sizeKB":8,"publishedAt":"2026-05","icon":"◇","iconStyle":"foundation","action":"download","bundlePath":"feature-svg-region-renderer.xml","publisherFp":"7da98308ba8da466","contentHash":"a8487ba532f92bafb4e3b9f6f8e09376b0792c920f5c90e73606696d125268d4","signature":"N+ci7pQzV3W1739d1iX4FgtSC8V8IPMMluh4hK6oNfJ+UdwhNkaEkungrYK2EW6/vRQJs4uERUTGLfEncUaJIg=="},{"id":"feature-iframe-region-renderer","category":"foundation","title":"iframe-region renderer · canvas feature","tagline":"Canvas feature that registers an iframe-region reader. Renders embedded HTML snapshots via iframe srcdoc (or live URL via src), verifies captured-hash via WebCrypto SHA-256, surfaces full metadata above the rendered iframe.","tags":["feature","canvas","iframe","renderer","captured-hash"],"sizeKB":8,"publishedAt":"2026-05","icon":"◇","iconStyle":"foundation","action":"download","bundlePath":"feature-iframe-region-renderer.xml","publisherFp":"7da98308ba8da466","contentHash":"a1fa636ad64dfb0f4f76df6f451f0196e57b0140526bbaee551e3cf2f69deb8a","signature":"3pI3UFd1oUaNbABH5Onm6TsOSfra+Cq7OHpSo9oe463bWIfoUDo2sZcjPt9lFUhBeVdM7CoWYmew+H2oOvpGcA=="},{"id":"stream-research-assistant","category":"tour","title":"Research Assistant","tagline":"Eight chunks build you a working AI research loop: signed question, wired endpoint, content-addressed response, forked draft, critic endpoint, bundled session.","tags":["stream","AI","invoker","compose","beginner"],"sizeKB":87,"publishedAt":"2026-05","icon":"🔍","iconStyle":"tour","action":"download","bundlePath":"memeroot-research-assistant.zip","publisherFp":"7da98308ba8da466","contentHash":"c4d1424cb5c02bfa8d11802884cd20fbdf9b6bdfcc59eabbd2277df0ffb10b77","signature":"ztNfiCnhR94fCvs3mfP6gqeNYqBvi13qcVK9Dr3S539nfp27Brm6Ve+ZRs2NbT85iF5K90FMnbxDehE5MIGjkQ=="},{"id":"stream-oracle-sql-free","category":"tour","title":"Oracle SQL Free","tagline":"Five chunks: AI proposes SQL, you run it on Oracle Live SQL externally, capture results as signed regions. Canvas-as-workspace, external-as-engine.","tags":["stream","integration","SQL","external-service"],"sizeKB":84,"publishedAt":"2026-05","icon":"⚡","iconStyle":"tour","action":"download","bundlePath":"memeroot-oracle-sql-free.zip","publisherFp":"7da98308ba8da466","contentHash":"4edfc9dbe165f6b58dfc91facb70525ceac529ade42a73243c62235591504f7e","signature":"bHHwd3A2uSvSleK4N57x1QjJb1mqrNhyyftQCpBa+AzwgSEpsqpWtO86mmyutSfZ7ZGCw8lAJNH4GnKlokFgig=="},{"id":"stream-interface-from-xml","category":"tour","title":"Interface from XML","tagline":"Seven chunks demonstrating that interfaces are data: declarative workflow + XSL stylesheet + signed completion regions. No application code.","tags":["stream","declarative","XSL","workflow"],"sizeKB":86,"publishedAt":"2026-05","icon":"◫","iconStyle":"tour","action":"download","bundlePath":"memeroot-interface-from-xml.zip","publisherFp":"7da98308ba8da466","contentHash":"e2846d8b7f58ac98aadee361d4c149ce8bae35ee1d51907a2509d68de149d9e4","signature":"D7082LnBrX4cHKOUffGA5spKegXTahKBHcpWtiv/Gdvi95ue2ZxEXOSXpJ1ksAogyqhELbAs5cjFlpQQnJ0L8w=="},{"id":"stream-page-build","category":"tour","title":"Page Build","tagline":"Six chunks from authored content to a self-contained HTML page that is itself a canvas. The recursive close: canvases produce canvases.","tags":["stream","publishing","recursive","bundle"],"sizeKB":84,"publishedAt":"2026-05","icon":"◊","iconStyle":"tour","action":"download","bundlePath":"memeroot-page-build.zip","publisherFp":"7da98308ba8da466","contentHash":"12c07dc3439ba1fbe80b5e59bc09b01a7b3af6955b92985ac1a35e8f827bbf46","signature":"UmzLfLTvc27CQ4Gh9Iw6MTOEJobqJqaJ33hqalNOamy+cslwZwimVjp1mi+Y2zzjmn8B7XFUvJUZphmvj/fluA=="},{"id":"stream-knowledge-tree","category":"tour","title":"Knowledge Tree","tagline":"Six chunks exercising the compose feature: include, fork, diff. Atomic sections become composable books; forks carry cryptographic lineage.","tags":["stream","compose","fork","lineage"],"sizeKB":83,"publishedAt":"2026-05","icon":"⌬","iconStyle":"tour","action":"download","bundlePath":"memeroot-knowledge-tree.zip","publisherFp":"7da98308ba8da466","contentHash":"c75ead2ce2bd8cd1fe4e33eecf08a2ab6e517b6c8f280be4244e54f720b75361","signature":"HSl6o/OBw7Amooed+hXV098xcKKGGEErtvO529RN29DENEq4FxYzxI1CtSRogheMR2XclTEDKseJoCu9O7288Q=="},{"id":"stream-compliance-audit-trail","category":"tour","title":"Compliance Audit Trail","tagline":"Six chunks producing a SOX-style audit packet with multi-party sign-offs. External auditor opens bundle.html and verifies in any browser. Replaces the audit-trail layer of GRC platforms.","tags":["stream","SOX","compliance","commercial","multi-party"],"sizeKB":88,"publishedAt":"2026-05","icon":"✓","iconStyle":"tour-commercial","action":"download","bundlePath":"memeroot-compliance-audit-trail.zip","publisherFp":"7da98308ba8da466","contentHash":"f69777bc7482503765ab0793ab030127370069ae46a70d53d26c740080002e9d","signature":"cQSi7wnKFeoOvsrop697/FzvFiN9SgKWHdu/DEqtKJ9eYrVnm0ivYyf8spgQfVNDXZXHPoXm0MTgEkw0vOIFPA=="},{"id":"stream-skill-author","category":"tour","title":"Skill Author","tagline":"Six chunks for authoring Claude Code skills as signed transferable artifacts. SKILL.md with cryptographic provenance, forkable with lineage.","tags":["stream","skill","Claude Code","ecosystem"],"sizeKB":88,"publishedAt":"2026-05","icon":"⚒","iconStyle":"tour-commercial","action":"download","bundlePath":"memeroot-skill-author.zip","publisherFp":"7da98308ba8da466","contentHash":"9a7bc2a91dafc37ce89681942527aa1bda3bfb6cfa63b3d1c719ffb26712d58d","signature":"9Td5FDC3wIWqTRonvzUX7JT2HJuUgDMszhTZGBBwX5sDdEUwt7Bst7fD+xlHsiQTDAJcD9CsYi/V8KndbFZdGQ=="},{"id":"skillpack-regulated-document-author","category":"skill","title":"regulated-document-author · production pack","tagline":"Production Claude Code skill pack: substantive SKILL.md (10.7 KB), 5 XML templates (SOX control, TOD, TOE, IRB protocol, audit finding, management letter), pre-publication checklist, worked example. 9 files signed by author and counter-signed by reviewer.","tags":["skill","production","SOX","FDA","IRB","compliance","multi-signed"],"sizeKB":26,"publishedAt":"2026-05","icon":"◐","iconStyle":"skill","action":"open","bundlePath":"regulated-document-author-bundle.html","publisherFp":"7da98308ba8da466","contentHash":"ab937a821d786c66f0a5c3da2ef7d453facd564acc057d66288b63d3c721f4d2","signature":"aTeiZ/YIuRmm0xX6W/BmqAukWL9SPufcGDGHkKDf9hfOZFN3Jm5jWSfKGMHmwJEUdo51JwhyTcgkpD+GrKgStw=="},{"id":"skillpack-memeroot-bridge","category":"skill","title":"memeroot-bridge · production pack","tagline":"Production Claude Code skill pack teaching Claude to produce Memeroot-shaped output. Substantive SKILL.md, 7 region templates (note, section, decision, task, reference, iframe-region, svg-region, workspace), 4 worked examples including iframe-region dashboard and svg-region chart with captured-hash, composition pattern with regulated-document-author. 13 files signed by author and counter-signed by reviewer.","tags":["skill","production","memeroot","bridge","claude-code","multi-signed","composition","iframe","svg"],"sizeKB":25,"publishedAt":"2026-05","icon":"⤞","iconStyle":"skill","action":"open","bundlePath":"memeroot-bridge-bundle.html","publisherFp":"7da98308ba8da466","contentHash":"6f0f42b52b48473e089001328b5fa46aca4b98349dd4f0a98ccc37a4f8cbb3c2","signature":"ey6ttD7z8eiFCgh9WH3tPy20LSWkf+1QZInLn4Tm/prMVkdUt6Q7MyFvcIo3ChekC3QiXHrZasOt7/iLPcsCfQ=="},{"id":"skillpack-iframe-snapshot-author","category":"skill","title":"iframe-snapshot-author · production pack","tagline":"Production Claude Code skill pack for capturing external HTML as audit-grade evidence. Fetches URLs (or reads local files) via the bash tool, computes SHA-256, produces ready-to-sign iframe-region with snapshot embedded inline. Substantive SKILL.md, Node.js capture script + shell variant, template, two worked examples. 6 files signed by author and counter-signed by reviewer.","tags":["skill","production","iframe","snapshot","capture","audit-evidence","sha256"],"sizeKB":15,"publishedAt":"2026-05","icon":"◧","iconStyle":"skill","action":"open","bundlePath":"iframe-snapshot-author-bundle.html","publisherFp":"7da98308ba8da466","contentHash":"109e04fe919d671c0ac5ed57f2b994f72d6e2d4ea8a30b8f19f535876d05a5b9","signature":"wnl4zVZ7V1C+8Q0yR+xsYD8paGl0Gi6EzQsXDd+JXFXddK8ueeZTYYcYpx79O+B3LFrXlZiRSsHSEnC5oaMCQA=="},{"id":"skill-regulated-doc-healthcare","category":"skill","title":"regulated-document-author (healthcare) · concept","tagline":"Conceptual fork demonstrating healthcare specialization — FDA 21 CFR Part 11, HIPAA, ICH GCP, GAMP 5 priority. Lineage preserved via fork-source reference.","tags":["skill","fork","healthcare","HIPAA","FDA","demo"],"sizeKB":3,"publishedAt":"2026-05","icon":"◐","iconStyle":"skill-fork","forkOf":"skillpack-regulated-document-author","action":"skill-md","skillMd":"---\nname: regulated-document-author-healthcare\ndescription: Use when authoring documents that face regulatory scrutiny (SOX internal controls, FDA submissions, IRB protocols, audit packets, GMP records, compliance attestations). Ensures cryptographic provenance, multi-party attestation, and tamper-evident structure.\n---\n\n# regulated-document-author (healthcare specialization)\n\n## When to use\n\nThe user is producing documentation that will be reviewed by external auditors, regulators, or internal compliance teams. Common signals: \"SOX control\", \"FDA submission\", \"IRB protocol\", \"audit packet\", \"GMP record\", \"compliance attestation\".\n\n## Instructions\n\n### Identify the regulatory frame\n\nDetermine which regulatory framework applies: FDA 21 CFR Part 11 (priority), HIPAA, ICH GCP (priority), GAMP 5, plus SOX (electronic records), ICH GCP (clinical trials), HIPAA (health information), defense procurement (DFARS clauses). The framework dictates required document structure, retention period, and signature requirements.\n\n### Structure as addressable regions\n\nAuthor each document component (control declaration, test of design, test of effectiveness, sign-off, finding) as its own addressable source. Granular regions are independently signable and verifiable.\n\n### Apply separation of duties to attestations\n\nDifferent actors sign different artifacts. Control owner signs the control declaration. Tester signs the test. Reviewer counter-signs the package.\n\n### Preserve fork lineage on revisions\n\nWhen a regulated document is revised, fork the original rather than overwrite. The fork-source element preserves verifiable lineage for the audit trail.\n\n### Bundle as the deliverable\n\nThe audit packet is the bundle.html, not the database record on a GRC platform. The bundle is self-contained, transferable, verifiable in any browser without a platform account.\n","publisherFp":"ba0e26bf408c1876","contentHash":"48fcf862293962cc27ccef71395ae86aa746d1975a1cceb794763bff74e5ae1b","signature":"y+fl0bNnu86exMEIfg5XDJufEs3yHmynvsoZuQiXT/TWjvbuJOlZvW2qsjt7gtgxcJkS2n0mMbE38bNBQrBlZQ=="},{"id":"skill-regulated-doc-finance","category":"skill","title":"regulated-document-author (finance) · concept","tagline":"Conceptual fork demonstrating financial-services specialization — SOX, Basel III, MAR, FINRA, Dodd-Frank, AML/KYC priority. Lineage preserved via fork-source reference.","tags":["skill","fork","finance","SOX","Basel","demo"],"sizeKB":3,"publishedAt":"2026-05","icon":"◐","iconStyle":"skill-fork","forkOf":"skillpack-regulated-document-author","action":"skill-md","skillMd":"---\nname: regulated-document-author-finance\ndescription: Use when authoring documents that face regulatory scrutiny (SOX internal controls, FDA submissions, IRB protocols, audit packets, GMP records, compliance attestations). Ensures cryptographic provenance, multi-party attestation, and tamper-evident structure.\n---\n\n# regulated-document-author (financial-services specialization)\n\n## When to use\n\nThe user is producing documentation that will be reviewed by external auditors, regulators, or internal compliance teams. Common signals: \"SOX control\", \"FDA submission\", \"IRB protocol\", \"audit packet\", \"GMP record\", \"compliance attestation\".\n\n## Instructions\n\n### Identify the regulatory frame\n\nDetermine which regulatory framework applies: SOX (priority), Basel III, MAR, FINRA, Dodd-Frank, AML/KYC, FDA 21 CFR Part 11 (electronic records), ICH GCP (clinical trials), HIPAA (health information), defense procurement (DFARS clauses). The framework dictates required document structure, retention period, and signature requirements.\n\n### Structure as addressable regions\n\nAuthor each document component (control declaration, test of design, test of effectiveness, sign-off, finding) as its own addressable source. Granular regions are independently signable and verifiable.\n\n### Apply separation of duties to attestations\n\nDifferent actors sign different artifacts. Control owner signs the control declaration. Tester signs the test. Reviewer counter-signs the package.\n\n### Preserve fork lineage on revisions\n\nWhen a regulated document is revised, fork the original rather than overwrite. The fork-source element preserves verifiable lineage for the audit trail.\n\n### Bundle as the deliverable\n\nThe audit packet is the bundle.html, not the database record on a GRC platform. The bundle is self-contained, transferable, verifiable in any browser without a platform account.\n","publisherFp":"54f4b2daa1046610","contentHash":"da291b1d971794439ac24284f258759729dee0a1fed290b66cf4008db5f2a898","signature":"Ho1wNxm3076dXluln3oBbEudq2N2oIj9a2RQ+cxM+rjhxIrG0f3GJpPkWYIU2n1K6yg2QVOuGr70De0G7ccYlg=="},{"id":"viz-iframe-region-demo-packet","category":"viz","title":"iframe-region demo packet","tagline":"Single self-contained HTML demonstrating the iframe-region chain. Two signed captured iframe-regions (operations dashboard + policy document), canvas + renderer feature bundled inline, demo publisher attribution + verify-all button. Auto-verifies on open: publisher signatures + captured-hash — all locally via WebCrypto.","tags":["demo","iframe-region","signed","self-contained","showcase","end-to-end"],"sizeKB":65,"publishedAt":"2026-05","icon":"◫","iconStyle":"viz","action":"open","bundlePath":"iframe-region-demo-packet.html","publisherFp":"7da98308ba8da466","contentHash":"363191b0580a3667c15b73cb3512e7bf9faf536b2e804b3bd53a1fd403410af4","signature":"X8f7hqyobhbJ7TP0PJd6XAL1WJ3woAHQxIOVcSnrt2EQd/cDowDn5uLOf/V9gvjw17YpYXoAUj5kgVInvLrFZw=="},{"id":"viz-mixed-demo-packet","category":"viz","title":"iframe + svg demo packet","tagline":"Single self-contained HTML with three signed regions: two iframe-regions (dashboard + policy) and one svg-region (chart). Both renderer features bundled. Demonstrates the captured-hash + sanitization model across two region kinds — and the federation pattern of pluggable renderers loaded from features.","tags":["demo","iframe-region","svg-region","signed","self-contained","mixed-region"],"sizeKB":78,"publishedAt":"2026-05","icon":"◫","iconStyle":"viz","action":"open","bundlePath":"iframe-and-svg-demo-packet.html","publisherFp":"7da98308ba8da466","contentHash":"37f4c3aabc2dd5a8fec6ea05e9697a410ff81da0d14d33690805f5c330a28f71","signature":"uKlVaCJSiYY71vzhWnshXb6r2fnsSpkpS1hPm5VIxujDPPyijwuesAJeXO5eW/Mbubp0n1vdBCoRHHgFrt1umg=="},{"id":"viz-mitochondria-cell","category":"viz","title":"Arias over the substrate","tagline":"Interactive SVG: the Memeroot canvas as a living cell with eight specialized mitochondria. Click each organelle to see its part in the architecture.","tags":["viz","interactive","metaphor","architecture"],"sizeKB":34,"publishedAt":"2026-05","icon":"◉","iconStyle":"viz","action":"open","bundlePath":"mitochondria-cell.html","publisherFp":"7da98308ba8da466","contentHash":"b7d36b0320b194e976bbfcb8a483c327da49a524651648252432c2e982a680cc","signature":"KKKBaVY5noiwiwUrA/fZa2gw/WUMhLcPYzP3VW/OcCg71s8W133VuWe186hcWJzCY5vsTpj5GYmdsMvCESXN+Q=="},{"id":"viz-signed-skills-showcase","category":"viz","title":"Signed skills · interactive showcase","tagline":"Live WebCrypto demo of signed Claude Code skills. Real ECDSA-P256 verification, tamper detection, copy SKILL.md, fork-tree visualization.","tags":["viz","interactive","WebCrypto","commercial"],"sizeKB":37,"publishedAt":"2026-05","icon":"◇","iconStyle":"viz","action":"open","bundlePath":"signed-skills-showcase.html","publisherFp":"7da98308ba8da466","contentHash":"085a9a526e5da851c299761cb08b3001b6b587c4f5be473000fedbd9adf985c4","signature":"q3qXhUZD0uxfwo/myoMkdnEuOuIbytPT914srU2TH+VZ7pEF1f4ZVdVIC83TddEw/02dmWO95x0nrDCigomsZA=="}];
const PUBLISHERS = {"54f4b2daa1046610":{"name":"Beta Capital Partners · Compliance Publisher · (demo identity)","pubB64":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2kVj7vYSmmitrO+pWNbljjr5fpjyF8sfFA9eYd/RXiPNPFQ/Hm9bS9IPCM52XPLZ+EsIVUyEyLJqn2jv3GHXIw=="},"7da98308ba8da466":{"name":"Memeroot Ltd · Rob Anderson · Founder","pubB64":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETdQViPwzmEiXRqCG/kr+cvPVkduSkQ/urNNKNNqOcTo0H3pgMNuKPd85EUDoqxXWOqXeaKHo0fcGHtpzcserDA=="},"ba0e26bf408c1876":{"name":"Acme Health Inc · Compliance Publisher · (demo identity)","pubB64":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKjhpbCs7h8DBkuURzwUmQqlfCYvO7R/t6L83Iz5xxinkLbmEr0XpfCPTd/gTi+309BgX4E5M+0Bpb9baj+eaUg=="}};  // fp -> { name, pubB64 }
const CURATOR_PUB = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDJsEtu0ZynGYJ4pR2a7LFkUS77DakMdSDKUTmez0lFBT+3/HykfiR+2kMtEKsLLJClSXROLPFXGgtiRY7UvjMw==";
const CURATOR_NAME = "Memeroot Ltd · Catalog Curator";
const CURATOR_FP = "da4d8e4d5cb5238d";
const MANIFEST = {"curator":"Memeroot Ltd · Catalog Curator","curatorFp":"da4d8e4d5cb5238d","entries":[{"id":"doc-composable-substrate-2026","contentHash":"0d424b8dae1f47e74e87ed44169320b74d5eb86524cb7318621a7f7c02772a8c","publisherFp":"7da98308ba8da466"},{"id":"doc-composable-substrate-reference-html","contentHash":"40cf890a33865b597261f57abac5e5c4de4ac4a84c833a081ad297b6b62d4b7a","publisherFp":"7da98308ba8da466"},{"id":"doc-composable-xml-arch","contentHash":"eb97f52e4b2c92f55c44f3378604e3f38f85b852c2440440222a3a6729c5844f","publisherFp":"7da98308ba8da466"},{"id":"doc-composable-xml-architecture-html","contentHash":"3e3513518998bb1f6d35a2f4efb12116cf430ae942cd19b12225fe477a25179f","publisherFp":"7da98308ba8da466"},{"id":"doc-ops-playbook","contentHash":"d8a7e9a5c1e1bb76ee562d5692ee9319b69add1c109413e21c855d970a946a89","publisherFp":"7da98308ba8da466"},{"id":"feature-iframe-region-renderer","contentHash":"a1fa636ad64dfb0f4f76df6f451f0196e57b0140526bbaee551e3cf2f69deb8a","publisherFp":"7da98308ba8da466"},{"id":"feature-svg-region-renderer","contentHash":"a8487ba532f92bafb4e3b9f6f8e09376b0792c920f5c90e73606696d125268d4","publisherFp":"7da98308ba8da466"},{"id":"iframe-region-builder","contentHash":"f563af919df4078312ba9e4db8cc83e778f74196b975c756b18336ef082b908d","publisherFp":"7da98308ba8da466"},{"id":"memeroot-cli","contentHash":"b3e390c8b7fc148ce8791b47c4dd018d52d2b5537d30fde641cee1ca9efc88b5","publisherFp":"7da98308ba8da466"},{"id":"mr-canvas-v0.8","contentHash":"5aa621c51da4f0b333473815b43ebde6c9bf1e177b349dd19cb8af553f1b1430","publisherFp":"7da98308ba8da466"},{"id":"skill-regulated-doc-finance","contentHash":"da291b1d971794439ac24284f258759729dee0a1fed290b66cf4008db5f2a898","publisherFp":"54f4b2daa1046610"},{"id":"skill-regulated-doc-healthcare","contentHash":"48fcf862293962cc27ccef71395ae86aa746d1975a1cceb794763bff74e5ae1b","publisherFp":"ba0e26bf408c1876"},{"id":"skillpack-iframe-snapshot-author","contentHash":"109e04fe919d671c0ac5ed57f2b994f72d6e2d4ea8a30b8f19f535876d05a5b9","publisherFp":"7da98308ba8da466"},{"id":"skillpack-memeroot-bridge","contentHash":"6f0f42b52b48473e089001328b5fa46aca4b98349dd4f0a98ccc37a4f8cbb3c2","publisherFp":"7da98308ba8da466"},{"id":"skillpack-regulated-document-author","contentHash":"ab937a821d786c66f0a5c3da2ef7d453facd564acc057d66288b63d3c721f4d2","publisherFp":"7da98308ba8da466"},{"id":"stream-compliance-audit-trail","contentHash":"f69777bc7482503765ab0793ab030127370069ae46a70d53d26c740080002e9d","publisherFp":"7da98308ba8da466"},{"id":"stream-interface-from-xml","contentHash":"e2846d8b7f58ac98aadee361d4c149ce8bae35ee1d51907a2509d68de149d9e4","publisherFp":"7da98308ba8da466"},{"id":"stream-knowledge-tree","contentHash":"c75ead2ce2bd8cd1fe4e33eecf08a2ab6e517b6c8f280be4244e54f720b75361","publisherFp":"7da98308ba8da466"},{"id":"stream-oracle-sql-free","contentHash":"4edfc9dbe165f6b58dfc91facb70525ceac529ade42a73243c62235591504f7e","publisherFp":"7da98308ba8da466"},{"id":"stream-page-build","contentHash":"12c07dc3439ba1fbe80b5e59bc09b01a7b3af6955b92985ac1a35e8f827bbf46","publisherFp":"7da98308ba8da466"},{"id":"stream-research-assistant","contentHash":"c4d1424cb5c02bfa8d11802884cd20fbdf9b6bdfcc59eabbd2277df0ffb10b77","publisherFp":"7da98308ba8da466"},{"id":"stream-skill-author","contentHash":"9a7bc2a91dafc37ce89681942527aa1bda3bfb6cfa63b3d1c719ffb26712d58d","publisherFp":"7da98308ba8da466"},{"id":"viz-iframe-region-demo-packet","contentHash":"363191b0580a3667c15b73cb3512e7bf9faf536b2e804b3bd53a1fd403410af4","publisherFp":"7da98308ba8da466"},{"id":"viz-mitochondria-cell","contentHash":"b7d36b0320b194e976bbfcb8a483c327da49a524651648252432c2e982a680cc","publisherFp":"7da98308ba8da466"},{"id":"viz-mixed-demo-packet","contentHash":"37f4c3aabc2dd5a8fec6ea05e9697a410ff81da0d14d33690805f5c330a28f71","publisherFp":"7da98308ba8da466"},{"id":"viz-signed-skills-showcase","contentHash":"085a9a526e5da851c299761cb08b3001b6b587c4f5be473000fedbd9adf985c4","publisherFp":"7da98308ba8da466"},{"id":"viz-spine-viewer","contentHash":"709279ef699651b54c9eb8c9062d4895ef9cc4fac42536e19728eff498501529","publisherFp":"7da98308ba8da466"}],"entryCount":27,"publishedAt":"2026-05-23","publisherCount":3,"publishers":{"54f4b2daa1046610":{"name":"Beta Capital Partners · Compliance Publisher · (demo identity)","pubB64":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2kVj7vYSmmitrO+pWNbljjr5fpjyF8sfFA9eYd/RXiPNPFQ/Hm9bS9IPCM52XPLZ+EsIVUyEyLJqn2jv3GHXIw=="},"7da98308ba8da466":{"name":"Memeroot Ltd · Rob Anderson · Founder","pubB64":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETdQViPwzmEiXRqCG/kr+cvPVkduSkQ/urNNKNNqOcTo0H3pgMNuKPd85EUDoqxXWOqXeaKHo0fcGHtpzcserDA=="},"ba0e26bf408c1876":{"name":"Acme Health Inc · Compliance Publisher · (demo identity)","pubB64":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKjhpbCs7h8DBkuURzwUmQqlfCYvO7R/t6L83Iz5xxinkLbmEr0XpfCPTd/gTi+309BgX4E5M+0Bpb9baj+eaUg=="}},"version":"2"};
const MANIFEST_SIGNATURE = "19BHH+qNUwNZtCl4Fe+rr6Y0wA2YnE+TLAf34aFAGFN1rm7FNids4Vl8KlxpGzw6RgoBvio0hITr0IzeXGZcTg==";

// A copy of ENTRIES we can mutate for the tampering demo
let currentEntries = JSON.parse(JSON.stringify(ENTRIES));

function b64ToBuf(b64) {
  const bin = atob(b64);
  const buf = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
  return buf;
}
function entryDigest(entry) {
  const { signature, contentHash, skillMd, ...rest } = entry;
  const sorted = {};
  Object.keys(rest).sort().forEach(k => { sorted[k] = rest[k]; });
  return JSON.stringify(sorted);
}
function pubForEntry(entry) {
  const fp = entry.publisherFp;
  const p = PUBLISHERS[fp];
  return p ? p.pubB64 : null;
}

async function verifyEntry(entry, pubB64) {
  try {
    const pubKey = await crypto.subtle.importKey('spki', b64ToBuf(pubB64), { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);
    return await crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, pubKey, b64ToBuf(entry.signature), new TextEncoder().encode(entryDigest(entry)));
  } catch (e) { console.error(e); return false; }
}
async function verifyCatalogIndex() {
  // Rebuild manifest from currentEntries — should match the embedded MANIFEST
  const builtEntries = currentEntries.map(e => ({
    id: e.id, contentHash: e.contentHash, publisherFp: e.publisherFp,
  })).sort((a, b) => a.id.localeCompare(b.id));
  const rebuilt = {
    curator: MANIFEST.curator,
    curatorFp: MANIFEST.curatorFp,
    entries: builtEntries,
    entryCount: builtEntries.length,
    publishedAt: MANIFEST.publishedAt,
    publisherCount: MANIFEST.publisherCount,
    publishers: MANIFEST.publishers,
    version: MANIFEST.version,
  };
  const rebuiltJson = JSON.stringify(rebuilt);
  const embeddedJson = JSON.stringify({
    curator: MANIFEST.curator,
    curatorFp: MANIFEST.curatorFp,
    entries: MANIFEST.entries,
    entryCount: MANIFEST.entryCount,
    publishedAt: MANIFEST.publishedAt,
    publisherCount: MANIFEST.publisherCount,
    publishers: MANIFEST.publishers,
    version: MANIFEST.version,
  });
  try {
    const pubKey = await crypto.subtle.importKey('spki', b64ToBuf(CURATOR_PUB), { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);
    const sigValid = await crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, pubKey, b64ToBuf(MANIFEST_SIGNATURE), new TextEncoder().encode(embeddedJson));
    const matches = rebuiltJson === embeddedJson;
    return { sigValid, matches, allOk: sigValid && matches };
  } catch (e) { console.error(e); return { sigValid: false, matches: false, allOk: false }; }
}
function escapeHtml(s) {
  return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}

// Search & filter
const searchInput = document.getElementById('searchInput');
const filterTabs = document.querySelectorAll('.filter-tab');
let activeFilter = 'all', searchTerm = '';
function applyFilters() {
  const term = searchTerm.toLowerCase();
  let visible = 0;
  ENTRIES.forEach(e => {
    const card = document.querySelector('.card[data-id="' + e.id + '"]');
    if (!card) return;
    const c = e.category === 'skill-fork' ? 'skill' : (e.category === 'tour-commercial' ? 'tour' : e.category);
    const matchCat = activeFilter === 'all' || c === activeFilter;
    const haystack = (e.title + ' ' + e.tagline + ' ' + e.tags.join(' ')).toLowerCase();
    const matchSearch = !term || haystack.includes(term);
    const show = matchCat && matchSearch;
    card.classList.toggle('hidden', !show);
    if (show) visible++;
  });
  document.getElementById('empty').classList.toggle('hidden', visible > 0);
}
searchInput.addEventListener('input', e => { searchTerm = e.target.value; applyFilters(); });
filterTabs.forEach(t => t.addEventListener('click', () => { filterTabs.forEach(x => x.classList.remove('active')); t.classList.add('active'); activeFilter = t.dataset.cat; applyFilters(); }));

// Counts
function updateCounts() {
  const cats = { all: 0, tour: 0, skill: 0, viz: 0, foundation: 0 };
  ENTRIES.forEach(e => { cats.all++; const c = e.category === 'skill-fork' ? 'skill' : (e.category === 'tour-commercial' ? 'tour' : e.category); if (cats[c] !== undefined) cats[c]++; });
  Object.keys(cats).forEach(c => { const el = document.getElementById('count-' + c); if (el) el.textContent = cats[c]; });
}
updateCounts();

// Card-level verify
async function verifyCardInline(cardEl, entry) {
  const sigEl = cardEl.querySelector('.card-sig-mini');
  const mark = sigEl.querySelector('.mark');
  const label = sigEl.querySelector('.label');
  mark.textContent = '⌛'; mark.className = 'mark unknown';
  label.textContent = 'verifying…';
  const ok = await verifyEntry(entry, pubForEntry(entry));
  mark.textContent = ok ? '✓' : '✗';
  mark.className = 'mark ' + (ok ? 'ok' : 'bad');
  label.textContent = ok ? 'verified' : 'invalid';
  cardEl.classList.toggle('verified', ok);
  return ok;
}

// Action handlers
async function copySkillMd(entry, btnEl) {
  try {
    await navigator.clipboard.writeText(entry.skillMd);
    btnEl.classList.add('copied');
    btnEl.textContent = '✓ copied';
    setTimeout(() => { btnEl.classList.remove('copied'); btnEl.textContent = 'Copy SKILL.md'; }, 2200);
  } catch (e) {
    const ta = document.createElement('textarea');
    ta.value = entry.skillMd;
    document.body.appendChild(ta);
    ta.select();
    document.execCommand('copy');
    ta.remove();
    btnEl.classList.add('copied');
    btnEl.textContent = '✓ copied';
    setTimeout(() => { btnEl.classList.remove('copied'); btnEl.textContent = 'Copy SKILL.md'; }, 2200);
  }
}

// Card click handlers
document.querySelectorAll('.card').forEach(card => {
  const id = card.dataset.id;
  const entry = ENTRIES.find(e => e.id === id);
  if (!entry) return;

  // Title/tagline click → modal
  card.querySelector('.card-head').addEventListener('click', () => openModal(entry));
  card.querySelector('.card-tagline').addEventListener('click', () => openModal(entry));

  // Action button
  const actionBtn = card.querySelector('.card-action-btn.primary');
  if (actionBtn && entry.action === 'skill-md') {
    actionBtn.addEventListener('click', e => {
      e.stopPropagation();
      copySkillMd(entry, actionBtn);
    });
  }
  // Inspect (modal) button
  const inspectBtn = card.querySelector('.card-action-btn.secondary');
  if (inspectBtn) {
    inspectBtn.addEventListener('click', e => {
      e.stopPropagation();
      openModal(entry);
    });
  }
});

// Modal
function openModal(entry) {
  const isCommercial = entry.category === 'tour-commercial';
  const skillBlock = entry.action === 'skill-md'
    ? '<div class="modal-section"><h4>SKILL.md preview</h4><div class="skill-preview">' + escapeHtml(entry.skillMd) + '</div></div>'
    : '';
  const actionBtnHtml = entry.action === 'download'
    ? '<a class="action primary" href="' + escapeHtml(entry.bundlePath) + '" download>Download · ' + escapeHtml(entry.bundlePath) + '</a>'
    : entry.action === 'open'
    ? '<a class="action primary" href="' + escapeHtml(entry.bundlePath) + '" target="_blank">Open · ' + escapeHtml(entry.bundlePath) + '</a>'
    : entry.action === 'skill-md'
    ? '<button class="action success" id="modalCopySkill">Copy SKILL.md</button>'
    : '';

  const html = `
    <button class="modal-close" onclick="closeModal()" aria-label="close">×</button>
    <div class="modal-eyebrow">${escapeHtml(entry.category)} · ${escapeHtml(entry.id)}</div>
    <h2 class="${isCommercial ? 'commercial' : ''}">${escapeHtml(entry.title)}</h2>
    <p class="modal-tagline">${escapeHtml(entry.tagline)}</p>
    <div class="modal-tags">${entry.tags.map(t => '<span class="card-tag-pill">' + escapeHtml(t) + '</span>').join('')}</div>
    ${entry.forkOf ? '<div class="fork-link">fork of <strong>' + escapeHtml(entry.forkOf) + '</strong> · lineage preserved cryptographically</div>' : ''}

    <div class="modal-sig-block unknown" id="modalSigBlock">
      <div class="sig-line"><span class="sig-mark unknown" id="modalSigMark">·</span> <span class="sig-label">content hash:</span> ${escapeHtml(entry.contentHash)}</div>
      <div class="sig-line"><span class="sig-label">signed by:</span> ${escapeHtml((PUBLISHERS[entry.publisherFp]||{}).name || "(unknown publisher)")}
      <div class="sig-line"><span class="sig-label">publisher fp:</span> ${escapeHtml(entry.publisherFp)}</div>
      <div class="sig-line" id="modalSigStatus"><span class="sig-label">status:</span> verifying…</div>
    </div>

    ${skillBlock}

    <div class="modal-section">
      <h4>component metadata</h4>
      <div class="value">size · ${entry.sizeKB} KB</div>
      <div class="value">published · ${escapeHtml(entry.publishedAt)}</div>
      <div class="value">category · ${escapeHtml(entry.category)}</div>
      ${entry.bundlePath ? '<div class="value">file · ' + escapeHtml(entry.bundlePath) + '</div>' : ''}
    </div>

    <div class="btn-row">
      ${actionBtnHtml}
      <button class="action" id="modalVerifyBtn">Re-verify</button>
      <button class="action danger" id="modalTamperBtn">Tamper test</button>
      <span class="toast" id="modalToast"></span>
    </div>
  `;
  document.getElementById('modalContent').innerHTML = html;
  document.getElementById('modal').classList.add('shown');

  let workingEntry = JSON.parse(JSON.stringify(entry));

  async function runVerify() {
    const block = document.getElementById('modalSigBlock');
    const mark = document.getElementById('modalSigMark');
    const statusEl = document.getElementById('modalSigStatus');
    block.classList.remove('ok', 'bad', 'unknown'); block.classList.add('unknown');
    mark.textContent = '⌛'; mark.className = 'sig-mark unknown';
    statusEl.innerHTML = '<span class="sig-label">status:</span> verifying…';
    await new Promise(r => setTimeout(r, 80));
    const ok = await verifyEntry(workingEntry, pubForEntry(workingEntry));
    block.classList.remove('unknown');
    block.classList.add(ok ? 'ok' : 'bad');
    mark.textContent = ok ? '✓' : '✗'; mark.className = 'sig-mark ' + (ok ? 'ok' : 'bad');
    statusEl.innerHTML = '<span class="sig-label">status:</span> ' + (ok ? '<span style="color: var(--verify);">verified · content unchanged since signing</span>' : '<span style="color: var(--fail);">invalid · content does not match signature</span>');
  }

  document.getElementById('modalVerifyBtn').addEventListener('click', runVerify);
  document.getElementById('modalTamperBtn').addEventListener('click', () => {
    workingEntry.tagline = workingEntry.tagline + ' [TAMPERED]';
    document.querySelector('.modal-tagline').textContent = workingEntry.tagline;
    const t = document.getElementById('modalToast');
    t.textContent = 'modified · click Re-verify to see signature break';
    t.className = 'toast show error';
  });

  const copyBtn = document.getElementById('modalCopySkill');
  if (copyBtn) copyBtn.addEventListener('click', () => copySkillMd(entry, copyBtn));

  setTimeout(runVerify, 200);
}

function closeModal() { document.getElementById('modal').classList.remove('shown'); }
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeModal(); });

// Combined verification: index signature + per-entry signatures
async function verifyAll() {
  const pubBar = document.getElementById('pubBar');
  const pubMark = document.getElementById('pubMark');
  const pubStatus = document.getElementById('pubStatus');
  const indexMarkManifest = document.getElementById('indexMarkManifest');
  const indexStatusManifest = document.getElementById('indexStatusManifest');
  const indexMarkEntries = document.getElementById('indexMarkEntries');
  const indexStatusEntries = document.getElementById('indexStatusEntries');

  // Reset to verifying state
  pubMark.textContent = '⌛';
  pubStatus.textContent = 'verifying…';
  pubStatus.classList.remove('bad');
  indexMarkManifest.textContent = '⌛'; indexMarkManifest.className = 'mark unknown';
  indexMarkEntries.textContent = '⌛'; indexMarkEntries.className = 'mark unknown';
  indexStatusManifest.textContent = 'verifying manifest signature…';
  indexStatusEntries.textContent = 'verifying ' + currentEntries.length + ' entries…';

  await new Promise(r => setTimeout(r, 80));

  // 1. Verify catalog index (manifest signature + set membership)
  const indexResult = await verifyCatalogIndex();
  indexMarkManifest.textContent = indexResult.allOk ? '✓' : '✗';
  indexMarkManifest.className = 'mark ' + (indexResult.allOk ? 'ok' : 'bad');
  if (indexResult.allOk) {
    indexStatusManifest.textContent = 'manifest verified · ' + MANIFEST.entryCount + ' entries · published ' + MANIFEST.publishedAt;
    indexStatusManifest.style.color = 'var(--verify)';
  } else if (!indexResult.sigValid) {
    indexStatusManifest.textContent = 'manifest signature invalid · catalog tampered';
    indexStatusManifest.style.color = 'var(--fail)';
  } else {
    indexStatusManifest.textContent = 'entries list does not match manifest · ' + currentEntries.length + ' present, ' + MANIFEST.entryCount + ' expected';
    indexStatusManifest.style.color = 'var(--fail)';
  }

  // 2. Verify each individual entry's signature
  let entryOkCount = 0;
  for (const entry of currentEntries) {
    const ok = await verifyEntry(entry, pubForEntry(entry));
    if (ok) entryOkCount++;
  }
  const allEntriesOk = entryOkCount === currentEntries.length;
  indexMarkEntries.textContent = allEntriesOk ? '✓' : '✗';
  indexMarkEntries.className = 'mark ' + (allEntriesOk ? 'ok' : 'bad');
  indexStatusEntries.textContent = entryOkCount + '/' + currentEntries.length + ' entries verified';
  indexStatusEntries.style.color = allEntriesOk ? 'var(--verify)' : 'var(--fail)';

  // 3. Update the top publisher bar to summarize
  const allGood = indexResult.allOk && allEntriesOk;
  pubMark.textContent = allGood ? '✓' : '✗';
  pubStatus.textContent = allGood
    ? 'catalog integrity intact · index ✓ · entries ✓'
    : (indexResult.allOk ? entryOkCount + ' of ' + currentEntries.length + ' entries valid · index ✓' : 'catalog index tampered · set of entries does not match what publisher signed');
  pubStatus.classList.toggle('bad', !allGood);
  pubBar.style.borderLeftColor = allGood ? 'var(--verify)' : 'var(--fail)';

  // 4. Update card-level sig marks (only for entries currently in the catalog)
  document.querySelectorAll('.card').forEach(card => {
    const entry = currentEntries.find(e => e.id === card.dataset.id);
    if (entry) verifyCardInline(card, entry);
  });
}

document.getElementById('pubBar').addEventListener('click', verifyAll);
document.getElementById('indexBar').addEventListener('click', e => {
  // Only trigger re-verify if clicked outside the buttons
  if (e.target.tagName !== 'BUTTON') verifyAll();
});

// =============== Tamper demo ===============
const btnSimulate = document.getElementById('btnSimulateRemove');
const btnRestore = document.getElementById('btnRestoreIndex');
let removedEntry = null;
let removedCardEl = null;

btnSimulate.addEventListener('click', async () => {
  // Remove the last entry from currentEntries and hide its card visually
  if (currentEntries.length === 0) return;
  removedEntry = currentEntries[currentEntries.length - 1];
  currentEntries = currentEntries.slice(0, -1);

  removedCardEl = document.querySelector('.card[data-id="' + removedEntry.id + '"]');
  if (removedCardEl) {
    removedCardEl.style.opacity = '0.3';
    removedCardEl.style.filter = 'grayscale(1)';
    removedCardEl.style.borderStyle = 'dashed';
    removedCardEl.style.pointerEvents = 'none';
    const tag = removedCardEl.querySelector('.card-tag');
    if (tag) { tag.dataset.original = tag.textContent; tag.textContent = 'removed by tampering'; tag.style.color = 'var(--fail)'; }
  }

  btnSimulate.style.display = 'none';
  btnRestore.style.display = 'inline-block';
  btnRestore.classList.add('restore');

  // Re-run verify to show the index signature break
  await verifyAll();
});

btnRestore.addEventListener('click', async () => {
  if (!removedEntry) return;
  currentEntries = [...currentEntries, removedEntry];
  if (removedCardEl) {
    removedCardEl.style.opacity = '';
    removedCardEl.style.filter = '';
    removedCardEl.style.borderStyle = '';
    removedCardEl.style.pointerEvents = '';
    const tag = removedCardEl.querySelector('.card-tag');
    if (tag && tag.dataset.original) { tag.textContent = tag.dataset.original; tag.style.color = ''; }
  }
  removedEntry = null;
  removedCardEl = null;
  btnRestore.style.display = 'none';
  btnSimulate.style.display = 'inline-block';
  await verifyAll();
});

setTimeout(verifyAll, 350);
</script>

</body>
</html>