taxa-server 0.1.0

axum web server for taxa: reproduces the HTTP contract + serves the embedded D3 frontend.
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>taxa</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,500;1,400&family=Space+Mono:wght@400&display=swap">
  <!-- Relative URLs so the server-injected <base href> resolves them under the
       app's base path (/ at root, /<app>/ behind the internal LB). -->
  <link rel="stylesheet" href="static/style.css">
  <script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/topojson-client@3"></script>
</head>
<body>
  <!-- The shell is dataset-agnostic; app.js fills the title, tab nav, and
       content sections from /api/manifest at boot. -->
  <header>
    <div class="brand">
      <a href="." class="logo" aria-label="home"></a>
      <h1 id="page-title"><a href="." id="home-link">taxa</a></h1>
    </div>
    <div class="header-right">
      <button class="hamburger" id="toggle-sidebar" aria-label="toggle sidebar"></button>
    </div>
  </header>

  <div id="subheader">
    <nav id="tabs"></nav>
    <div class="subheader-right">
      <div id="entity-search-wrap">
        <input id="entity-search" type="text" autocomplete="off"
               placeholder="Search…" aria-label="Search">
        <ul id="entity-search-results" hidden></ul>
      </div>
    </div>
  </div>

  <div id="layout">
    <aside id="sidebar">
      <div id="sidebar-content"><p class="placeholder"></p></div>
    </aside>
    <main id="content"></main>
  </div>

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