<header class="site-header">
    <div class="header-inner">
        <div class="header-search">
            <div
                class="commander"
                onclick="
                    document
                        .getElementById('search-input')
                        .focus()
                "
            >
                <span class="commander-prompt">~</span>
                <input
                    type="text"
                    id="search-input"
                    autocomplete="off"
                    spellcheck="false"
                />
            </div>
            <div
                id="search-results"
                class="search-results"
            ></div>
        </div>
    </div>
</header>

<!-- Top-right contribute fab β€” mirrors the top-left identity
     header. Layout is reversed (label first, icon at the outer
     right edge) so icons sit at the two outermost corners and the
     labels read inward. -->
<a href="/contribute" class="contribute-fab" aria-label="Contribute">
    <span class="contribute-fab-name">contribute</span>
    <span class="contribute-fab-icon" aria-hidden="true"></span>
</a>

<!-- Toggle lives OUTSIDE the sidebar so it stays clickable when
     the sidebar slides offscreen on mobile (translateX(-100%)
     would otherwise sweep the toggle away with it). -->
<button
    class="sidebar-toggle"
    aria-label="Toggle sidebar"
    aria-expanded="false"
>
    <span></span><span></span><span></span>
</button>

<aside class="sidebar">
    <div class="sidebar-header">
        <a href="/" class="site-title">
            {%- for item in nav_menu if item.label == site.title and item.icon -%}
            <span class="site-icon" aria-hidden="true">{{ item.icon }}</span>
            {%- endfor -%}
            <span class="site-name">{{ site.title }}</span>
        </a>
    </div>

    <nav class="sidebar-nav" aria-label="Main navigation">
        {% if nav_menu is defined and nav_menu %}
        <ul class="sidebar-menu">
            {% for item in nav_menu %}
            {# Skip whichever item duplicates the site title β€” the
               title row above already shows it (with the matching
               icon). Position-independent: works whether the title
               item is first in menu-order or not. #}
            {% if item.label != site.title %}
            <li class="sidebar-item">
                <a
                    href="{{ item.url }}"
                    {%
                    if
                    item.external
                    %}target="_blank"
                    rel="noopener"
                    {%
                    endif
                    %}
                    {%
                    if
                    item.active
                    %}class="active"
                    {%
                    endif
                    %}
                >
                    {% if item.icon %}<span
                        class="sidebar-icon"
                        >{{ item.icon }}</span
                    >{% endif %}
                    <span class="sidebar-label"
                        >{{ item.label }}</span
                    >
                    {% if item.external %}<span
                        class="external-icon"
                        aria-hidden="true"
                        >&nearr;</span
                    >{% endif %}
                </a>
            </li>
            {% endif %}
            {% endfor %}
        </ul>
        {% endif %}

    </nav>

    <!-- Primary functions live INSIDE the sidebar's flex column so
         their geometry is inherited verbatim β€” same width, same
         left edge, same row format. .sidebar-nav has flex: 1 so
         the launcher gets pushed to the bottom of the sidebar
         automatically. -->
    <nav class="app-launcher" aria-label="Site sections">
    <ul class="sidebar-menu app-launcher-list">
        <li class="sidebar-item">
            <a href="/files">
                <span class="sidebar-icon" aria-hidden="true">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M9 3h7l4 4v11a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" />
                        <path d="M16 3v4h4" />
                        <path d="M5 7v13a2 2 0 0 0 2 2h10" opacity="0.55" />
                    </svg>
                </span>
                <span class="sidebar-label">Files</span>
            </a>
        </li>
        <li class="sidebar-item">
            <a href="/blog">
                <span class="sidebar-icon" aria-hidden="true">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
                        <circle cx="5" cy="7" r="1" fill="currentColor" stroke="none" />
                        <circle cx="5" cy="12" r="1" fill="currentColor" stroke="none" />
                        <circle cx="5" cy="17" r="1" fill="currentColor" stroke="none" />
                        <line x1="9" y1="7" x2="20" y2="7" />
                        <line x1="9" y1="12" x2="20" y2="12" />
                        <line x1="9" y1="17" x2="16" y2="17" />
                    </svg>
                </span>
                <span class="sidebar-label">Blog</span>
            </a>
        </li>
    </ul>
    {% if graph is defined and graph.enabled %}
    <a href="/graph" class="app-orb app-orb--main app-orb--graph" aria-label="Graph">
        <span class="app-orb-glyph" aria-hidden="true">
            <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" class="app-orb-graph-svg">
                <!-- Edges drawn first (under nodes). Opacity layered:
                     spokes from the central hub strongest, ring/perimeter
                     edges medium, outer leaf edges faintest. -->
                <g stroke="currentColor" stroke-linecap="round" fill="none">
                    <g stroke-width="1.1" opacity="0.7">
                        <line x1="50" y1="50" x2="32" y2="30" />
                        <line x1="50" y1="50" x2="68" y2="30" />
                        <line x1="50" y1="50" x2="78" y2="50" />
                        <line x1="50" y1="50" x2="68" y2="70" />
                        <line x1="50" y1="50" x2="32" y2="70" />
                        <line x1="50" y1="50" x2="22" y2="50" />
                    </g>
                    <g stroke-width="0.9" opacity="0.45">
                        <line x1="32" y1="30" x2="68" y2="30" />
                        <line x1="68" y1="30" x2="78" y2="50" />
                        <line x1="78" y1="50" x2="68" y2="70" />
                        <line x1="68" y1="70" x2="32" y2="70" />
                        <line x1="32" y1="70" x2="22" y2="50" />
                        <line x1="22" y1="50" x2="32" y2="30" />
                    </g>
                    <g stroke-width="0.8" opacity="0.35">
                        <line x1="32" y1="30" x2="20" y2="16" />
                        <line x1="32" y1="30" x2="38" y2="12" />
                        <line x1="68" y1="30" x2="62" y2="12" />
                        <line x1="68" y1="30" x2="80" y2="16" />
                        <line x1="78" y1="50" x2="92" y2="34" />
                        <line x1="78" y1="50" x2="94" y2="50" />
                        <line x1="78" y1="50" x2="92" y2="66" />
                        <line x1="68" y1="70" x2="80" y2="84" />
                        <line x1="68" y1="70" x2="62" y2="88" />
                        <line x1="32" y1="70" x2="38" y2="88" />
                        <line x1="32" y1="70" x2="20" y2="84" />
                        <line x1="22" y1="50" x2="8" y2="34" />
                        <line x1="22" y1="50" x2="6" y2="50" />
                        <line x1="22" y1="50" x2="8" y2="66" />
                    </g>
                </g>
                <!-- Nodes. Three sizes: hub, mid, leaf. -->
                <g fill="currentColor">
                    <circle cx="50" cy="50" r="4.5" />
                    <circle cx="32" cy="30" r="2.6" />
                    <circle cx="68" cy="30" r="2.6" />
                    <circle cx="78" cy="50" r="2.6" />
                    <circle cx="68" cy="70" r="2.6" />
                    <circle cx="32" cy="70" r="2.6" />
                    <circle cx="22" cy="50" r="2.6" />
                </g>
                <g fill="currentColor" opacity="0.75">
                    <circle cx="20" cy="16" r="1.5" />
                    <circle cx="38" cy="12" r="1.5" />
                    <circle cx="62" cy="12" r="1.5" />
                    <circle cx="80" cy="16" r="1.5" />
                    <circle cx="92" cy="34" r="1.5" />
                    <circle cx="94" cy="50" r="1.5" />
                    <circle cx="92" cy="66" r="1.5" />
                    <circle cx="80" cy="84" r="1.5" />
                    <circle cx="62" cy="88" r="1.5" />
                    <circle cx="38" cy="88" r="1.5" />
                    <circle cx="20" cy="84" r="1.5" />
                    <circle cx="8"  cy="66" r="1.5" />
                    <circle cx="6"  cy="50" r="1.5" />
                    <circle cx="8"  cy="34" r="1.5" />
                </g>
            </svg>
        </span>
    </a>
    {% endif %}
    </nav>
</aside>

<!-- Lunar machine time clock β€” bottom-right. Two-line readout:
     LMT date (year Β· moon Β· day-of-moon) on top, UTC time below.
     Clicking opens the /mt page (Machine Time spec). -->
<a href="/mt" class="lmt-clock" aria-label="Machine Time">
    <span class="lmt-clock-time" aria-hidden="true"></span>
    <span class="lmt-clock-date" aria-hidden="true"></span>
</a>

<script>
    (function () {
        var toggle = document.querySelector(
            ".sidebar-toggle",
        );
        var sidebar = document.querySelector(".sidebar");
        if (toggle && sidebar) {
            toggle.addEventListener("click", function () {
                var expanded =
                    toggle.getAttribute("aria-expanded") ===
                    "true";
                toggle.setAttribute(
                    "aria-expanded",
                    !expanded,
                );
                sidebar.classList.toggle("open");
            });
        }

        // Strip trailing slash for comparison so /cyb and /cyb/
        // both count as the same path.
        var path = window.location.pathname.replace(/\/$/, "");
        document
            .querySelectorAll(".sidebar-menu a, .app-launcher .app-orb")
            .forEach(function (a) {
                var href = (a.getAttribute("href") || "").replace(/\/$/, "");
                if (!href || href === "/") return;
                // Exact match OR href is a strict path prefix (next
                // char must be "/", not just any continuation β€” so
                // /cybics no longer matches /cyb's "active" rule).
                if (path === href || path.indexOf(href + "/") === 0) {
                    a.classList.add("active");
                }
            });

        // Lunar machine time β€” port of optica/src/lunar.rs.
        // Synodic period 29.53059 d, reference new moon
        // 2000-01-06 18:14 UTC (JD 2 451 550.26).
        var SYNODIC = 29.53059;
        var REF_NEW_MOON = 2451550.26;
        function julianDay(d) {
            var y = d.getUTCFullYear();
            var m = d.getUTCMonth() + 1;
            var day = d.getUTCDate();
            if (m <= 2) { y -= 1; m += 12; }
            var a = Math.floor(y / 100);
            var b = 2 - a + Math.floor(a / 4);
            return (
                Math.floor(365.25 * (y + 4716)) +
                Math.floor(30.6001 * (m + 1)) +
                day + b - 1524.5
            );
        }
        function lmtNow() {
            var now = new Date();
            var jd = julianDay(now);
            var lunarAge = ((jd - REF_NEW_MOON) % SYNODIC + SYNODIC) % SYNODIC;
            var dd = Math.min(Math.floor(lunarAge), 29) + 1;
            var yy = now.getUTCFullYear() - 1970;
            var yearStart = new Date(Date.UTC(now.getUTCFullYear(), 0, 1));
            var firstMoon = REF_NEW_MOON +
                Math.ceil((julianDay(yearStart) - REF_NEW_MOON) / SYNODIC) * SYNODIC;
            var mm = jd < firstMoon
                ? 1
                : Math.floor((jd - firstMoon) / SYNODIC) + 1;
            var hh = String(now.getUTCHours()).padStart(2, "0");
            var mn = String(now.getUTCMinutes()).padStart(2, "0");
            return {
                date: yy + " Β· " + mm + " Β· " + dd,
                time: hh + ":" + mn,
            };
        }
        var clockDate = document.querySelector(".lmt-clock-date");
        var clockTime = document.querySelector(".lmt-clock-time");
        if (clockDate && clockTime) {
            function tick() {
                var t = lmtNow();
                clockDate.textContent = t.date;
                clockTime.textContent = t.time;
            }
            tick();
            // Re-tick at the next minute boundary, then every minute.
            var msToMin = 60000 - (Date.now() % 60000);
            setTimeout(function () {
                tick();
                setInterval(tick, 60000);
            }, msToMin);
        }
    })();
</script>

Graph