florecon 0.2.2

Incremental financial reconciliation by min-cost flow: a conserving combinator algebra over a network-simplex core. Nothing created, nothing lost.
Documentation
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>florecon workbench</title>
    <link rel="stylesheet" href="./styles.css" />
    <!-- Bare `import "apache-arrow"` in the core/ingest modules resolves here.
         All client-side: the plugin wasm + your data never leave the browser. -->
    <script type="importmap">
      { "imports": { "apache-arrow": "https://esm.sh/apache-arrow@21" } }
    </script>
  </head>
  <body>
    <header>
      <h1>florecon <span class="dim">workbench</span></h1>
      <div id="domain" class="domain dim">no plugin loaded</div>
    </header>

    <!-- ── setup ────────────────────────────────────────────────────────── -->
    <section id="setup" class="card">
      <div class="row">
        <label class="field">
          <span>1 · plugin (.wasm)</span>
          <input id="wasm-file" type="file" accept=".wasm" />
        </label>
        <label class="field">
          <span>2 · data (.csv)</span>
          <input id="csv-file" type="file" accept=".csv,text/csv" />
        </label>
        <label class="field">
          <span>config (optional JSON)</span>
          <input id="config" type="text" placeholder='{"flow_window": 30}' />
        </label>
      </div>
      <div id="mapping" class="mapping hidden">
        <h3>3 · map columns <span class="dim">— each declared input column ← a CSV column</span></h3>
        <div id="map-grid" class="map-grid"></div>
        <div class="row">
          <button id="solve-btn" class="primary">solve →</button>
          <label class="field inline">
            <span>or restore a workspace</span>
            <input id="ws-file" type="file" accept=".json,application/json" />
          </label>
        </div>
      </div>
      <p id="setup-msg" class="msg"></p>
    </section>

    <!-- ── workbench ────────────────────────────────────────────────────── -->
    <section id="work" class="hidden">
      <div id="metrics" class="metrics"></div>

      <div class="toolbar">
        <button data-act="solve">re-solve</button>
        <button data-act="pin-clean">pin clean</button>
        <button data-act="merge">merge selection</button>
        <button data-act="tag">tag selection…</button>
        <span class="sep"></span>
        <button data-act="save">save workspace</button>
        <button data-act="export-groups">groups.csv</button>
        <button data-act="export-results">results.csv</button>
        <button data-act="export-json">result.json</button>
        <span id="work-msg" class="msg"></span>
      </div>

      <div class="panes">
        <aside id="facets" class="facets"></aside>
        <div class="center">
          <table id="groups" class="grid">
            <thead></thead>
            <tbody></tbody>
          </table>
          <table id="detail" class="grid">
            <thead></thead>
            <tbody></tbody>
          </table>
        </div>
      </div>
    </section>

    <script type="module" src="./app.js"></script>
  </body>
</html>