<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>mdlive: {{ current_file|default('preview') }}</title>
    <link rel="icon" type="image/png" href="/static/favicon.png" />

    <!-- Critical: Apply theme and sidebar state before first paint to prevent flash -->
    <script>
      (function () {
        try {
          // Apply theme immediately
          const theme = localStorage.getItem("theme") || "catppuccin-mocha";
          document.documentElement.setAttribute("data-theme", theme);

          // Restore saved sidebar width before paint
          const savedSidebarWidth = localStorage.getItem("sidebar-width");
          if (savedSidebarWidth) {
            document.documentElement.style.setProperty(
              "--sidebar-width",
              savedSidebarWidth + "px",
            );
          }

          // Restore content width before first paint to prevent FOUC
          const savedContentWidth = localStorage.getItem("content-width");
          const validWidths = ['narrow', 'default', 'wide', 'full'];
          if (savedContentWidth && validWidths.includes(savedContentWidth)) {
            document.documentElement.setAttribute("data-width", savedContentWidth);
          }

          // restore editor split ratio
          const savedSplit = localStorage.getItem("editor-split");
          if (savedSplit) {
            document.documentElement.style.setProperty(
              "--editor-split",
              savedSplit + "%",
            );
          }

          // Apply sidebar state to both html and body elements
          // This works because body inherits the collapsed state via CSS selectors
          const isSidebarCollapsed =
            localStorage.getItem("sidebar-collapsed") === "true";
          if (isSidebarCollapsed) {
            // Set on html first for early rendering
            document.documentElement.classList.add("sidebar-collapsed");

            // Transfer to body when available
            if (document.body) {
              document.body.classList.add("sidebar-collapsed");
            } else {
              document.addEventListener("DOMContentLoaded", function () {
                document.body.classList.add("sidebar-collapsed");
              });
            }
          }
        } catch(e) {
          /* localStorage unavailable — apply safe defaults */
          document.documentElement.setAttribute("data-theme", "catppuccin-mocha");
          document.documentElement.setAttribute("data-width", "default");
        } finally {
          document.documentElement.classList.add("theme-initialized");
        }
      })();
    </script>

    <script>
      // shared helper: epoch seconds → relative time label (compact)
      window.formatRelativeTime = function(epoch) {
          if (!epoch) return '';
          var now = Math.floor(Date.now() / 1000);
          var diff = Math.max(0, now - epoch);
          if (diff < 60) return 'now';
          if (diff < 3600) return Math.floor(diff / 60) + 'm';
          if (diff < 86400) return Math.floor(diff / 3600) + 'h';
          if (diff < 604800) return Math.floor(diff / 86400) + 'd';
          if (diff < 2592000) return Math.floor(diff / 604800) + 'w';
          if (diff < 31536000) return Math.floor(diff / 2592000) + 'mo';
          return Math.floor(diff / 31536000) + 'y';
      };
    </script>

    <style>
      /* Prevent flash by hiding content until theme is applied */
      html:not(.theme-initialized) body {
          opacity: 0;
      }

      html.theme-initialized body {
          opacity: 1;
          transition: opacity 0.1s ease-in;
      }

      /* Universal box-sizing */
      *, *::before, *::after {
          box-sizing: border-box;
      }

      :root {
          --bg-color: #fff;
          --text-color: #333;
          --border-color: #eaecef;
          --border-color-light: #dfe2e5;
          --code-bg: #f6f8fa;
          --blockquote-color: #6a737d;
          --link-color: #0366d6;
          --table-header-bg: #f6f8fa;
          --hl-keyword: #cf222e;
          --hl-string: #0a3069;
          --hl-number: #0550ae;
          --hl-comment: #6e7781;
          --hl-function: #8250df;
          --hl-built-in: #953800;
          --hl-literal: #0550ae;
          --hl-meta: #953800;
          --hl-attr: #953800;
          --sidebar-width: 250px;
          --sidebar-collapsed-width: 48px;
          --content-max-width: 900px;
          --transition-speed: 0.3s;
          --transition-timing: ease;
      }

      [data-theme="dark"] {
          --bg-color: #0d1117;
          --text-color: #e6edf3;
          --border-color: #30363d;
          --border-color-light: #21262d;
          --code-bg: #161b22;
          --blockquote-color: #8b949e;
          --link-color: #58a6ff;
          --table-header-bg: #161b22;
          --hl-keyword: #ff7b72;
          --hl-string: #a5d6ff;
          --hl-number: #79c0ff;
          --hl-comment: #8b949e;
          --hl-function: #d2a8ff;
          --hl-built-in: #ffa657;
          --hl-literal: #79c0ff;
          --hl-meta: #ffa657;
          --hl-attr: #79c0ff;
      }

      [data-theme="catppuccin-latte"] {
          --bg-color: #eff1f5;
          --text-color: #4c4f69;
          --border-color: #bcc0cc;
          --border-color-light: #ccd0da;
          --code-bg: #e6e9ef;
          --blockquote-color: #6c6f85;
          --link-color: #1e66f5;
          --table-header-bg: #ccd0da;
          --hl-keyword: #8839ef;
          --hl-string: #40a02b;
          --hl-number: #fe640b;
          --hl-comment: #9ca0b0;
          --hl-function: #1e66f5;
          --hl-built-in: #df8e1d;
          --hl-literal: #fe640b;
          --hl-meta: #d20f39;
          --hl-attr: #df8e1d;
      }

      [data-theme="catppuccin-macchiato"] {
          --bg-color: #24273a;
          --text-color: #cad3f5;
          --border-color: #494d64;
          --border-color-light: #363a4f;
          --code-bg: #1e2030;
          --blockquote-color: #a5adcb;
          --link-color: #8aadf4;
          --table-header-bg: #363a4f;
          --hl-keyword: #c6a0f6;
          --hl-string: #a6da95;
          --hl-number: #f5a97f;
          --hl-comment: #6e738d;
          --hl-function: #8aadf4;
          --hl-built-in: #eed49f;
          --hl-literal: #f5a97f;
          --hl-meta: #ed8796;
          --hl-attr: #eed49f;
      }

      [data-theme="catppuccin-mocha"] {
          --bg-color: #1e1e2e;
          --text-color: #cdd6f4;
          --border-color: #45475a;
          --border-color-light: #313244;
          --code-bg: #181825;
          --blockquote-color: #a6adc8;
          --link-color: #89b4fa;
          --table-header-bg: #313244;
          --hl-keyword: #cba6f7;
          --hl-string: #a6e3a1;
          --hl-number: #fab387;
          --hl-comment: #6c7086;
          --hl-function: #89b4fa;
          --hl-built-in: #f9e2af;
          --hl-literal: #fab387;
          --hl-meta: #f38ba8;
          --hl-attr: #f9e2af;
      }

      /* Common body styles */
      body {
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
          line-height: 1.6;
          color: var(--text-color);
          background-color: var(--bg-color);
          transition: background-color var(--transition-speed) var(--transition-timing),
                      color var(--transition-speed) var(--transition-timing);
      }

      {% if show_navigation %}
      /* ============================================
         Multi-file Navigation Layout
         ============================================ */

      html, body {
          margin: 0;
          padding: 0;
      }

      body {
          display: flex;
          max-width: none;
          height: 100vh;
          overflow: hidden;
      }

      /* Sidebar */
      .sidebar {
          width: var(--sidebar-width);
          min-width: var(--sidebar-width);
          background: var(--code-bg);
          border-right: 1px solid var(--border-color);
          padding: 0;
          height: 100vh;
          position: fixed;
          left: 0;
          top: 0;
          overflow-y: auto;
          transition: width var(--transition-speed) var(--transition-timing),
                      min-width var(--transition-speed) var(--transition-timing),
                      background var(--transition-speed) var(--transition-timing);
      }

      body.sidebar-collapsed .sidebar {
          width: var(--sidebar-collapsed-width);
          min-width: var(--sidebar-collapsed-width);
          overflow: hidden;
          background: var(--bg-color);
      }

      body.sidebar-resizing .sidebar,
      body.sidebar-resizing .page-container,
      body.sidebar-resizing #content,
      body.sidebar-resizing .sidebar-toggle {
          transition: none;
      }

      .sidebar-resize-handle {
          position: absolute;
          top: 0;
          right: 0;
          width: 4px;
          height: 100%;
          cursor: col-resize;
          z-index: 103;
      }

      .sidebar-resize-handle:hover,
      .sidebar-resize-handle.active {
          background: var(--link-color);
          opacity: 0.5;
      }

      body.sidebar-collapsed .sidebar-resize-handle {
          display: none;
      }

      .sidebar-header {
          height: 68px;
          display: flex;
          align-items: center;
          padding-left: 16px;
      }

      .sidebar-logo {
          height: 28px;
          width: auto;
          opacity: 0.9;
          transition: opacity 0.2s ease;
      }

      .sidebar-logo:hover {
          opacity: 1;
      }

      body.sidebar-collapsed .sidebar-logo {
          display: none;
      }

      .file-tree-parent {
          display: flex;
          align-items: center;
          gap: 6px;
          padding: 4px 10px;
          margin: 0 0 4px 0;
          cursor: pointer;
          font-family: var(--code-font);
          font-size: 13px;
          color: var(--blockquote-color);
          border-radius: 4px;
          transition: color 0.15s, background 0.15s;
          user-select: none;
      }

      .file-tree-parent:hover {
          color: var(--text-color);
          background: var(--code-bg);
      }

      body.sidebar-collapsed .file-tree-parent {
          display: none;
      }

      .sidebar-content {
          padding: 0 20px 20px 20px;
          opacity: 1;
          transition: opacity 0.2s var(--transition-timing);
      }

      body.sidebar-collapsed .sidebar-content {
          opacity: 0;
          pointer-events: none;
      }

      /* File Navigation Tree */
      .file-tree {
          list-style: none;
          padding: 0;
          margin: 0;
      }

      .file-tree ul {
          list-style: none;
          padding-left: 16px;
          margin: 0;
      }

      .file-tree li {
          margin-bottom: 2px;
      }

      .file-tree a {
          display: flex;
          justify-content: space-between;
          align-items: baseline;
          gap: 8px;
          padding: 6px 12px;
          color: var(--text-color);
          text-decoration: none;
          border-radius: 6px;
          transition: background 0.2s var(--transition-timing);
          font-size: 14px;
      }

      .file-tree a .file-name {
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          min-width: 0;
          flex: 1;
      }

      .file-tree a .file-icon {
          display: inline-block;
          flex-shrink: 0;
          width: 1.6em;
          font-size: 9px;
          font-weight: 600;
          letter-spacing: 0;
          text-align: center;
          line-height: 1.4;
          padding: 1px 2px;
          border-radius: 3px;
          border: 1px solid var(--blockquote-color);
          color: var(--blockquote-color);
          background: transparent;
          text-transform: uppercase;
          font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
          opacity: 0.85;
      }

      .file-tree a .file-icon::before { content: "?"; }
      .file-tree a .file-icon-markdown::before { content: "MD"; }
      .file-tree a .file-icon-json::before { content: "{}"; }
      .file-tree a .file-icon-csv::before { content: "CSV"; }
      .file-tree a .file-icon-yaml::before { content: "YML"; }
      .file-tree a .file-icon-toml::before { content: "TML"; }
      .file-tree a .file-icon-mermaid::before { content: "MMD"; }
      .file-tree a .file-icon-plaintext::before { content: "TXT"; }
      .file-tree a .file-icon-unknown::before { content: "·"; }

      .file-tree a:hover .file-icon,
      .file-tree a.active .file-icon {
          opacity: 1;
          border-color: currentColor;
          color: currentColor;
      }

      .file-tree a .file-ts {
          font-size: 11px;
          color: var(--blockquote-color);
          white-space: nowrap;
          flex-shrink: 0;
      }

      .file-tree a .file-ts {
          margin-left: 8px;
      }

      .file-tree a:hover,
      .file-tree a:focus-visible {
          background: var(--border-color-light);
          outline: none;
      }

      .file-tree a.active {
          background: var(--border-color-light);
          color: var(--text-color);
          font-weight: 600;
      }

      .sidebar-search {
          padding: 0 20px 12px 20px;
      }

      .sidebar-search input {
          width: 100%;
          padding: 6px 10px;
          font-size: 13px;
          background: var(--bg-color);
          color: var(--text-color);
          border: 1px solid var(--border-color);
          border-radius: 6px;
          outline: none;
          font-family: inherit;
          transition: border-color 0.2s var(--transition-timing),
                      background 0.2s var(--transition-timing);
      }

      .sidebar-search input:focus {
          border-color: var(--link-color);
      }

      .sidebar-search input::placeholder {
          color: var(--blockquote-color);
      }

      body.sidebar-collapsed .sidebar-search {
          opacity: 0;
          pointer-events: none;
      }

      .sidebar-sort {
          padding: 0 20px 12px 20px;
      }

      .sidebar-sort select {
          width: 100%;
          padding: 6px 10px;
          font-size: 13px;
          background: var(--bg-color);
          color: var(--text-color);
          border: 1px solid var(--border-color);
          border-radius: 6px;
          outline: none;
          font-family: inherit;
          cursor: pointer;
          transition: border-color 0.2s var(--transition-timing),
                      background 0.2s var(--transition-timing);
      }

      .sidebar-sort select:focus {
          border-color: var(--link-color);
      }

      body.sidebar-collapsed .sidebar-sort {
          opacity: 0;
          pointer-events: none;
      }

      .file-tree li.search-hidden {
          display: none;
      }

      .file-tree summary {
          padding: 6px 12px;
          cursor: pointer;
          font-size: 14px;
          font-weight: 600;
          color: var(--text-color);
          border-radius: 6px;
      }

      .file-tree summary:hover {
          background: var(--border-color-light);
      }

      /* Main Content Area */
      #content {
          margin-left: auto;
          margin-right: auto;
          max-width: var(--content-max-width);
          padding: 20px;
          min-height: 100vh;
      }

      #content.content-code {
          max-width: none;
          padding: 12px 20px;
      }

      #content.content-code pre {
          overflow-x: auto;
      }

      /* Sidebar Toggle Button */
      .sidebar-toggle {
          position: fixed;
          top: 20px;
          left: calc(var(--sidebar-width) - 52px);
          background: transparent;
          border: none;
          border-radius: 6px;
          padding: 8px;
          cursor: w-resize;
          font-size: 18px;
          color: var(--text-color);
          transition: left var(--transition-speed) var(--transition-timing),
                      background 0.2s var(--transition-timing);
          width: 40px;
          height: 40px;
          display: flex;
          align-items: center;
          justify-content: center;
          z-index: 102;
      }

      .sidebar-toggle:hover,
      .sidebar-toggle:focus-visible {
          background: var(--border-color-light);
          outline: none;
      }

      body.sidebar-collapsed .sidebar-toggle {
          left: 4px;
          cursor: e-resize;
      }

      /* Tab Bar */
      .tab-bar {
          position: fixed;
          top: 0;
          left: var(--sidebar-width);
          right: 0;
          height: 36px;
          display: flex;
          flex-direction: row;
          align-items: stretch;
          background: var(--code-bg);
          border-bottom: 1px solid var(--border-color);
          z-index: 10;
          transition: left var(--transition-speed) var(--transition-timing),
                      background var(--transition-speed) var(--transition-timing);
      }

      body.sidebar-collapsed .tab-bar {
          left: var(--sidebar-collapsed-width);
      }

      body.sidebar-resizing .tab-bar {
          transition: none;
      }

      .tab-scroll {
          display: flex;
          flex: 1 1 0;
          min-width: 0;
          overflow: hidden;
          align-items: stretch;
      }

      .tab {
          display: flex;
          align-items: center;
          gap: 6px;
          padding: 0 10px;
          height: 100%;
          cursor: pointer;
          border-right: 1px solid var(--border-color);
          white-space: nowrap;
          font-size: 13px;
          color: var(--text-color);
          background: transparent;
          user-select: none;
          -webkit-user-drag: element;
          flex-shrink: 0;
          transition: background 0.15s ease;
      }

      .tab:hover {
          background: var(--border-color-light);
      }

      .tab.active {
          background: var(--bg-color);
          font-weight: 600;
          border-bottom: 2px solid var(--link-color);
      }

      .tab.dragging {
          opacity: 0.4;
      }

      .tab.drop-before {
          box-shadow: inset 2px 0 0 0 var(--link-color);
      }

      .tab.drop-after {
          box-shadow: inset -2px 0 0 0 var(--link-color);
      }

      .tab-dirty {
          width: 6px;
          height: 6px;
          border-radius: 50%;
          background: var(--link-color);
          display: none;
          flex-shrink: 0;
      }

      .tab.dirty .tab-dirty {
          display: inline-block;
      }

      .tab-name {
          max-width: 160px;
          overflow: hidden;
          text-overflow: ellipsis;
      }

      .tab-close {
          display: flex;
          align-items: center;
          justify-content: center;
          width: 16px;
          height: 16px;
          border: none;
          background: none;
          color: var(--text-color);
          opacity: 0.4;
          cursor: pointer;
          padding: 0;
          font-size: 14px;
          line-height: 1;
          border-radius: 3px;
          flex-shrink: 0;
      }

      .tab-close:hover {
          opacity: 1;
          background: var(--border-color-light);
      }

      /* overflow chevron */
      .tab-overflow-btn {
          display: none;
          align-items: center;
          justify-content: center;
          width: 32px;
          flex-shrink: 0;
          border: none;
          border-left: 1px solid var(--border-color);
          background: var(--code-bg);
          color: var(--text-color);
          cursor: pointer;
          font-size: 14px;
          opacity: 0.6;
          position: relative;
      }
      .tab-overflow-btn:hover { opacity: 1; }
      .tab-overflow-btn.visible { display: flex; }

      .tab-overflow-badge {
          position: absolute;
          top: 4px;
          right: 3px;
          min-width: 14px;
          height: 14px;
          border-radius: 7px;
          background: var(--link-color);
          color: var(--bg-color);
          font-size: 9px;
          font-weight: 700;
          line-height: 14px;
          text-align: center;
          padding: 0 3px;
          pointer-events: none;
      }

      /* overflow dropdown */
      .tab-overflow-menu {
          display: none;
          position: absolute;
          top: 36px;
          right: 0;
          min-width: 220px;
          max-width: 360px;
          max-height: 400px;
          overflow-y: auto;
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 6px;
          box-shadow: 0 4px 16px rgba(0,0,0,0.18);
          z-index: 100;
          padding: 4px 0;
      }
      .tab-overflow-menu.show { display: block; }

      .tab-overflow-item {
          display: flex;
          align-items: center;
          gap: 8px;
          padding: 6px 10px;
          cursor: pointer;
          font-size: 13px;
          color: var(--text-color);
          white-space: nowrap;
          overflow: hidden;
      }
      .tab-overflow-item:hover {
          background: var(--border-color-light);
      }
      .tab-overflow-item.active {
          font-weight: 600;
          color: var(--link-color);
      }
      .tab-overflow-item .tab-dirty {
          display: none;
      }
      .tab-overflow-item.dirty .tab-dirty {
          display: inline-block;
      }
      .tab-overflow-item .tab-name {
          flex: 1 1 auto;
          min-width: 0;
          max-width: none;
          overflow: hidden;
          text-overflow: ellipsis;
      }

      .has-tabs .page-container,
      .has-tabs .editor-container {
          padding-top: 36px;
      }

      {% else %}
      /* Single-file layout */
      html, body {
          margin: 0;
          padding: 0;
      }
      body {
          height: 100vh;
          overflow: hidden;
      }
      .page-container {
          max-width: var(--content-max-width);
          margin: 0 auto;
      }
      .page-container:has(#content.content-code) {
          max-width: none;
      }
      {% endif %}

      /* Context Menu */
      .context-menu {
          display: none;
          position: fixed;
          z-index: 1001;
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 8px;
          padding: 4px;
          min-width: 180px;
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
      }

      .context-menu.show {
          display: block;
      }

      .context-menu-item {
          display: block;
          width: 100%;
          padding: 8px 12px;
          background: none;
          border: none;
          color: var(--text-color);
          font-size: 13px;
          text-align: left;
          cursor: pointer;
          border-radius: 4px;
          font-family: inherit;
      }

      .context-menu-item:hover {
          background: var(--border-color-light);
      }

      .context-menu-item.destructive {
          color: #e64553;
      }

      .context-menu-item.destructive:hover {
          background: rgba(230, 69, 83, 0.1);
      }

      /* File Dialog */
      .file-dialog-overlay {
          display: none;
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: rgba(0, 0, 0, 0.5);
          z-index: 1002;
          backdrop-filter: blur(4px);
      }

      .file-dialog-overlay.show {
          display: flex;
          align-items: center;
          justify-content: center;
      }

      .file-dialog {
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 12px;
          padding: 24px;
          max-width: 500px;
          width: 90%;
      }

      .file-dialog h3 {
          margin: 0 0 16px 0;
          color: var(--text-color);
          font-size: 16px;
      }

      .file-dialog input {
          width: 100%;
          padding: 8px 12px;
          font-size: 14px;
          background: var(--code-bg);
          color: var(--text-color);
          border: 1px solid var(--border-color);
          border-radius: 6px;
          outline: none;
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
      }

      .file-dialog input:focus {
          border-color: var(--link-color);
      }

      .file-dialog-hint {
          font-size: 12px;
          color: var(--blockquote-color);
          margin-top: 6px;
      }

      .file-dialog-error {
          font-size: 13px;
          color: #e64553;
          margin-top: 8px;
          display: none;
      }

      .file-dialog-buttons {
          display: flex;
          justify-content: flex-end;
          gap: 8px;
          margin-top: 16px;
      }

      .file-dialog-buttons button {
          padding: 8px 16px;
          border-radius: 6px;
          border: 1px solid var(--border-color);
          cursor: pointer;
          font-size: 13px;
          font-family: inherit;
      }

      .file-dialog-btn-cancel {
          background: transparent;
          color: var(--text-color);
      }

      .file-dialog-btn-cancel:hover {
          background: var(--border-color-light);
      }

      .file-dialog-btn-confirm {
          background: var(--link-color);
          color: #fff;
          border-color: var(--link-color);
      }

      .file-dialog-btn-confirm:hover {
          opacity: 0.9;
      }

      .confirm-dialog-message {
          margin: 0 0 16px 0;
          font-size: 14px;
          color: var(--text-color);
          line-height: 1.5;
      }

      .alert-dialog-detail {
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
          font-size: 13px;
          opacity: 0.8;
      }

      .file-dialog-btn-destructive {
          background: #e64553;
          color: #fff;
          border-color: #e64553;
      }

      .file-dialog-btn-destructive:hover {
          opacity: 0.9;
      }

      .footer-toggles {
          position: fixed;
          bottom: 20px;
          right: 20px;
          display: flex;
          gap: 8px;
          z-index: 100;
      }

      .footer-toggles > button {
          width: 40px;
          height: 36px;
          padding: 0;
          display: inline-flex;
          align-items: center;
          justify-content: center;
          background: var(--code-bg);
          border: 1px solid var(--border-color-light);
          border-radius: 6px;
          cursor: pointer;
          font-size: 14px;
          color: var(--text-color);
          transition: background 0.2s var(--transition-timing),
                      border-color var(--transition-speed) var(--transition-timing);
      }

      .footer-toggles > button:hover,
      .footer-toggles > button:focus-visible {
          background: var(--border-color-light);
          outline: none;
      }

      .theme-toggle {
          font-size: 18px;
          line-height: 1;
      }

      .edit-toggle {
          background: var(--code-bg);
          border: 1px solid var(--border-color-light);
          border-radius: 6px;
          padding: 8px;
          cursor: pointer;
          color: var(--text-color);
          transition: background 0.2s var(--transition-timing),
                      border-color var(--transition-speed) var(--transition-timing);
          text-decoration: none;
          display: flex;
          align-items: center;
          justify-content: center;
      }

      .edit-toggle:hover,
      .edit-toggle:focus-visible {
          background: var(--border-color-light);
          outline: none;
          text-decoration: none;
      }

      .theme-modal {
          display: none;
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: rgba(0, 0, 0, 0.5);
          z-index: 1000;
          backdrop-filter: blur(4px);
      }

      .theme-modal.show {
          display: flex;
          align-items: center;
          justify-content: center;
      }

      .theme-modal-content {
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 12px;
          padding: 24px;
          max-width: 600px;
          width: 90%;
          max-height: 80vh;
          overflow-y: auto;
      }

      .theme-modal h3 {
          margin: 0 0 20px 0;
          color: var(--text-color);
          font-size: 18px;
          text-align: center;
      }

      .theme-grid {
          display: grid;
          grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
          gap: 16px;
      }

      .theme-card {
          border: 2px solid transparent;
          border-radius: 8px;
          padding: 16px;
          cursor: pointer;
          transition: all 0.2s ease;
          text-align: center;
      }

      .theme-card:hover {
          transform: translateY(-2px);
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
      }

      .theme-card.selected {
          border-color: var(--link-color);
          box-shadow: 0 0 0 1px var(--link-color);
      }

      .theme-card-icon {
          font-size: 24px;
          margin-bottom: 8px;
      }

      .theme-card-name {
          font-size: 14px;
          font-weight: 600;
          margin-bottom: 12px;
      }

      .theme-card-preview {
          display: flex;
          gap: 4px;
          justify-content: center;
          margin-bottom: 8px;
      }

      .theme-color-swatch {
          width: 16px;
          height: 16px;
          border-radius: 3px;
          border: 1px solid rgba(0, 0, 0, 0.1);
      }

      .theme-card-sample {
          font-size: 11px;
          opacity: 0.8;
      }

      .find-bar {
          display: none;
          position: fixed;
          top: 12px;
          right: 16px;
          z-index: 10000;
          background: var(--code-bg, var(--bg-color));
          color: var(--text-color);
          border: 1px solid var(--border-color);
          border-radius: 8px;
          box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
          padding: 6px 8px;
          align-items: center;
          gap: 6px;
          font-size: 13px;
      }
      .find-bar.show { display: flex; }
      .find-bar input {
          width: 220px;
          padding: 4px 8px;
          background: var(--bg-color);
          color: var(--text-color);
          border: 1px solid var(--border-color);
          border-radius: 4px;
          outline: none;
          font-family: inherit;
          font-size: 13px;
      }
      .find-bar input:focus { border-color: var(--link-color); }
      .find-bar .find-count {
          min-width: 56px;
          text-align: center;
          opacity: 0.75;
          font-variant-numeric: tabular-nums;
          font-size: 12px;
      }
      .find-bar button {
          background: transparent;
          color: var(--text-color);
          border: 1px solid var(--border-color);
          border-radius: 4px;
          width: 24px;
          height: 24px;
          line-height: 1;
          cursor: pointer;
          font-size: 14px;
          padding: 0;
      }
      .find-bar button:hover { border-color: var(--link-color); }
      mark.find-hit {
          background: #ffe066;
          color: #000;
          border-radius: 2px;
          padding: 0 1px;
      }
      mark.find-hit.active {
          background: #ff8c1a;
          color: #000;
          outline: 1px solid #ff8c1a;
      }

      .shortcuts-modal {
          display: none;
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: rgba(0, 0, 0, 0.5);
          z-index: 1000;
          backdrop-filter: blur(4px);
      }

      .shortcuts-modal.show {
          display: flex;
          align-items: center;
          justify-content: center;
      }

      .shortcuts-modal-content {
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 12px;
          padding: 24px;
          max-width: 420px;
          width: 90%;
          max-height: 80vh;
          overflow-y: auto;
      }

      .shortcuts-modal h3 {
          margin: 0 0 16px 0;
          color: var(--text-color);
          font-size: 18px;
          text-align: center;
      }

      .shortcuts-table {
          width: 100%;
          border-collapse: collapse;
      }

      .shortcuts-table td {
          padding: 6px 12px;
          color: var(--text-color);
      }

      .shortcuts-table tr + tr td {
          border-top: 1px solid var(--border-color-light);
      }

      .shortcuts-key {
          display: inline-block;
          background: var(--code-bg);
          border: 1px solid var(--border-color-light);
          border-radius: 4px;
          padding: 2px 8px;
          font-family: var(--code-font);
          font-size: 13px;
          min-width: 24px;
          text-align: center;
      }

      .about-modal {
          display: none;
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: rgba(0, 0, 0, 0.5);
          z-index: 1000;
          backdrop-filter: blur(4px);
      }

      .about-modal.show {
          display: flex;
          align-items: center;
          justify-content: center;
      }

      .about-modal-content {
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 12px;
          padding: 24px 32px;
          max-width: 380px;
          width: 90%;
          text-align: center;
      }

      .about-logo {
          width: 180px;
          margin-bottom: 12px;
      }

      .about-company {
          font-size: 14px;
          color: var(--blockquote-color);
          margin: 0 0 8px 0;
      }

      .about-github {
          display: inline-flex;
          align-items: center;
          gap: 6px;
          color: var(--link-color);
          text-decoration: none;
          font-size: 13px;
          margin-bottom: 16px;
      }

      .about-github:hover {
          text-decoration: underline;
      }

      .about-github svg {
          flex-shrink: 0;
      }

      .about-divider {
          border: none;
          border-top: 1px solid var(--border-color-light);
          margin: 0 0 16px 0;
      }

      .about-attribution {
          font-size: 13px;
          color: var(--blockquote-color);
          margin: 0 0 16px 0;
          font-style: italic;
      }

      .about-libs {
          text-align: left;
          margin: 0;
          padding: 0;
          list-style: none;
      }

      .about-libs-heading {
          font-size: 12px;
          color: var(--blockquote-color);
          text-transform: uppercase;
          letter-spacing: 0.5px;
          margin-bottom: 8px;
          text-align: left;
      }

      .about-libs li {
          display: flex;
          justify-content: space-between;
          padding: 4px 0;
          font-size: 13px;
          color: var(--text-color);
          border-top: 1px solid var(--border-color-light);
      }

      .about-libs li span:last-child {
          color: var(--blockquote-color);
          font-size: 12px;
      }

      .about-license {
          font-size: 12px;
          color: var(--blockquote-color);
          margin: 16px 0 0 0;
      }

      .workspace-modal {
          display: none;
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: rgba(0, 0, 0, 0.5);
          z-index: 1000;
          backdrop-filter: blur(4px);
      }

      .workspace-modal.show {
          display: flex;
          align-items: center;
          justify-content: center;
      }

      .workspace-modal-content {
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 12px;
          padding: 24px 32px;
          max-width: 680px;
          width: 90%;
      }

      .workspace-modal h3 {
          margin: 0 0 16px 0;
          color: var(--text-color);
          font-size: 18px;
          text-align: center;
      }

      .workspace-path-input {
          width: 100%;
          padding: 10px 14px;
          font-size: 15px;
          font-family: var(--code-font);
          background: var(--code-bg);
          color: var(--text-color);
          border: 1px solid var(--border-color-light);
          border-radius: 6px;
          outline: none;
      }

      .workspace-path-input:focus {
          border-color: var(--link-color);
      }

      .workspace-path-input::placeholder {
          color: var(--blockquote-color);
      }

      .workspace-error {
          color: #e74c3c;
          font-size: 13px;
          margin: 8px 0 0 0;
          display: none;
      }

      .workspace-recent-heading {
          font-size: 13px;
          color: var(--blockquote-color);
          margin: 20px 0 8px 0;
          text-transform: uppercase;
          letter-spacing: 0.5px;
      }

      .workspace-recent-filter {
          width: 100%;
          padding: 7px 12px;
          font-size: 13px;
          font-family: var(--code-font);
          background: var(--code-bg);
          color: var(--text-color);
          border: 1px solid var(--border-color-light);
          border-radius: 6px;
          outline: none;
          margin: 0 0 8px 0;
          box-sizing: border-box;
      }
      .workspace-recent-filter:focus {
          border-color: var(--link-color);
      }
      .workspace-recent-filter::placeholder {
          color: var(--blockquote-color);
      }

      .workspace-recent-list {
          list-style: none;
          margin: 0;
          padding: 0;
          max-height: 320px;
          overflow-y: auto;
      }

      .workspace-recent-item {
          display: flex;
          align-items: center;
          padding: 8px 12px;
          border-radius: 6px;
          cursor: pointer;
          transition: background 0.15s;
          gap: 10px;
      }

      .workspace-recent-item:hover {
          background: var(--code-bg);
      }
      .workspace-recent-item.active {
          background: var(--link-color);
          color: #fff;
      }
      .workspace-recent-item.active .workspace-recent-path {
          color: #fff;
      }

      .workspace-recent-icon {
          font-size: 16px;
          flex-shrink: 0;
          width: 20px;
          text-align: center;
      }

      .workspace-recent-ts {
          font-size: 11px;
          color: var(--blockquote-color);
          flex-shrink: 0;
          font-variant-numeric: tabular-nums;
          margin-left: 8px;
      }
      .workspace-recent-item.active .workspace-recent-ts {
          color: rgba(255, 255, 255, 0.85);
      }

      .workspace-recent-path {
          font-family: var(--code-font);
          font-size: 13px;
          color: var(--text-color);
          flex: 1;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
      }

      .workspace-empty {
          text-align: center;
          color: var(--blockquote-color);
          font-size: 14px;
          padding: 24px 0;
      }

      .workspace-input-row {
          display: flex;
          gap: 8px;
      }
      .workspace-input-row .workspace-path-input {
          flex: 1;
          min-width: 0;
      }
      .workspace-browse-btn {
          padding: 8px 14px;
          font-size: 14px;
          background: var(--code-bg);
          color: var(--text-color);
          border: 1px solid var(--border-color-light);
          border-radius: 6px;
          cursor: pointer;
          flex-shrink: 0;
          display: flex;
          align-items: center;
          gap: 6px;
          transition: background 0.15s;
      }
      .workspace-browse-btn:hover {
          background: var(--border-color);
      }
      .workspace-open-btn {
          padding: 8px 18px;
          font-size: 14px;
          font-weight: 500;
          background: var(--link-color);
          color: #fff;
          border: 1px solid var(--link-color);
          border-radius: 6px;
          cursor: pointer;
          flex-shrink: 0;
          transition: opacity 0.15s;
      }
      .workspace-open-btn:hover {
          opacity: 0.9;
      }
      .browse-modal {
          display: none;
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background: rgba(0, 0, 0, 0.5);
          z-index: 1100;
          backdrop-filter: blur(4px);
      }
      .browse-modal.show {
          display: flex;
          align-items: center;
          justify-content: center;
      }
      .browse-modal-content {
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 12px;
          padding: 0;
          max-width: 640px;
          width: 90%;
          max-height: 80vh;
          display: flex;
          flex-direction: column;
          overflow: hidden;
      }
      .browse-modal-header {
          display: flex;
          align-items: center;
          gap: 8px;
          padding: 12px 16px;
          border-bottom: 1px solid var(--border-color);
          flex-shrink: 0;
      }
      .browse-modal-header h3 {
          margin: 0;
          font-size: 16px;
          color: var(--text-color);
          flex: 1;
      }
      .browse-modal-close {
          background: none;
          border: none;
          cursor: pointer;
          color: var(--blockquote-color);
          font-size: 18px;
          padding: 2px 8px;
          border-radius: 4px;
          line-height: 1;
      }
      .browse-modal-close:hover {
          background: var(--border-color);
          color: var(--text-color);
      }
      .browse-modal-bar {
          display: flex;
          align-items: center;
          gap: 8px;
          padding: 8px 16px;
          border-bottom: 1px solid var(--border-color);
          background: var(--code-bg);
          flex-shrink: 0;
      }
      .browse-modal-up {
          background: none;
          border: 1px solid var(--border-color-light);
          cursor: pointer;
          color: var(--text-color);
          font-size: 14px;
          padding: 4px 8px;
          border-radius: 4px;
          flex-shrink: 0;
      }
      .browse-modal-up:hover {
          background: var(--border-color);
      }
      .browse-modal-path {
          font-family: var(--code-font);
          font-size: 13px;
          color: var(--text-color);
          background: var(--bg-color);
          border: 1px solid var(--border-color-light);
          border-radius: 4px;
          padding: 4px 8px;
          flex: 1;
          min-width: 0;
          outline: none;
      }
      .browse-modal-path:focus {
          border-color: var(--link-color);
      }
      .browse-modal-list {
          list-style: none;
          margin: 0;
          padding: 0;
          overflow-y: auto;
          flex: 1;
      }
      .browse-modal-item {
          display: flex;
          align-items: center;
          padding: 6px 16px 6px 0;
          cursor: pointer;
          gap: 6px;
          font-family: var(--code-font);
          font-size: 13px;
          color: var(--text-color);
          transition: background 0.1s;
      }
      .browse-modal-item:hover {
          background: var(--code-bg);
      }
      .browse-modal-item.selected {
          background: var(--link-color);
          color: #fff;
      }
      .browse-modal-item.selected:hover {
          opacity: 0.9;
      }
      .browse-modal-item-icon {
          flex-shrink: 0;
          width: 18px;
          text-align: center;
          font-size: 15px;
      }
      .browse-modal-item-name {
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
      }
      .browse-tree-arrow {
          flex-shrink: 0;
          width: 16px;
          text-align: center;
          font-size: 10px;
          color: var(--blockquote-color);
          cursor: pointer;
          user-select: none;
          line-height: 1;
          transition: transform 0.15s;
      }
      .browse-tree-arrow:hover {
          color: var(--text-color);
      }
      .browse-tree-arrow.expanded {
          transform: rotate(90deg);
      }
      .browse-tree-arrow-placeholder {
          flex-shrink: 0;
          width: 16px;
      }
      .browse-tree-loading {
          font-size: 12px;
          color: var(--blockquote-color);
          font-style: italic;
          cursor: default;
      }
      .browse-modal-controls {
          display: flex;
          align-items: center;
          gap: 12px;
          padding: 6px 16px;
          border-bottom: 1px solid var(--border-color);
          background: var(--code-bg);
          flex-shrink: 0;
          font-size: 12px;
          color: var(--blockquote-color);
      }
      .browse-modal-controls label {
          display: flex;
          align-items: center;
          gap: 4px;
          cursor: pointer;
          user-select: none;
      }
      .browse-modal-controls label:hover {
          color: var(--text-color);
      }
      .browse-modal-controls input[type="checkbox"] {
          margin: 0;
          cursor: pointer;
      }
      .browse-sort-btn {
          background: none;
          border: 1px solid var(--border-color-light);
          border-radius: 4px;
          padding: 2px 8px;
          font-size: 12px;
          cursor: pointer;
          color: var(--blockquote-color);
          font-family: var(--code-font);
      }
      .browse-sort-btn:hover {
          color: var(--text-color);
          background: var(--border-color);
      }
      .browse-sort-btn.active {
          color: var(--link-color);
          border-color: var(--link-color);
      }
      .browse-modal-item-time {
          margin-left: auto;
          flex-shrink: 0;
          font-size: 11px;
          color: var(--blockquote-color);
          padding-right: 16px;
      }
      .browse-modal-footer {
          display: flex;
          align-items: center;
          justify-content: flex-end;
          gap: 8px;
          padding: 12px 16px;
          border-top: 1px solid var(--border-color);
          flex-shrink: 0;
      }
      .browse-modal-btn {
          padding: 6px 16px;
          font-size: 13px;
          border-radius: 6px;
          cursor: pointer;
          border: 1px solid var(--border-color-light);
          background: var(--code-bg);
          color: var(--text-color);
      }
      .browse-modal-btn:hover {
          background: var(--border-color);
      }
      .browse-modal-btn-primary {
          background: var(--link-color);
          color: #fff;
          border-color: var(--link-color);
      }
      .browse-modal-btn-primary:hover {
          opacity: 0.9;
      }

      .workspace-picker-page {
          display: flex;
          align-items: center;
          justify-content: center;
          height: 100vh;
          overflow-y: auto;
          position: relative;
      }

      .workspace-picker-version {
          position: absolute;
          bottom: 16px;
          right: 16px;
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
          font-size: 11px;
          opacity: 0.35;
          color: var(--blockquote-color);
      }

      .workspace-picker-page .workspace-modal-content {
          max-width: 680px;
      }

      .workspace-picker-page .workspace-picker-card {
          max-width: 820px;
      }
      .workspace-picker-cols {
          display: flex;
          gap: 28px;
          align-items: stretch;
      }
      .picker-col-left {
          flex: 1.3;
          min-width: 0;
          display: flex;
          flex-direction: column;
      }
      .picker-col-left .workspace-recent-heading {
          margin-top: 0;
      }
      .picker-col-left .workspace-recent-list {
          flex: 1;
          max-height: 360px;
      }
      .picker-col-right {
          width: 240px;
          flex-shrink: 0;
          border-left: 1px solid var(--border-color);
          padding-left: 28px;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
      }
      .picker-col-right img {
          width: 190px;
          display: block;
          margin: 0 auto 12px;
      }
      .picker-col-right h3 {
          margin: 0 0 16px 0;
          font-size: 16px;
          color: var(--text-color);
          text-align: center;
      }
      .picker-col-right .workspace-path-input {
          width: 100%;
          margin-bottom: 8px;
      }
      .picker-btn-block {
          width: 100%;
          justify-content: center;
          margin-bottom: 8px;
      }
      .picker-col-right .workspace-error {
          width: 100%;
          text-align: center;
      }

      @media (max-width: 620px) {
          .workspace-picker-cols { flex-direction: column; }
          .picker-col-right {
              width: 100%;
              border-left: none;
              padding-left: 0;
              border-top: 1px solid var(--border-color);
              padding-top: 16px;
          }
      }

      /* Content width presets */
      :root[data-width="narrow"]     { --content-max-width: 680px; }
      /* [data-width="default"] uses :root default of 900px — no override needed */
      :root[data-width="wide"]       { --content-max-width: 1200px; }
      :root[data-width="full"]       { --content-max-width: 100%; }

      .width-card {
          border: 2px solid transparent;
          border-radius: 8px;
          padding: 16px;
          cursor: pointer;
          transition: all 0.2s ease;
          text-align: center;
          background: var(--code-bg);
          color: var(--text-color);
      }

      .width-card:hover {
          transform: translateY(-2px);
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
      }

      .width-card.selected {
          border-color: var(--link-color);
          box-shadow: 0 0 0 1px var(--link-color);
      }

      /* Theme-specific card styles */
      .theme-card[data-theme="light"] {
          background: #fff;
          color: #333;
      }

      .theme-card[data-theme="dark"] {
          background: #0d1117;
          color: #e6edf3;
      }

      .theme-card[data-theme="catppuccin-latte"] {
          background: #eff1f5;
          color: #4c4f69;
      }

      .theme-card[data-theme="catppuccin-macchiato"] {
          background: #24273a;
          color: #cad3f5;
      }

      .theme-card[data-theme="catppuccin-mocha"] {
          background: #1e1e2e;
          color: #cdd6f4;
      }

      pre {
          background-color: var(--code-bg);
          border-radius: 6px;
          padding: 16px;
          overflow: auto;
          position: relative;
      }

      pre .copy-btn {
          position: absolute;
          top: 8px;
          right: 8px;
          background: transparent;
          border: 1px solid var(--border-color);
          border-radius: 4px;
          padding: 4px 6px;
          cursor: pointer;
          color: var(--blockquote-color);
          opacity: 0;
          transition: opacity 0.2s ease, background 0.2s ease;
          line-height: 1;
          display: flex;
          align-items: center;
          justify-content: center;
      }

      pre:hover .copy-btn {
          opacity: 1;
      }

      pre .copy-btn:hover {
          background: var(--border-color-light);
          color: var(--text-color);
      }

      pre .copy-btn.copied {
          opacity: 1;
          color: #a6e3a1;
          border-color: #a6e3a1;
      }
      code {
          background-color: var(--code-bg);
          padding: 2px 4px;
          border-radius: 3px;
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
      }
      pre code {
          background-color: transparent;
          padding: 0;
      }
      pre code.hljs { background: transparent; padding: 0; }
      .hljs-keyword, .hljs-selector-tag { color: var(--hl-keyword); }
      .hljs-string, .hljs-doctag, .hljs-regexp { color: var(--hl-string); }
      .hljs-number { color: var(--hl-number); }
      .hljs-comment { color: var(--hl-comment); font-style: italic; }
      .hljs-title, .hljs-title\.function_ { color: var(--hl-function); }
      .hljs-built_in { color: var(--hl-built-in); }
      .hljs-literal { color: var(--hl-literal); }
      .hljs-meta, .hljs-meta .hljs-keyword { color: var(--hl-meta); }
      .hljs-attr, .hljs-attribute { color: var(--hl-attr); }
      .hljs-type, .hljs-title\.class_ { color: var(--hl-built-in); }
      .hljs-variable, .hljs-template-variable { color: var(--text-color); }
      .hljs-params { color: var(--text-color); }
      .hljs-punctuation { color: var(--blockquote-color); }
      .hljs-symbol { color: var(--hl-literal); }
      .hljs-section { color: var(--hl-function); font-weight: bold; }
      .hljs-addition { color: var(--hl-string); }
      .hljs-deletion { color: var(--hl-meta); }
      blockquote {
          border-left: 4px solid var(--border-color-light);
          padding-left: 16px;
          margin-left: 0;
          color: var(--blockquote-color);
      }
      table {
          border-collapse: collapse;
          width: 100%;
          margin: 16px 0;
          display: block;
          overflow-x: auto;
      }
      th, td {
          border: 1px solid var(--border-color-light);
          padding: 8px 12px;
          text-align: left;
      }
      th {
          background-color: var(--table-header-bg);
          font-weight: bold;
      }
      h1, h2, h3, h4, h5, h6 {
          margin-top: 24px;
          margin-bottom: 16px;
          font-weight: 600;
          line-height: 1.25;
      }
      h1 { border-bottom: 1px solid var(--border-color); padding-bottom: 8px; }
      h2 { border-bottom: 1px solid var(--border-color); padding-bottom: 8px; }
      a { color: var(--link-color); text-decoration: none; }
      a:hover { text-decoration: underline; }
      img { max-width: 100%; height: auto; }


      /* Shared page header */
      .page-header {
          display: flex;
          align-items: center;
          gap: 8px 12px;
          padding: 8px 16px;
          border-bottom: 1px solid var(--border-color);
          background: var(--code-bg);
          flex-shrink: 0;
          min-height: 48px;
          flex-wrap: wrap;
      }

      .page-header .branding-logo {
          height: 28px;
          width: auto;
          opacity: 0.85;
          margin-left: 8px;
      }

      /* View mode container */
      .page-container {
          display: flex;
          flex-direction: column;
          height: 100vh;
          overflow-y: auto;
      }

      .page-container #content {
          flex: 1 0 auto;
          padding-bottom: 40vh;
      }

      /* Editor mode styles */
      .editor-container {
          display: flex;
          flex-direction: column;
          height: 100vh;
          overflow: hidden;
      }

      .editor-header {
          /* extends .page-header */
      }

      .editor-filename {
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
          font-size: 14px;
          color: var(--text-color);
          opacity: 0.8;
          flex-shrink: 1;
          min-width: 0;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
      }

      .editor-filename-input {
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
          font-size: 14px;
          color: var(--text-color);
          background: var(--bg-color);
          border: 1px solid var(--border-color);
          border-radius: 4px;
          padding: 4px 8px;
          min-width: 250px;
          outline: none;
      }

      .editor-filename-input:focus {
          border-color: var(--link-color);
      }

      .file-modified-ts {
          font-size: 12px;
          color: var(--blockquote-color);
          white-space: nowrap;
      }

      .not-found-page {
          text-align: center;
          padding: 80px 20px;
      }
      .not-found-page h2 {
          margin: 0 0 8px;
          font-size: 24px;
      }
      .not-found-page p {
          opacity: 0.6;
          margin: 0 0 24px;
      }
      .not-found-page a {
          color: var(--link-color);
      }

      .landing-page {
          text-align: center;
          padding: 100px 20px;
          opacity: 0.85;
      }
      .landing-page h2 {
          margin: 0 0 12px;
          font-size: 22px;
          font-weight: 500;
      }
      .landing-page p {
          opacity: 0.6;
          margin: 0;
          font-size: 14px;
      }
      .landing-page code {
          background: var(--code-bg, rgba(127,127,127,0.15));
          padding: 1px 6px;
          border-radius: 4px;
          font-size: 12px;
      }

      .editor-spacer {
          flex: 1;
      }

      .editor-btn {
          padding: 6px 14px;
          border-radius: 6px;
          border: 1px solid var(--border-color);
          cursor: pointer;
          font-size: 13px;
          font-family: inherit;
          background: transparent;
          color: var(--text-color);
          transition: background 0.15s ease;
          flex-shrink: 0;
      }

      .editor-btn:hover {
          background: var(--border-color-light);
      }

      .editor-btn-save {
          background: var(--link-color);
          color: #fff;
          border-color: var(--link-color);
      }

      .editor-btn-save:hover {
          opacity: 0.9;
          background: var(--link-color);
      }

      .editor-btn-save.saved {
          background: #a6e3a1;
          border-color: #a6e3a1;
          color: #1e1e2e;
      }

      .editor-btn-icon {
          padding: 4px 6px;
          border: none;
          opacity: 0.4;
      }

      .editor-btn-toggle {
          padding: 4px 8px;
          border: 1px solid transparent;
          opacity: 0.5;
      }

      .editor-btn-toggle.active {
          opacity: 0.9;
          border-color: var(--border-color);
      }

      .editor-panes.preview-hidden .editor-pane-resize-handle,
      .editor-panes.preview-hidden #previewPaneWrapper {
          display: none;
      }

      .editor-panes.preview-hidden .editor-pane:first-child {
          flex: 1;
      }

      .editor-btn-icon:hover {
          opacity: 1;
          background: var(--border-color-light);
      }

      .copy-path-btn {
          padding: 4px 6px;
          border: none;
          background: transparent;
          cursor: pointer;
          color: var(--text-color);
          opacity: 0.4;
          transition: opacity 0.15s ease;
          display: flex;
          align-items: center;
          justify-content: center;
          position: relative;
          margin-right: 4px;
      }

      .copy-path-btn:hover {
          opacity: 1;
          background: var(--border-color-light);
          border-radius: 4px;
      }

      .copy-path-btn.copied::after {
          content: 'Copied!';
          position: absolute;
          bottom: -24px;
          left: 50%;
          transform: translateX(-50%);
          font-size: 11px;
          color: #a6e3a1;
          white-space: nowrap;
          pointer-events: none;
      }

      .editor-btn-destructive {
          color: #e64553;
          border-color: transparent;
          opacity: 0.6;
      }

      .editor-btn-destructive:hover {
          background: rgba(230, 69, 83, 0.1);
          border-color: #e64553;
          opacity: 1;
      }

      .header-separator {
          width: 1px;
          height: 20px;
          background: var(--border-color);
          flex-shrink: 0;
      }

      .unsaved-dot {
          display: none;
          width: 8px;
          height: 8px;
          border-radius: 50%;
          background: var(--link-color);
          flex-shrink: 0;
      }

      .editor-header.unsaved .unsaved-dot {
          display: block;
      }

      .revision-badge {
          display: none;
          font-size: 12px;
          padding: 3px 10px;
          border-radius: 4px;
          background: rgba(230, 160, 30, 0.15);
          color: #e0a020;
          border: 1px solid rgba(230, 160, 30, 0.3);
          flex-shrink: 0;
          white-space: nowrap;
          order: 10;
          flex-basis: 100%;
      }

      .revision-badge.show {
          display: inline-block;
      }

      .revision-controls {
          display: none;
          align-items: center;
          gap: 8px;
          order: 11;
      }

      .revision-controls.show {
          display: inline-flex;
      }

      .revision-overlay {
          display: none;
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          z-index: 50;
          background: var(--bg-color);
          flex-direction: column;
          overflow: hidden;
      }

      .revision-overlay.show {
          display: flex;
      }


      .revision-overlay-content {
          flex: 1;
          overflow-y: auto;
          padding: 24px 32px;
      }

      .revision-diff-toggle {
          display: inline-flex;
          align-items: center;
          gap: 6px;
          cursor: pointer;
          font-size: 12px;
          color: var(--link-color);
          background: none;
          border: none;
          padding: 0;
          font-family: inherit;
      }

      .revision-diff-toggle:hover {
          text-decoration: underline;
      }

      .revision-diff-toggle svg {
          transition: transform 0.15s;
      }

      .revision-diff-toggle.expanded svg {
          transform: rotate(90deg);
      }

      .revision-diff {
          display: none;
          margin-top: 12px;
          border: 1px solid var(--border-color-light);
          border-radius: 6px;
          overflow: hidden;
          font-family: 'SF Mono', 'Fira Code', 'Fira Mono', monospace;
          font-size: 12px;
          line-height: 1.5;
      }

      .revision-diff.show {
          display: block;
      }

      .revision-diff pre {
          margin: 0;
          padding: 12px 16px;
          overflow-x: auto;
          background: var(--bg-color);
      }

      .diff-add {
          background: rgba(40, 167, 69, 0.15);
          color: inherit;
      }

      .diff-del {
          background: rgba(220, 53, 69, 0.15);
          color: inherit;
      }

      .diff-hunk {
          color: var(--link-color);
          opacity: 0.7;
      }

      .diff-context {
          opacity: 0.6;
      }

      .editor-panes {
          display: flex;
          flex: 1;
          overflow: hidden;
      }

      .editor-pane {
          flex: 1;
          overflow: auto;
          min-width: 0;
      }

      .editor-pane:first-child {
          flex: 0 0 var(--editor-split, 50%);
      }

      .editor-panes:not(:has(#previewPaneWrapper)) .editor-pane:first-child {
          flex: 1;
      }

      .editor-pane-resize-handle {
          flex-shrink: 0;
          width: 4px;
          cursor: col-resize;
          background: var(--border-color);
      }

      .editor-pane-resize-handle:hover,
      .editor-pane-resize-handle.active {
          background: var(--link-color);
          opacity: 0.5;
      }

      body.editor-resizing {
          user-select: none;
          cursor: col-resize;
      }

      .editor-pane-edit {
          display: flex;
          overflow: hidden;
      }

      .line-numbers {
          flex-shrink: 0;
          width: 48px;
          padding: 20px 8px 20px 0;
          text-align: right;
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
          font-size: 14px;
          line-height: 1.6;
          color: var(--blockquote-color);
          background: var(--code-bg);
          border-right: 1px solid var(--border-color);
          overflow: hidden;
          user-select: none;
          white-space: pre;
      }

      .editor-pane textarea {
          flex: 1;
          min-width: 0;
          height: 100%;
          resize: none;
          border: none;
          outline: none;
          padding: 20px;
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
          font-size: 14px;
          line-height: 1.6;
          color: var(--text-color);
          background: var(--bg-color);
          tab-size: 2;
      }

      .editor-preview {
          padding: 20px;
          padding-bottom: 48px;
          max-width: none;
      }

      .editor-notify {
          display: none;
          padding: 8px 16px;
          background: var(--link-color);
          color: #fff;
          font-size: 13px;
          text-align: center;
          flex-shrink: 0;
      }

      .editor-notify.show {
          display: block;
      }

      /* transient toast notifications */
      .toast-container {
          position: fixed;
          bottom: 24px;
          right: 24px;
          z-index: 1000;
          display: flex;
          flex-direction: column;
          gap: 8px;
          pointer-events: none;
      }
      .toast {
          background: var(--bg-elevated, #2a2a2a);
          color: var(--text-color, #fff);
          border: 1px solid var(--border-color);
          border-left: 3px solid var(--link-color);
          padding: 10px 14px;
          border-radius: 4px;
          font-size: 13px;
          max-width: 360px;
          box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
          opacity: 0;
          transform: translateX(12px);
          transition: opacity 180ms ease, transform 180ms ease;
      }
      .toast.show {
          opacity: 1;
          transform: translateX(0);
      }

      /* revisions panel */
      .history-panel {
          display: none;
          position: fixed;
          top: 0;
          right: 0;
          width: 320px;
          height: 100%;
          background: var(--bg-color);
          border-left: 1px solid var(--border-color);
          z-index: 200;
          flex-direction: column;
          box-shadow: -4px 0 12px rgba(0, 0, 0, 0.15);
      }

      .history-panel.show {
          display: flex;
      }

      .history-panel-header {
          display: flex;
          align-items: center;
          justify-content: space-between;
          padding: 12px 16px;
          border-bottom: 1px solid var(--border-color);
          font-weight: 600;
          font-size: 14px;
      }

      .history-panel-close {
          background: none;
          border: none;
          color: var(--text-color);
          cursor: pointer;
          font-size: 18px;
          padding: 4px;
      }

      .history-list {
          flex: 1;
          overflow-y: auto;
          padding: 8px;
      }

      .history-item {
          display: flex;
          align-items: flex-start;
          width: 100%;
          padding: 10px 12px;
          background: none;
          border: none;
          border-radius: 6px;
          color: var(--text-color);
          text-align: left;
          cursor: pointer;
          font-family: inherit;
          font-size: 13px;
          margin-bottom: 2px;
      }

      .history-item:hover {
          background: var(--border-color-light);
      }

      .history-item-content {
          flex: 1;
          min-width: 0;
      }

      .history-item-time {
          font-weight: 600;
          font-size: 12px;
          color: var(--link-color);
      }

      .history-item-preview {
          margin-top: 2px;
          opacity: 0.7;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
      }

      .history-item-delete {
          flex-shrink: 0;
          background: none;
          border: none;
          color: var(--text-color);
          opacity: 0;
          cursor: pointer;
          padding: 2px 4px;
          margin-left: 4px;
          border-radius: 4px;
          font-size: 14px;
          line-height: 1;
          transition: opacity 0.15s, color 0.15s;
      }

      .history-item:hover .history-item-delete {
          opacity: 0.5;
      }

      .history-item-delete:hover {
          opacity: 1 !important;
          color: #e55;
      }

      {% if show_navigation and editor_mode %}
      .editor-container {
          margin-left: var(--sidebar-width);
          flex: 1;
          min-width: 0;
          transition: margin-left var(--transition-speed) var(--transition-timing);
      }

      body.sidebar-collapsed .editor-container {
          margin-left: var(--sidebar-collapsed-width);
      }

      .status-bar {
          left: var(--sidebar-width);
          transition: left var(--transition-speed) var(--transition-timing);
      }
      body.sidebar-collapsed .status-bar {
          left: var(--sidebar-collapsed-width);
      }
      {% endif %}

      {% if show_navigation and not editor_mode %}
      .page-container {
          margin-left: var(--sidebar-width);
          flex: 1;
          min-width: 0;
          transition: margin-left var(--transition-speed) var(--transition-timing);
      }

      body.sidebar-collapsed .page-container {
          margin-left: var(--sidebar-collapsed-width);
      }

      .status-bar {
          left: var(--sidebar-width);
          transition: left var(--transition-speed) var(--transition-timing);
      }
      body.sidebar-collapsed .status-bar {
          left: var(--sidebar-collapsed-width);
      }

      .page-container #content {
          margin-left: max(0px, calc((100vw - var(--sidebar-width) - var(--content-max-width)) / 4));
      }

      body.sidebar-collapsed .page-container #content {
          margin-left: max(0px, calc((100vw - var(--sidebar-collapsed-width) - var(--content-max-width)) / 4));
      }

      .page-container #content.content-code,
      body.sidebar-collapsed .page-container #content.content-code {
          margin-left: 0;
      }
      {% endif %}

      @media (max-width: 640px) {
          .page-header .branding-logo {
              display: none;
          }
      }

      /* status bar clearance for editor mode */
      .editor-container {
          padding-bottom: 80px;
      }
      .status-bar {
          position: fixed;
          bottom: 0;
          left: 0;
          right: 0;
          height: 24px;
          display: flex;
          align-items: center;
          padding: 0 12px;
          font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
          font-size: 12px;
          background: var(--code-bg);
          border-top: 1px solid var(--border-color);
          color: var(--text-color);
          opacity: 0.7;
          z-index: 999;
          gap: 12px;
      }
      .status-bar-path {
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          direction: rtl;
          text-align: left;
      }
      .status-bar-path span {
          direction: ltr;
          unicode-bidi: bidi-override;
      }
      .status-bar-mode {
          flex-shrink: 0;
          opacity: 0.6;
      }
      .status-bar-spacer {
          flex: 1;
      }
      .status-bar-version {
          flex-shrink: 0;
          font-size: 11px;
          opacity: 0.35;
          color: var(--blockquote-color);
          padding-left: 8px;
      }
    </style>

    <script src="/highlight.min.js"></script>
    {% if mermaid_enabled %}
    <script src="/mermaid.min.js"></script>
    {% endif %}
    <script>
      let lastModified = Date.now();

      // Theme management
      function initTheme() {
        // Theme is already set by the early script to prevent flash
        // Just update the theme selection UI to match current theme
        const currentTheme =
          document.documentElement.getAttribute("data-theme");
        updateThemeSelection(currentTheme);
      }

      function openThemeModal() {
        const modal = document.getElementById("themeModal");
        modal.classList.add("show");
        updateThemeSelection(
          document.documentElement.getAttribute("data-theme"),
        );
      }

      function closeThemeModal() {
        const modal = document.getElementById("themeModal");
        modal.classList.remove("show");
      }

      function selectTheme(theme) {
        document.documentElement.setAttribute("data-theme", theme);
        localStorage.setItem("theme", theme);
        updateThemeSelection(theme);
        updateMermaidTheme();
        closeThemeModal();
      }

      function updateThemeSelection(selectedTheme) {
        // Update all theme cards to show selection state
        const cards = document.querySelectorAll(".theme-card");
        cards.forEach((card) => {
          if (card.dataset.theme === selectedTheme) {
            card.classList.add("selected");
          } else {
            card.classList.remove("selected");
          }
        });
      }

      // Content width management
      const WIDTH_PRESETS = ['narrow', 'default', 'wide', 'full'];

      function setContentWidth(preset) {
        if (!WIDTH_PRESETS.includes(preset)) preset = 'default';
        document.documentElement.setAttribute('data-width', preset);
        try { localStorage.setItem('content-width', preset); } catch (e) {}
        updateWidthSelection(preset);
      }

      function cycleContentWidth() {
        const current = document.documentElement.getAttribute('data-width') || 'default';
        const idx = WIDTH_PRESETS.indexOf(current);
        const next = WIDTH_PRESETS[(idx + 1) % WIDTH_PRESETS.length];
        setContentWidth(next);
      }

      function updateWidthSelection(preset) {
        document.querySelectorAll('.width-card').forEach(function(card) {
          card.classList.toggle('selected', card.dataset.width === preset);
        });
      }

      // Sidebar toggle management
      function toggleSidebar() {
        document.body.classList.toggle("sidebar-collapsed");
        const isCollapsed =
          document.body.classList.contains("sidebar-collapsed");
        localStorage.setItem(
          "sidebar-collapsed",
          isCollapsed ? "true" : "false",
        );
      }

      function initSidebar() {
        const isCollapsed =
          localStorage.getItem("sidebar-collapsed") === "true";
        if (isCollapsed) {
          document.body.classList.add("sidebar-collapsed");
        }
        // restore saved width
        const savedWidth = localStorage.getItem("sidebar-width");
        if (savedWidth) {
          document.documentElement.style.setProperty(
            "--sidebar-width",
            savedWidth + "px",
          );
        }
      }

      function initSidebarResize() {
        const handle = document.getElementById("sidebarResizeHandle");
        if (!handle) return;

        const minWidth = 180;
        const maxWidthPercent = 0.4;

        handle.addEventListener("mousedown", function (e) {
          e.preventDefault();
          handle.classList.add("active");
          document.body.classList.add("sidebar-resizing");

          function onMove(e) {
            const maxWidth = window.innerWidth * maxWidthPercent;
            const width = Math.min(Math.max(e.clientX, minWidth), maxWidth);
            document.documentElement.style.setProperty(
              "--sidebar-width",
              width + "px",
            );
          }

          function onUp() {
            handle.classList.remove("active");
            document.body.classList.remove("sidebar-resizing");
            const current = getComputedStyle(
              document.documentElement,
            ).getPropertyValue("--sidebar-width");
            localStorage.setItem("sidebar-width", parseInt(current));
            document.removeEventListener("mousemove", onMove);
            document.removeEventListener("mouseup", onUp);
          }

          document.addEventListener("mousemove", onMove);
          document.addEventListener("mouseup", onUp);
        });
      }

      // persist tree open/closed state across page loads
      function initTreeState() {
        const tree = document.querySelector(".file-tree");
        if (!tree) return;

        var saved = {};
        try {
          saved = JSON.parse(localStorage.getItem("tree-state") || "{}");
        } catch (e) {}

        tree.querySelectorAll("details").forEach(function (d) {
          var key = d.querySelector("summary").textContent.trim();
          if (saved[key]) d.setAttribute("open", "");
          d.addEventListener("toggle", function () {
            saveTreeState();
          });
        });
      }

      function saveTreeState() {
        var tree = document.querySelector(".file-tree");
        if (!tree) return;
        var state = {};
        tree.querySelectorAll("details").forEach(function (d) {
          var key = d.querySelector("summary").textContent.trim();
          if (d.open) state[key] = true;
        });
        localStorage.setItem("tree-state", JSON.stringify(state));
      }

      function restoreTreeState() {
        var tree = document.querySelector(".file-tree");
        if (!tree) return;
        var saved = {};
        try {
          saved = JSON.parse(localStorage.getItem("tree-state") || "{}");
        } catch (e) {}
        tree.querySelectorAll("details").forEach(function (d) {
          var key = d.querySelector("summary").textContent.trim();
          if (saved[key]) d.setAttribute("open", "");
          else d.removeAttribute("open");
        });
      }

      // sidebar search - filters tree like nvim /
      function initSidebarSearch() {
        const input = document.getElementById("sidebarSearch");
        if (!input) return;

        input.addEventListener("input", function () {
          const query = this.value.toLowerCase().trim();
          filterTree(query);
        });

        // esc clears search and blurs
        document.addEventListener("keydown", function (e) {
          if (e.key === "Escape" && document.activeElement === input) {
            input.value = "";
            filterTree("");
            input.blur();
          }
        });
      }

      function filterTree(query) {
        const tree = document.querySelector(".file-tree");
        if (!tree) return;

        if (!query) {
          tree
            .querySelectorAll("li")
            .forEach((li) => li.classList.remove("search-hidden"));
          restoreTreeState();
          return;
        }

        // walk bottom-up: mark file nodes, then propagate visibility to parent dirs
        const allItems = tree.querySelectorAll("li");
        allItems.forEach((li) => {
          const link = li.querySelector(":scope > a");
          if (link) {
            const nameSpan = link.querySelector(".file-name");
            const text = (nameSpan || link).textContent.toLowerCase();
            li.classList.toggle("search-hidden", !text.includes(query));
          }
        });

        // for directory nodes: visible if dir name matches (show all children)
        // or if any child is visible. process innermost first.
        const dirs = Array.from(tree.querySelectorAll("li:has(> details)"));
        dirs.reverse().forEach((li) => {
          const summary = li.querySelector(":scope > details > summary");
          const dirName = summary ? summary.textContent.toLowerCase() : "";
          const dirMatches = dirName.includes(query);
          const childLis = li.querySelectorAll(":scope > details > ul > li");

          if (dirMatches) {
            // dir name matches: show dir and all its children
            li.classList.remove("search-hidden");
            childLis.forEach((c) => c.classList.remove("search-hidden"));
            // unhide nested dirs' children too
            li.querySelectorAll("li").forEach((nested) =>
              nested.classList.remove("search-hidden"),
            );
          }

          const anyVisible = Array.from(childLis).some(
            (c) => !c.classList.contains("search-hidden"),
          );
          li.classList.toggle("search-hidden", !anyVisible && !dirMatches);

          const details = li.querySelector(":scope > details");
          if (details) {
            if (anyVisible || dirMatches) {
              details.setAttribute("open", "");
            } else {
              details.removeAttribute("open");
            }
          }
        });
      }

      // sidebar sort -- reorders tree items at each directory level
      function initSidebarSort() {
        var select = document.getElementById("sidebarSort");
        if (!select) return;

        var sortKey = baseDir ? 'mdlive-sort:' + baseDir : 'sidebar-sort';
        var saved = localStorage.getItem(sortKey) || "name-asc";
        select.value = saved;
        applySortMode(saved);

        select.addEventListener("change", function () {
          var mode = this.value;
          localStorage.setItem(sortKey, mode);
          applySortMode(mode);
        });
      }

      function applySortMode(mode) {
        var tree = document.querySelector(".file-tree");
        if (!tree) return;

        var isNameSort = mode.startsWith("name");
        tree.classList.toggle("sort-by-name", isNameSort);

        // always populate timestamps so users can spot recent files even when
        // sorting by name. created sort uses created; everything else shows modified.
        var field = mode.startsWith("created") ? "created" : "modified";
        tree.querySelectorAll(".file-ts").forEach(function (span) {
          var el = span.closest("a");
          if (!el) return;
          var epoch = parseInt(el.getAttribute("data-" + field), 10);
          span.textContent = epoch ? formatRelativeTime(epoch) : "";
        });

        sortTreeUl(tree, mode);
      }

      function sortTreeUl(ul, mode) {
        var lis = Array.from(ul.children).filter(function (el) {
          return el.tagName === "LI";
        });
        if (lis.length === 0) return;

        lis.forEach(function (li) {
          var subUl = li.querySelector(":scope > details > ul");
          if (subUl) sortTreeUl(subUl, mode);
        });

        var parts = mode.split("-");
        var field = parts[0];
        var dir = parts[1];

        lis.sort(function (a, b) {
          var av = getSortValue(a, field);
          var bv = getSortValue(b, field);
          if (field === "name") {
            var cmp = av.localeCompare(bv, undefined, { sensitivity: "base" });
            return dir === "desc" ? -cmp : cmp;
          }
          return dir === "desc" ? bv - av : av - bv;
        });

        lis.forEach(function (li) {
          ul.appendChild(li);
        });
      }

      function getSortValue(li, field) {
        if (field === "name") {
          var details = li.querySelector(":scope > details");
          if (details) {
            var summary = details.querySelector("summary");
            return summary ? summary.textContent.trim().toLowerCase() : "";
          }
          var link = li.querySelector(":scope > a");
          var nameSpan = link ? link.querySelector(".file-name") : null;
          return nameSpan ? nameSpan.textContent.trim().toLowerCase() : (link ? link.textContent.trim().toLowerCase() : "");
        }
        var el = li.querySelector(":scope > a, :scope > details");
        if (!el) return 0;
        return parseInt(el.getAttribute("data-" + field), 10) || 0;
      }

      function initSidebarNav() {
        var el = document.getElementById('fileTreeParent');
        if (!el || !baseDir) return;
        var parts = baseDir.split('/').filter(Boolean);
        if (parts.length <= 1) {
            el.style.display = 'none';
            return;
        }
        el.addEventListener('click', function() {
            var parent = baseDir.substring(0, baseDir.lastIndexOf('/')) || '/';
            fetch('/api/workspace/switch', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ path: parent })
            })
            .then(function(r) { return r.json(); })
            .then(function(data) {
                if (data.success) {
                    fetch('/api/session/persist', { method: 'POST' }).catch(function() {});
                    window.location.href = '/';
                }
            });
        });
      }

      var formatRelativeTime = window.formatRelativeTime;

      function initFileModifiedTs() {
        var el = document.querySelector('.file-modified-ts');
        if (!el) return;
        var epoch = parseInt(el.getAttribute('data-epoch'), 10);
        if (!epoch) return;
        var d = new Date(epoch * 1000);
        el.textContent = 'Modified ' + formatRelativeTime(epoch);
        el.title = 'Last modified: ' + d.toLocaleString();
      }

      // copy button on fenced code blocks
      function initCopyButtons() {
        const copyIcon =
          '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
        const checkIcon =
          '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';

        document.querySelectorAll("pre > code").forEach(function (codeEl) {
          const pre = codeEl.parentElement;
          const btn = document.createElement("button");
          btn.className = "copy-btn";
          btn.innerHTML = copyIcon;
          btn.setAttribute("aria-label", "Copy code");

          btn.addEventListener("click", function () {
            navigator.clipboard.writeText(codeEl.textContent).then(function () {
              btn.innerHTML = checkIcon;
              btn.classList.add("copied");
              setTimeout(function () {
                btn.innerHTML = copyIcon;
                btn.classList.remove("copied");
              }, 2000);
            });
          });

          pre.appendChild(btn);
        });
      }

      // Mermaid theme management
      function getMermaidTheme() {
        const currentTheme =
          document.documentElement.getAttribute("data-theme");
        switch (currentTheme) {
          case "dark":
          case "catppuccin-macchiato":
          case "catppuccin-mocha":
            return "dark";
          case "light":
          case "catppuccin-latte":
          default:
            return "default";
        }
      }

      function initMermaid() {
        if (typeof mermaid !== "undefined") {
          mermaid.initialize({
            startOnLoad: false,
            theme: getMermaidTheme(),
            themeVariables: {
              fontFamily:
                '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif',
            },
            flowchart: {
              useMaxWidth: true,
              htmlLabels: true,
            },
            sequence: {
              useMaxWidth: true,
            },
            gantt: {
              useMaxWidth: true,
            },
          });

          // Find and transform mermaid code blocks
          transformMermaidCodeBlocks();

          // Render all mermaid diagrams
          mermaid.run();
        }
      }

      function transformMermaidCodeBlocks() {
        // Find all code blocks with language-mermaid class
        const mermaidCodeBlocks = document.querySelectorAll(
          "code.language-mermaid",
        );

        mermaidCodeBlocks.forEach((codeElement, index) => {
          const preElement = codeElement.parentElement;
          if (preElement && preElement.tagName === "PRE") {
            // Get the mermaid code content
            const mermaidCode = codeElement.textContent;

            // Create new mermaid div
            const mermaidDiv = document.createElement("div");
            mermaidDiv.className = "mermaid";
            mermaidDiv.id = `mermaid-${index}`;
            mermaidDiv.textContent = mermaidCode;
            mermaidDiv.setAttribute("data-original", mermaidCode);

            // Replace the pre/code block with the mermaid div
            preElement.parentElement.replaceChild(mermaidDiv, preElement);
          }
        });
      }

      function updateMermaidTheme() {
        if (typeof mermaid !== "undefined") {
          mermaid.initialize({
            startOnLoad: false,
            theme: getMermaidTheme(),
            themeVariables: {
              fontFamily:
                '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif',
            },
          });

          // Re-render all mermaid diagrams with new theme
          const mermaidElements = document.querySelectorAll(".mermaid");
          mermaidElements.forEach((element) => {
            element.removeAttribute("data-processed");
            const originalContent = element.getAttribute("data-original");
            if (originalContent) {
              element.textContent = originalContent;
            }
          });

          mermaid.run();
        }
      }

      // Context menu and file operations
      function initContextMenu() {
        var menu = document.getElementById("contextMenu");
        if (!menu) return;

        // directory mode: file tree links
        document.querySelectorAll(".file-tree a").forEach(function (link) {
          link.addEventListener("contextmenu", function (e) {
            e.preventDefault();
            var path = link.getAttribute("href").replace(/^\//, "");
            showContextMenu(e.clientX, e.clientY, "file", path);
          });
        });

        // directory mode: folder summaries
        document
          .querySelectorAll(".file-tree summary")
          .forEach(function (summary) {
            summary.addEventListener("contextmenu", function (e) {
              e.preventDefault();
              e.stopPropagation();
              var details = summary.closest("details");
              var dirPath = details
                ? details.getAttribute("data-dir-path") || ""
                : "";
              showContextMenu(e.clientX, e.clientY, "directory", dirPath);
            });
          });

        // directory mode: right-click empty sidebar space for root-level new file
        var sidebar = document.querySelector(".sidebar");
        if (sidebar) {
          sidebar.addEventListener("contextmenu", function (e) {
            if (e.target.closest("a, summary, input, .sidebar-resize-handle"))
              return;
            e.preventDefault();
            showContextMenu(e.clientX, e.clientY, "directory", "");
          });
        }

        // single-file mode: right-click content area
        var content = document.getElementById("content");
        if (content && !document.querySelector(".file-tree")) {
          content.addEventListener("contextmenu", function (e) {
            if (e.target.closest("a, button, input, textarea, select")) return;
            e.preventDefault();
            showContextMenu(e.clientX, e.clientY, "file", currentFile);
          });
        }

        document.addEventListener("click", function (e) {
          if (!menu.contains(e.target)) hideContextMenu();
        });
        document.addEventListener("scroll", hideContextMenu, true);
      }

      function createMenuItem(label, destructive) {
        var btn = document.createElement("button");
        btn.className =
          "context-menu-item" + (destructive ? " destructive" : "");
        btn.textContent = label;
        return btn;
      }

      function showContextMenu(x, y, type, path) {
        var menu = document.getElementById("contextMenu");
        menu.innerHTML = "";
        var isDirectoryMode = !!document.querySelector(".file-tree");

        if (type === "file") {
          var editBtn = createMenuItem("Edit", false);
          editBtn.onclick = function () {
            hideContextMenu();
            window.location.href = "/edit/" + path;
          };
          var isMarkdown = path.toLowerCase().endsWith('.md');
          var copyLabel = isMarkdown ? "Copy raw markdown" : "Copy raw content";
          var copyBtn = createMenuItem(copyLabel, false);
          copyBtn.onclick = function () {
            copyRawMarkdown(path);
          };
          var copyPathBtn = createMenuItem("Copy path", false);
          copyPathBtn.onclick = function () {
            copyPath(path);
          };
          menu.appendChild(editBtn);
          menu.appendChild(copyBtn);
          menu.appendChild(copyPathBtn);

          if (isDirectoryMode) {
            var moveBtn = createMenuItem("Move / rename", false);
            moveBtn.onclick = function () {
              moveFile(path);
            };
            var dirPath = path.includes("/")
              ? path.substring(0, path.lastIndexOf("/"))
              : "";
            var newBtn = createMenuItem("New file here", false);
            newBtn.onclick = function () {
              addNewFile(dirPath);
            };
            var newDirBtn = createMenuItem("New directory here", false);
            newDirBtn.onclick = function () {
              addNewDirectory(dirPath);
            };
            var deleteBtn = createMenuItem("Delete file", true);
            deleteBtn.onclick = function () {
              deleteFile(path);
            };
            menu.appendChild(moveBtn);
            menu.appendChild(newBtn);
            menu.appendChild(newDirBtn);
            menu.appendChild(deleteBtn);
          }
        } else {
          var newBtn = createMenuItem("New file", false);
          newBtn.onclick = function () {
            addNewFile(path);
          };
          var newDirBtn = createMenuItem("New directory", false);
          newDirBtn.onclick = function () {
            addNewDirectory(path);
          };
          var copyDirPathBtn = createMenuItem("Copy path", false);
          copyDirPathBtn.onclick = function () {
            copyPath(path);
          };
          menu.appendChild(newBtn);
          menu.appendChild(newDirBtn);
          menu.appendChild(copyDirPathBtn);
          // rename / delete don't apply to the workspace root (path === "")
          if (path) {
            var moveDirBtn = createMenuItem("Move / rename", false);
            moveDirBtn.onclick = function () {
              moveFile(path);
            };
            var deleteDirBtn = createMenuItem("Delete directory", true);
            deleteDirBtn.onclick = function () {
              deleteDirectory(path);
            };
            menu.appendChild(moveDirBtn);
            menu.appendChild(deleteDirBtn);
          }
        }

        menu.classList.add("show");
        var rect = menu.getBoundingClientRect();
        if (x + rect.width > window.innerWidth)
          x = window.innerWidth - rect.width - 8;
        if (y + rect.height > window.innerHeight)
          y = window.innerHeight - rect.height - 8;
        menu.style.left = x + "px";
        menu.style.top = y + "px";
      }

      function hideContextMenu() {
        var menu = document.getElementById("contextMenu");
        if (menu) menu.classList.remove("show");
      }

      function copyFilePath(btn) {
        var rel = document.querySelector('.editor-filename');
        if (!rel) return;
        var full = baseDir ? baseDir + '/' + rel.textContent : rel.textContent;
        navigator.clipboard.writeText(full).then(function() {
          btn.classList.add('copied');
          setTimeout(function() { btn.classList.remove('copied'); }, 1200);
        });
      }

      function copyPath(path) {
        hideContextMenu();
        var full = baseDir ? (path ? baseDir + "/" + path : baseDir) : path;
        navigator.clipboard.writeText(full).catch(function (err) {
          alert("Failed to copy: " + err.message);
        });
      }

      function copyRawMarkdown(path) {
        hideContextMenu();
        fetch("/api/raw_content?path=" + encodeURIComponent(path))
          .then(function (r) {
            if (!r.ok) throw new Error("Failed to fetch");
            return r.text();
          })
          .then(function (text) {
            return navigator.clipboard.writeText(text);
          })
          .catch(function (err) {
            alert("Failed to copy: " + err.message);
          });
      }

      function deleteFile(path) {
        hideContextMenu();
        showConfirm(
          "Delete " + path + "?",
          function () {
            fetch("/api/delete_file", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ path: path }),
            })
              .then(function (r) {
                return r.json();
              })
              .then(function (data) {
                if (!data.success) {
                  alert("Delete failed: " + (data.error || "unknown error"));
                  return;
                }
                TabManager.clearDraft(path);
                if (path === currentFile) {
                  var tabs = TabManager.tabs();
                  var tabIdx = -1;
                  for (var i = 0; i < tabs.length; i++) {
                      if (tabs[i].path === path) { tabIdx = i; break; }
                  }
                  if (tabIdx !== -1) {
                      tabs.splice(tabIdx, 1);
                      TabManager.save();
                      if (tabs.length > 0) {
                          var nextIdx = Math.min(tabIdx, tabs.length - 1);
                          window.location.href = '/' + tabs[nextIdx].path;
                      } else {
                          window.location.href = "/";
                      }
                  } else {
                      window.location.href = "/";
                  }
                }
              })
              .catch(function (err) {
                alert("Delete failed: " + err.message);
              });
          },
          { destructive: true },
        );
      }

      function moveFile(path) {
        hideContextMenu();
        openFileDialog(
          "Move / rename",
          path,
          "Enter new path relative to root",
          function (newPath) {
            fetch("/api/move_file", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ path: path, target: newPath }),
            })
              .then(function (r) {
                return r.json();
              })
              .then(function (data) {
                if (!data.success) {
                  showFileDialogError(data.error || "unknown error");
                  return;
                }
                closeFileDialog();
                TabManager.updatePath(path, data.path);
                if (path === currentFile) {
                  window.location.href = "/" + data.path;
                }
              })
              .catch(function (err) {
                showFileDialogError(err.message);
              });
          },
        );
      }

      function deleteDirectory(path) {
        hideContextMenu();
        showConfirm(
          'Delete directory "' + path + '" and everything inside it?',
          function () {
            fetch("/api/delete_directory", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ path: path }),
            })
              .then(function (r) {
                return r.json();
              })
              .then(function (data) {
                if (!data.success) {
                  alert("Delete failed: " + (data.error || "unknown error"));
                  return;
                }
                // close tabs for anything under the deleted directory
                var prefix = path + "/";
                var tabs = TabManager.tabs().slice();
                for (var i = 0; i < tabs.length; i++) {
                  var p = tabs[i].path;
                  if (p === path || p.indexOf(prefix) === 0) {
                    TabManager.clearDraft(p);
                  }
                }
                // websocket Reload will refresh the tree
              })
              .catch(function (err) {
                alert("Delete failed: " + err.message);
              });
          },
          { destructive: true },
        );
      }

      function addNewFile(dirPath) {
        hideContextMenu();
        window.location.href = "/new?dir=" + encodeURIComponent(dirPath || "");
      }

      function addNewDirectory(parentDir) {
        hideContextMenu();
        openFileDialog('New directory', '', 'Enter directory name', function(dirName) {
          var fullPath = parentDir ? parentDir + '/' + dirName : dirName;
          fetch('/api/create_directory', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ path: fullPath })
          })
          .then(function(r) { return r.json(); })
          .then(function(data) {
            if (!data.success) {
              showFileDialogError(data.error || 'unknown error');
              return;
            }
            closeFileDialog();
            // websocket Reload will refresh the sidebar tree with the new dir
          })
          .catch(function(err) {
            showFileDialogError(err.message);
          });
        });
      }

      var _fileDialogCallback = null;

      function openFileDialog(title, value, hint, onConfirm) {
        var overlay = document.getElementById("fileDialog");
        var input = document.getElementById("fileDialogInput");
        var errorEl = document.getElementById("fileDialogError");
        document.getElementById("fileDialogTitle").textContent = title;
        document.getElementById("fileDialogHint").textContent = hint;
        errorEl.style.display = "none";
        input.value = value;
        _fileDialogCallback = onConfirm;
        overlay.classList.add("show");
        var lastSlash = value.lastIndexOf("/");
        var extDot = value.lastIndexOf(".");
        input.focus();
        input.setSelectionRange(
          lastSlash + 1,
          extDot > lastSlash ? extDot : value.length,
        );
      }

      function closeFileDialog() {
        var overlay = document.getElementById("fileDialog");
        if (overlay) overlay.classList.remove("show");
        _fileDialogCallback = null;
      }

      function showFileDialogError(msg) {
        var errorEl = document.getElementById("fileDialogError");
        if (errorEl) {
          errorEl.textContent = msg;
          errorEl.style.display = "block";
        }
      }

      var _confirmDialogCallback = null;

      function showConfirm(message, onConfirm, opts) {
        opts = opts || {};
        var overlay = document.getElementById("confirmDialog");
        var okBtn = document.getElementById("confirmDialogOk");
        document.getElementById("confirmDialogMessage").textContent = message;
        _confirmDialogCallback = onConfirm;
        okBtn.className = opts.destructive
          ? "file-dialog-btn-destructive"
          : "file-dialog-btn-confirm";
        overlay.classList.add("show");
      }

      function closeConfirmDialog() {
        var overlay = document.getElementById("confirmDialog");
        if (overlay) overlay.classList.remove("show");
        _confirmDialogCallback = null;
      }

      function showAlert(title, detail) {
        document.getElementById("alertDialogTitle").textContent = title;
        document.getElementById("alertDialogMessage").textContent = detail || "";
        document.getElementById("alertDialog").classList.add("show");
      }

      function closeAlertDialog() {
        document.getElementById("alertDialog").classList.remove("show");
      }

      // WebSocket reconnect with exponential backoff
      var _wsReconnectDelay = 3000;

      // Auto-refresh functionality using WebSocket
      function setupLiveReload() {
        const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
        const wsUrl = `${protocol}//${window.location.host}/ws`;
        const socket = new WebSocket(wsUrl);

        socket.onopen = function (event) {
          console.log("WebSocket connected");
          _wsReconnectDelay = 3000;
        };

        socket.onmessage = function (event) {
          try {
            const message = JSON.parse(event.data);
            if (message.type === "Reload") {
              console.log("Reloading page via WebSocket");
              window.location.reload();
            } else if (message.type === "FileMoved") {
              if (typeof TabManager !== 'undefined') {
                TabManager.updatePath(message.from, message.to);
              }
              var movedPrefix = message.from + '/';
              if (currentFile === message.from) {
                window.location.href = "/" + message.to;
              } else if (currentFile && currentFile.indexOf(movedPrefix) === 0) {
                window.location.href = "/" + message.to + '/' + currentFile.substring(movedPrefix.length);
              }
            } else if (message.type === "WorkspaceChanged") {
              console.log("Workspace changed to: " + message.base_dir);
              // skip navigation if we're already showing this workspace
              if (message.base_dir && message.base_dir === baseDir && !message.file) return;
              window.location.href = message.file ? '/' + message.file : '/';
            }
          } catch (error) {
            console.error("Error parsing WebSocket message:", error);
          }
        };

        socket.onerror = function (event) {
          console.error("WebSocket error:", event);
        };

        socket.onclose = function (event) {
          console.log("WebSocket closed, attempting to reconnect...");
          setTimeout(setupLiveReload, _wsReconnectDelay);
          _wsReconnectDelay = Math.min(_wsReconnectDelay * 2, 30000);
        };
      }

      // Per-file scroll memory: tab switches do a full page nav, so without this
      // every open file snaps back to the top. Restore is gated to tab mode and
      // only fires for files that have a stored position (i.e. already-open tabs).
      var ScrollMemory = (function() {
        var restoring = false;

        // baseDir/currentFile/etc. are defined in a later <script> block, so this
        // IIFE must not touch them at eval time -- only inside functions called
        // from DOMContentLoaded, by which point those globals exist.
        function enabled() { return showNavigation && !!currentFile; }
        function mode() { return isEditorMode ? 'edit' : 'view'; }
        function key() { return 'mdlive-scroll:' + baseDir + ':' + mode() + ':' + currentFile; }
        function scrollEl() {
          return isEditorMode
            ? document.getElementById('editorTextarea')
            : document.querySelector('.page-container');
        }

        function save() {
          if (!enabled()) return;
          var el = scrollEl();
          if (!el) return;
          try { sessionStorage.setItem(key(), String(el.scrollTop)); } catch(_) {}
        }

        function restore() {
          if (!enabled()) return;
          var el = scrollEl();
          if (!el) return;
          var raw;
          try { raw = sessionStorage.getItem(key()); } catch(_) { return; }
          if (raw === null) return;
          var target = parseInt(raw, 10);
          if (isNaN(target) || target <= 0) return;
          // async content (mermaid, highlight.js) grows height after load, so
          // reapply across frames until it sticks or we hit the cap.
          restoring = true;
          var frames = 0;
          (function apply() {
            if (!restoring) return;
            el.scrollTop = target;
            frames++;
            if (Math.abs(el.scrollTop - target) > 1 && frames < 120) {
              requestAnimationFrame(apply);
            } else {
              restoring = false;
            }
          })();
        }

        function init() {
          if (!enabled()) return;
          var el = scrollEl();
          if (el) {
            var pending = null;
            el.addEventListener('scroll', function() {
              if (pending) return;
              pending = requestAnimationFrame(function() { pending = null; save(); });
            }, { passive: true });
          }
          // a genuine user scroll cancels an in-flight restore
          ['wheel', 'touchstart', 'keydown', 'mousedown'].forEach(function(ev) {
            window.addEventListener(ev, function() { restoring = false; }, { passive: true, capture: true });
          });
          window.addEventListener('pagehide', save);
          restore();
        }

        return { init: init, save: save, restore: restore };
      })();

      // Initialize theme and live reload on page load
      document.addEventListener("DOMContentLoaded", function () {
        initTheme();
        const currentWidth = document.documentElement.getAttribute('data-width') || 'default';
        updateWidthSelection(currentWidth);
        initSidebar();
        initSidebarResize();
        initTreeState();
        initSidebarSearch();
        initSidebarSort();
        initSidebarNav();
        if (typeof hljs !== "undefined") {
          hljs.highlightAll();
        }
        initCopyButtons();
        initMermaid();
        initContextMenu();
        initFileModifiedTs();
        ScrollMemory.init();

        // sidebar link interception for tab management (view mode only)
        if (showNavigation && !isEditorMode) {
            document.querySelectorAll('.file-tree a').forEach(function(link) {
                link.addEventListener('click', function(e) {
                    var href = link.getAttribute('href');
                    if (!href || href === '#') return;
                    var path = href.replace(/^\//, '');
                    if (!path) return;
                    e.preventDefault();
                    if (!TabManager.addTab(path, 'view')) {
                        showAlert('Tab limit reached', 'Close a tab to open more files.');
                        return;
                    }
                    TabManager.switchTo(path);
                });
            });
        }

        if (typeof window._editorSetupLiveReload === "function") {
          window._editorSetupLiveReload();
        } else {
          setupLiveReload();
        }

        // Modal close functionality
        const modal = document.getElementById("themeModal");

        // Close modal when clicking outside
        modal.addEventListener("click", function (e) {
          if (e.target === modal) {
            closeThemeModal();
          }
        });

        // File dialog events
        var fileDialogOverlay = document.getElementById("fileDialog");
        var fileDialogConfirmBtn = document.getElementById("fileDialogConfirm");
        if (fileDialogConfirmBtn) {
          fileDialogConfirmBtn.addEventListener("click", function () {
            if (_fileDialogCallback) {
              _fileDialogCallback(
                document.getElementById("fileDialogInput").value.trim(),
              );
            }
          });
        }
        if (fileDialogOverlay) {
          fileDialogOverlay.addEventListener("click", function (e) {
            if (e.target === fileDialogOverlay) closeFileDialog();
          });
          document
            .getElementById("fileDialogInput")
            .addEventListener("keydown", function (e) {
              if (e.key === "Enter" && _fileDialogCallback) {
                _fileDialogCallback(this.value.trim());
              }
            });
        }

        // Confirm dialog events
        var confirmOverlay = document.getElementById("confirmDialog");
        var confirmOkBtn = document.getElementById("confirmDialogOk");
        if (confirmOkBtn) {
          confirmOkBtn.addEventListener("click", function () {
            var cb = _confirmDialogCallback;
            closeConfirmDialog();
            if (cb) cb();
          });
        }
        document
          .getElementById("confirmDialogCancel")
          .addEventListener("click", closeConfirmDialog);
        if (confirmOverlay) {
          confirmOverlay.addEventListener("click", function (e) {
            if (e.target === confirmOverlay) closeConfirmDialog();
          });
        }

        // Alert dialog events
        var alertOverlay = document.getElementById("alertDialog");
        if (alertOverlay) {
          alertOverlay.addEventListener("click", function (e) {
            if (e.target === alertOverlay) closeAlertDialog();
          });
        }

        // Close modals with ESC key
        document.addEventListener("keydown", function (e) {
          if (e.key === "Escape") {
            var shortcutsModal = document.getElementById('shortcutsModal');
            if (shortcutsModal && shortcutsModal.classList.contains('show')) {
              closeShortcutsModal();
              return;
            }
            if (alertOverlay && alertOverlay.classList.contains("show")) {
              closeAlertDialog();
            } else if (confirmOverlay && confirmOverlay.classList.contains("show")) {
              closeConfirmDialog();
            } else if (
              fileDialogOverlay &&
              fileDialogOverlay.classList.contains("show")
            ) {
              closeFileDialog();
            } else if (modal.classList.contains("show")) {
              closeThemeModal();
            }
          }
        });
      });
    </script>
  </head>
  <body>
    {% if show_navigation %}
    <button
      class="sidebar-toggle"
      onclick="toggleSidebar()"
      aria-label="Toggle sidebar"
    >
      <svg
        width="24"
        height="24"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="1.5"
        stroke-linecap="round"
        stroke-linejoin="round"
      >
        <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
        <line x1="9" y1="3" x2="9" y2="21"></line>
      </svg>
    </button>
    <nav class="sidebar">
      <div class="sidebar-resize-handle" id="sidebarResizeHandle"></div>
      <div class="sidebar-header">
        <img src="/static/md.png" alt="mdlive" class="sidebar-logo" />
      </div>
      <div class="sidebar-search">
        <input
          type="text"
          id="sidebarSearch"
          placeholder="search (s)"
          autocomplete="off"
          spellcheck="false"
        />
      </div>
      <div class="sidebar-sort">
        <select id="sidebarSort">
          <option value="name-asc">Name A-Z</option>
          <option value="name-desc">Name Z-A</option>
          <option value="modified-desc">Modified newest</option>
          <option value="modified-asc">Modified oldest</option>
          <option value="created-desc">Created newest</option>
          <option value="created-asc">Created oldest</option>
        </select>
      </div>
      <div class="sidebar-content">
        <div class="file-tree-parent" id="fileTreeParent" title="Open parent directory">..</div>
        <ul class="file-tree sort-by-name">
          {% for item in tree recursive %}
          <li>
            {% if item.is_dir %}
            <details data-dir-path="{{ item.dir_path }}" data-modified="{{ item.modified }}" data-created="{{ item.created }}">
              <summary>{{ item.name }}</summary>
              <ul>
                {{ loop(item.children) }}
              </ul>
            </details>
            {% else %}
            <a href="/{{ item.path|safe }}" data-modified="{{ item.modified }}" data-created="{{ item.created }}"{% if item.path == current_file %} class="active"{% endif %}>
              <span class="file-icon file-icon-{{ item.file_type|default('unknown') }}" aria-hidden="true"></span><span class="file-name">{{ item.name }}</span><span class="file-ts"></span>
            </a>
            {% endif %}
          </li>
          {% endfor %}
        </ul>
      </div>
    </nav>
    <div class="tab-bar" id="tabBar"></div>
    {% endif %}
    <script>
      var currentFile = {{ current_file|default('')|tojson }};
      var isEditorMode = {{ editor_mode|default(false)|tojson }};
      var showNavigation = {{ show_navigation|default(false)|tojson }};
      var baseDir = {{ base_dir|default('')|tojson }};
      var isDefaultFile = {{ is_default_file|default(false)|tojson }};
      var unavailablePath = {{ unavailable_path|default('')|tojson }};
      // server-injected tab state (authoritative across launches/ports)
      var __serverTabs = {{ saved_tabs|default(none)|tojson }};
    </script>
    <script>
    // 404 recovery: if the URL matches a saved tab, close it and jump to the
    // next one -- like Sublime / VS Code when a file vanishes. Toast is shown
    // on the destination page via sessionStorage handoff.
    (function() {
        if (!unavailablePath) return;
        try {
            var tabsKey = 'mdlive-tabs:' + baseDir;
            var activeKey = 'mdlive-active-tab:' + baseDir;
            var stored = localStorage.getItem(tabsKey);
            var tabs = stored ? JSON.parse(stored) : [];
            if (!Array.isArray(tabs)) return;

            var idx = -1;
            for (var i = 0; i < tabs.length; i++) {
                if (tabs[i].path === unavailablePath) { idx = i; break; }
            }
            if (idx === -1) return;  // direct URL, not a tracked tab -- leave the page as-is

            tabs.splice(idx, 1);
            localStorage.setItem(tabsKey, JSON.stringify(tabs));
            try { sessionStorage.removeItem('tab-draft:' + baseDir + ':' + unavailablePath); } catch(e) {}
            if (localStorage.getItem(activeKey) === unavailablePath) {
                localStorage.removeItem(activeKey);
            }

            try {
                sessionStorage.setItem('mdlive-pending-toast',
                    'Closed tab — "' + unavailablePath + '" was moved, renamed, or deleted.');
            } catch(e) {}

            var target = tabs.length > 0 ? tabs[Math.min(idx, tabs.length - 1)] : null;
            var url = target
                ? (target.mode === 'edit' ? '/edit/' + target.path : '/' + target.path)
                : '/';
            window.location.replace(url);
        } catch(e) { /* fall back to the rendered not-found body */ }
    })();
    </script>
    <script>
    // Resume on landing: if this workspace has saved tabs (server-side first,
    // localStorage fallback), jump to the last active tab. Stay on landing
    // otherwise. Server-side storage survives port shifts across launches.
    (function() {
        if (!showNavigation) return;
        if (currentFile) return;  // already viewing a file -- no resume needed
        try {
            var savedTabs = [];
            var activePath = null;

            if (__serverTabs && Array.isArray(__serverTabs.tabs) && __serverTabs.tabs.length > 0) {
                savedTabs = __serverTabs.tabs;
                activePath = __serverTabs.active || null;
            } else {
                var stored = localStorage.getItem('mdlive-tabs:' + baseDir);
                savedTabs = stored ? JSON.parse(stored) : [];
                if (!Array.isArray(savedTabs)) savedTabs = [];
                activePath = localStorage.getItem('mdlive-active-tab:' + baseDir);
            }
            if (savedTabs.length === 0) return;

            var target = null;
            if (activePath) {
                for (var i = 0; i < savedTabs.length; i++) {
                    if (savedTabs[i].path === activePath) {
                        target = savedTabs[i];
                        break;
                    }
                }
            }
            if (!target) target = savedTabs[savedTabs.length - 1];
            if (!target || !target.path) return;

            var url = target.mode === 'edit' ? '/edit/' + target.path : '/' + target.path;
            window.location.replace(url);
        } catch(e) { /* fall through and render the landing page */ }
    })();
    </script>
    <script>
    var TabManager = (function() {
        var MAX_TABS = 20;
        var STORAGE_KEY = 'mdlive-tabs:' + baseDir;
        var ACTIVE_KEY = 'mdlive-active-tab:' + baseDir;
        var DRAFT_PREFIX = 'tab-draft:' + baseDir + ':';
        var tabs = [];
        var currentPath = currentFile;
        var tabBar = null;
        var draggedPath = null;

        function load() {
            // prefer server-injected tabs (survives port shifts); fall back to localStorage
            try {
                if (__serverTabs && Array.isArray(__serverTabs.tabs) && __serverTabs.tabs.length > 0) {
                    tabs = __serverTabs.tabs.slice();
                    if (__serverTabs.active) {
                        try { localStorage.setItem(ACTIVE_KEY, __serverTabs.active); } catch(_) {}
                    }
                    try { localStorage.setItem(STORAGE_KEY, JSON.stringify(tabs)); } catch(_) {}
                    return;
                }
                var stored = localStorage.getItem(STORAGE_KEY);
                if (stored) tabs = JSON.parse(stored);
                if (!Array.isArray(tabs)) tabs = [];
            } catch(e) { tabs = []; }
        }

        var __saveTimer = null;
        function persistToServer() {
            try {
                var active = null;
                try { active = localStorage.getItem(ACTIVE_KEY); } catch(_) {}
                fetch('/api/workspace/tabs', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ tabs: tabs, active: active }),
                    keepalive: true
                }).catch(function() {});
            } catch(_) {}
        }

        function save() {
            try { localStorage.setItem(STORAGE_KEY, JSON.stringify(tabs)); } catch(_) {}
            // debounce server writes; quick edits coalesce into a single POST
            if (__saveTimer) clearTimeout(__saveTimer);
            __saveTimer = setTimeout(persistToServer, 200);
        }

        function findTab(path) {
            for (var i = 0; i < tabs.length; i++) {
                if (tabs[i].path === path) return i;
            }
            return -1;
        }

        function getDisplayName(path) {
            var parts = path.split('/');
            var name = parts[parts.length - 1];
            // check for ambiguous filenames
            var count = 0;
            for (var i = 0; i < tabs.length; i++) {
                var tParts = tabs[i].path.split('/');
                if (tParts[tParts.length - 1] === name) count++;
            }
            if (count > 1 && parts.length > 1) {
                return parts[parts.length - 2] + '/' + name;
            }
            return name;
        }

        function isDirty(path) {
            return sessionStorage.getItem(DRAFT_PREFIX + path) !== null;
        }

        function cacheDraft(path, content) {
            sessionStorage.setItem(DRAFT_PREFIX + path, content);
        }

        function clearDraft(path) {
            sessionStorage.removeItem(DRAFT_PREFIX + path);
        }

        function getDraft(path) {
            return sessionStorage.getItem(DRAFT_PREFIX + path);
        }

        function makeTabEl(tab) {
            var div = document.createElement('div');
            div.className = 'tab';
            if (tab.path === currentPath) div.className += ' active';
            if (isDirty(tab.path)) div.className += ' dirty';
            div.setAttribute('data-path', tab.path);
            var fileParts = tab.path.split('/');
            div.title = fileParts[fileParts.length - 1];

            var dot = document.createElement('span');
            dot.className = 'tab-dirty';
            div.appendChild(dot);

            var nameSpan = document.createElement('span');
            nameSpan.className = 'tab-name';
            nameSpan.textContent = getDisplayName(tab.path);
            div.appendChild(nameSpan);

            var closeBtn = document.createElement('button');
            closeBtn.className = 'tab-close';
            closeBtn.title = 'Close tab';
            closeBtn.innerHTML = '&times;';
            closeBtn.addEventListener('click', function(e) {
                e.stopPropagation();
                removeTab(tab.path);
            });
            closeBtn.addEventListener('mousedown', function(e) {
                e.stopPropagation();
            });
            div.appendChild(closeBtn);

            div.addEventListener('click', function() {
                switchTo(tab.path);
            });

            // drag-and-drop reordering
            div.draggable = true;
            div.addEventListener('dragstart', function(e) {
                draggedPath = tab.path;
                div.classList.add('dragging');
                if (e.dataTransfer) {
                    e.dataTransfer.effectAllowed = 'move';
                    try { e.dataTransfer.setData('text/plain', tab.path); } catch(_) {}
                }
            });
            div.addEventListener('dragend', function() {
                draggedPath = null;
                clearDropIndicators();
            });
            div.addEventListener('dragover', function(e) {
                if (!draggedPath || draggedPath === tab.path) return;
                e.preventDefault();
                if (e.dataTransfer) e.dataTransfer.dropEffect = 'move';
                var rect = div.getBoundingClientRect();
                var before = e.clientX < rect.left + rect.width / 2;
                div.classList.toggle('drop-before', before);
                div.classList.toggle('drop-after', !before);
            });
            div.addEventListener('dragleave', function() {
                div.classList.remove('drop-before', 'drop-after');
            });
            div.addEventListener('drop', function(e) {
                e.preventDefault();
                var src = draggedPath;
                clearDropIndicators();
                if (!src || src === tab.path) return;
                var rect = div.getBoundingClientRect();
                var insertAfter = e.clientX >= rect.left + rect.width / 2;
                reorderTab(src, tab.path, insertAfter);
            });

            return div;
        }

        // move a tab to the last position in the array (so it becomes visible)
        function promoteTab(path) {
            var idx = findTab(path);
            if (idx === -1) return;
            var item = tabs.splice(idx, 1)[0];
            tabs.push(item);
            save();
        }

        function render() {
            if (!tabBar) return;
            tabBar.innerHTML = '';

            // inner scroll area for visible tabs
            var scrollEl = document.createElement('div');
            scrollEl.className = 'tab-scroll';

            for (var i = 0; i < tabs.length; i++) {
                scrollEl.appendChild(makeTabEl(tabs[i]));
            }
            tabBar.appendChild(scrollEl);

            // chevron overflow button + dropdown
            var chevBtn = document.createElement('button');
            chevBtn.className = 'tab-overflow-btn';
            chevBtn.title = 'More tabs';
            chevBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">'
                + '<path d="M4.5 6l3.5 4 3.5-4z"/></svg>';

            var badge = document.createElement('span');
            badge.className = 'tab-overflow-badge';
            chevBtn.appendChild(badge);

            var menu = document.createElement('div');
            menu.className = 'tab-overflow-menu';
            chevBtn.appendChild(menu);

            chevBtn.addEventListener('click', function(e) {
                e.stopPropagation();
                var showing = menu.classList.toggle('show');
                if (showing) buildOverflowMenu(scrollEl, menu, badge);
            });

            tabBar.appendChild(chevBtn);

            // detect overflow after layout
            requestAnimationFrame(function() {
                updateOverflowState(scrollEl, chevBtn, badge);
            });
        }

        function updateOverflowState(scrollEl, chevBtn, badge) {
            var overflowing = scrollEl.scrollWidth > scrollEl.clientWidth;
            chevBtn.classList.toggle('visible', overflowing);
            if (overflowing) {
                var hidden = countHiddenTabs(scrollEl);
                badge.textContent = hidden;
                badge.style.display = hidden > 0 ? '' : 'none';
            } else {
                badge.style.display = 'none';
            }
        }

        function countHiddenTabs(scrollEl) {
            var count = 0;
            var right = scrollEl.getBoundingClientRect().right;
            var children = scrollEl.children;
            for (var i = 0; i < children.length; i++) {
                var r = children[i].getBoundingClientRect();
                if (r.right > right + 1) count++;
            }
            return count;
        }

        function buildOverflowMenu(scrollEl, menu, badge) {
            menu.innerHTML = '';
            var right = scrollEl.getBoundingClientRect().right;
            var children = scrollEl.children;
            var hiddenPaths = {};
            for (var i = 0; i < children.length; i++) {
                var r = children[i].getBoundingClientRect();
                if (r.right > right + 1) {
                    hiddenPaths[children[i].getAttribute('data-path')] = true;
                }
            }

            // show ALL tabs — hidden ones first, then visible as secondary section
            var hiddenTabs = [];
            var visibleTabs = [];
            for (var j = 0; j < tabs.length; j++) {
                if (hiddenPaths[tabs[j].path]) {
                    hiddenTabs.push(tabs[j]);
                } else {
                    visibleTabs.push(tabs[j]);
                }
            }

            var allItems = hiddenTabs.concat(visibleTabs);
            if (hiddenTabs.length > 0 && visibleTabs.length > 0) {
                // add a separator index to insert after hidden tabs
                var sepAfter = hiddenTabs.length;
            }

            for (var k = 0; k < allItems.length; k++) {
                (function(tab, idx) {
                    if (sepAfter && idx === sepAfter) {
                        var sep = document.createElement('div');
                        sep.style.cssText = 'height:1px;background:var(--border-color);margin:4px 0;';
                        menu.appendChild(sep);
                    }
                    var row = document.createElement('div');
                    row.className = 'tab-overflow-item';
                    if (tab.path === currentPath) row.className += ' active';
                    if (isDirty(tab.path)) row.className += ' dirty';

                    var dot = document.createElement('span');
                    dot.className = 'tab-dirty';
                    row.appendChild(dot);

                    var name = document.createElement('span');
                    name.className = 'tab-name';
                    name.textContent = getDisplayName(tab.path);
                    row.appendChild(name);

                    var closeBtn = document.createElement('button');
                    closeBtn.className = 'tab-close';
                    closeBtn.title = 'Close tab';
                    closeBtn.innerHTML = '&times;';
                    closeBtn.addEventListener('click', function(e) {
                        e.stopPropagation();
                        menu.classList.remove('show');
                        removeTab(tab.path);
                    });
                    row.appendChild(closeBtn);

                    row.addEventListener('click', function() {
                        menu.classList.remove('show');
                        promoteTab(tab.path);
                        switchTo(tab.path);
                    });

                    menu.appendChild(row);
                })(allItems[k], k);
            }
        }

        function clearDropIndicators() {
            if (!tabBar) return;
            var all = tabBar.querySelectorAll('.tab-scroll .tab');
            for (var i = 0; i < all.length; i++) {
                all[i].classList.remove('drop-before', 'drop-after');
            }
        }

        function reorderTab(fromPath, toPath, insertAfter) {
            var fromIdx = findTab(fromPath);
            var toIdx = findTab(toPath);
            if (fromIdx === -1 || toIdx === -1 || fromIdx === toIdx) return;
            var item = tabs.splice(fromIdx, 1)[0];
            // after splice, recompute target index
            var newIdx = toIdx;
            if (fromIdx < toIdx) newIdx = toIdx - 1;
            if (insertAfter) newIdx += 1;
            if (newIdx < 0) newIdx = 0;
            if (newIdx > tabs.length) newIdx = tabs.length;
            tabs.splice(newIdx, 0, item);
            save();
            render();
        }

        function closeActiveTab() {
            if (tabs.length === 0) return;
            var activePath = currentPath;
            if (findTab(activePath) === -1) return;
            removeTab(activePath);
        }

        function addTab(path, mode) {
            if (!path) return false;
            var idx = findTab(path);
            if (idx !== -1) {
                tabs[idx].mode = mode || tabs[idx].mode;
                save();
                render();
                return true;
            }
            if (tabs.length >= MAX_TABS) return false;
            tabs.push({ path: path, mode: mode || 'view' });
            save();
            render();
            return true;
        }

        function removeTab(path) {
            var idx = findTab(path);
            if (idx === -1) return;

            if (path === currentPath && isDirty(path)) {
                showConfirm('This tab has unsaved changes. Close anyway?', function() {
                    clearDraft(path);
                    doRemoveTab(path, idx);
                });
                return;
            }

            clearDraft(path);
            doRemoveTab(path, idx);
        }

        function doRemoveTab(path, idx) {
            tabs.splice(idx, 1);
            save();

            if (path === currentPath) {
                if (tabs.length === 0) {
                    try { localStorage.removeItem(ACTIVE_KEY); } catch(e) {}
                    window.location.href = '/';
                    return;
                }
                var nextIdx = Math.min(idx, tabs.length - 1);
                switchTo(tabs[nextIdx].path);
                return;
            }
            render();
        }

        function switchTo(path) {
            if (path === currentPath) return;

            // cache draft if current tab is in editor and dirty
            if (typeof window._tabGetEditorContent === 'function') {
                var content = window._tabGetEditorContent();
                if (content !== null) {
                    cacheDraft(currentPath, content);
                }
            }

            var tab = tabs[findTab(path)];
            if (!tab) return;

            var url = tab.mode === 'edit' ? '/edit/' + path : '/' + path;
            window.location.href = url;
        }

        function updateMode(path, mode) {
            var idx = findTab(path);
            if (idx !== -1) {
                tabs[idx].mode = mode;
                save();
            }
        }

        function updatePath(oldPath, newPath) {
            // handles both file renames (exact match) and directory renames
            // (every tab under the renamed dir is rewritten)
            var prefix = oldPath + '/';
            var newPrefix = newPath + '/';
            var changed = false;
            for (var i = 0; i < tabs.length; i++) {
                var p = tabs[i].path;
                var np = null;
                if (p === oldPath) {
                    np = newPath;
                } else if (p.indexOf(prefix) === 0) {
                    np = newPrefix + p.substring(prefix.length);
                }
                if (np !== null) {
                    var draft = getDraft(p);
                    if (draft !== null) {
                        clearDraft(p);
                        cacheDraft(np, draft);
                    }
                    tabs[i].path = np;
                    changed = true;
                }
            }
            if (changed) {
                save();
                render();
            }
        }

        function init() {
            if (!showNavigation) return;
            tabBar = document.getElementById('tabBar');
            if (!tabBar) return;

            load();

            // clean tabs for paths that may have been removed server-side
            // (we don't proactively remove -- server 404 handles it)

            // ensure current file is in tabs
            if (currentPath) {
                var mode = isEditorMode ? 'edit' : 'view';
                var idx = findTab(currentPath);
                if (idx === -1) {
                    if (tabs.length >= MAX_TABS) {
                        // make room by removing the last non-active tab
                        for (var i = tabs.length - 1; i >= 0; i--) {
                            if (tabs[i].path !== currentPath) {
                                tabs.splice(i, 1);
                                break;
                            }
                        }
                    }
                    tabs.push({ path: currentPath, mode: mode });
                } else {
                    tabs[idx].mode = mode;
                }
                // remember which tab was active before save() so server gets the new active
                try { localStorage.setItem(ACTIVE_KEY, currentPath); } catch(e) {}
                save();
            }

            document.body.classList.add('has-tabs');
            render();

            // close overflow menu on outside click
            document.addEventListener('click', function() {
                var m = tabBar.querySelector('.tab-overflow-menu.show');
                if (m) m.classList.remove('show');
            });

            // recheck overflow on resize
            window.addEventListener('resize', function() { render(); });

            // flush pending save synchronously on unload so the server captures
            // the latest tab order even mid-debounce
            window.addEventListener('pagehide', function() {
                if (__saveTimer) {
                    clearTimeout(__saveTimer);
                    __saveTimer = null;
                }
                try {
                    var active = null;
                    try { active = localStorage.getItem(ACTIVE_KEY); } catch(_) {}
                    var payload = JSON.stringify({ tabs: tabs, active: active });
                    if (navigator.sendBeacon) {
                        var blob = new Blob([payload], { type: 'application/json' });
                        navigator.sendBeacon('/api/workspace/tabs', blob);
                    }
                } catch(_) {}
            });
        }

        return {
            init: init,
            addTab: addTab,
            removeTab: removeTab,
            switchTo: switchTo,
            updateMode: updateMode,
            updatePath: updatePath,
            cacheDraft: cacheDraft,
            clearDraft: clearDraft,
            getDraft: getDraft,
            isDirty: isDirty,
            render: render,
            save: save,
            closeActiveTab: closeActiveTab,
            tabs: function() { return tabs; },
            MAX_TABS: MAX_TABS
        };
    })();

    // exposed for the Tauri wrapper's Cmd+W menu handler
    window.mdliveCloseActiveTab = function() {
        if (typeof TabManager === 'undefined') { try { window.close(); } catch(_){} return; }
        TabManager.closeActiveTab();
    };

    document.addEventListener('DOMContentLoaded', function() {
        TabManager.init();
        showPendingToast();
    });

    function showToast(message) {
        var container = document.getElementById('toastContainer');
        if (!container) return;
        var item = document.createElement('div');
        item.className = 'toast';
        item.textContent = message;
        container.appendChild(item);
        // force layout so the transition runs
        void item.offsetWidth;
        item.classList.add('show');
        setTimeout(function() {
            item.classList.remove('show');
            setTimeout(function() {
                if (item.parentNode) item.parentNode.removeChild(item);
            }, 220);
        }, 4000);
    }

    function showPendingToast() {
        try {
            var msg = sessionStorage.getItem('mdlive-pending-toast');
            if (!msg) return;
            sessionStorage.removeItem('mdlive-pending-toast');
            showToast(msg);
        } catch(e) {}
    }
    </script>
    <div id="toastContainer" class="toast-container"></div>
    <div id="contextMenu" class="context-menu"></div>
    <div id="fileDialog" class="file-dialog-overlay">
      <div class="file-dialog">
        <h3 id="fileDialogTitle"></h3>
        <input
          type="text"
          id="fileDialogInput"
          autocomplete="off"
          spellcheck="false"
        />
        <div class="file-dialog-hint" id="fileDialogHint"></div>
        <div class="file-dialog-error" id="fileDialogError"></div>
        <div class="file-dialog-buttons">
          <button class="file-dialog-btn-cancel" onclick="closeFileDialog()">
            Cancel
          </button>
          <button class="file-dialog-btn-confirm" id="fileDialogConfirm">
            Confirm
          </button>
        </div>
      </div>
    </div>

    <div id="confirmDialog" class="file-dialog-overlay">
      <div class="file-dialog">
        <p class="confirm-dialog-message" id="confirmDialogMessage"></p>
        <div class="file-dialog-buttons">
          <button class="file-dialog-btn-cancel" id="confirmDialogCancel">
            Cancel
          </button>
          <button class="file-dialog-btn-confirm" id="confirmDialogOk">
            OK
          </button>
        </div>
      </div>
    </div>

    <div id="alertDialog" class="file-dialog-overlay">
      <div class="file-dialog">
        <h3 id="alertDialogTitle"></h3>
        <p class="confirm-dialog-message alert-dialog-detail" id="alertDialogMessage"></p>
        <div class="file-dialog-buttons">
          <button class="file-dialog-btn-confirm" onclick="closeAlertDialog()">
            OK
          </button>
        </div>
      </div>
    </div>

    <div class="footer-toggles">
      {% if daemon_mode|default(false) %}
      <button
        class="workspace-toggle"
        onclick="openWorkspaceModal()"
        title="Open workspace (o)"
      >
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"></path>
        </svg>
      </button>
      {% endif %}
      <button
        class="about-toggle"
        onclick="openAboutModal()"
        title="About (?)"
      >?</button>
      <button
        class="shortcuts-toggle"
        onclick="openShortcutsModal()"
        title="Keyboard shortcuts (/)"
      >
        <svg
          width="16"
          height="16"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          stroke-width="2"
          stroke-linecap="round"
          stroke-linejoin="round"
        >
          <rect x="2" y="4" width="20" height="16" rx="2" ry="2"></rect>
          <path
            d="M6 8h.001M10 8h.001M14 8h.001M18 8h.001M8 12h.001M12 12h.001M16 12h.001M8 16h8"
          ></path>
        </svg>
      </button>
      <button class="theme-toggle" onclick="openThemeModal()">🎨</button>
    </div>

    {% if editor_mode %}
    <div class="editor-container">
      <div class="editor-notify" id="editorNotify">
        File changed externally -- reload to see changes
      </div>
      <div class="page-header editor-header">
        <span class="unsaved-dot" id="unsavedDot"></span>
        {% if new_file_mode %}
        <input
          type="text"
          class="editor-filename-input"
          id="editorFilename"
          value="{{ current_file }}"
          spellcheck="false"
          autocomplete="off"
        />
        {% else %}
        <span class="editor-filename">{{ current_file }}</span>
        <button
          class="copy-path-btn"
          onclick="copyFilePath(this)"
          title="Copy file path"
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
        </button>
        <button
          class="editor-btn editor-btn-icon"
          onclick="editorRename()"
          title="Rename / move"
        >
          <svg
            width="14"
            height="14"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
          >
            <path
              d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
            ></path>
            <path
              d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
            ></path>
          </svg>
        </button>
        {% endif %}
        <span class="revision-badge" id="revisionBadge"></span>
        <span class="revision-controls" id="revisionControls">
          <span class="header-separator"></span>
          <button
            class="revision-diff-toggle"
            id="revisionDiffToggle"
            onclick="toggleRevisionDiff()"
          >
            <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor">
              <path d="M8 5v14l11-7z" />
            </svg>
            Show changes
          </button>
          <button class="editor-btn" onclick="revertToRevision()">
            Revert to this version
          </button>
          <button class="editor-btn" onclick="dismissRevisionOverlay()">
            Back to editing
          </button>
        </span>
        <div class="editor-spacer"></div>
        {% if file_modified %}
        <span class="file-modified-ts" data-epoch="{{ file_modified }}"></span>
        {% endif %}
        {% if file_type == "markdown" %}
        <button
          class="editor-btn editor-btn-toggle active"
          id="previewToggle"
          onclick="togglePreviewPane()"
          title="Toggle preview"
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <rect x="2" y="3" width="20" height="18" rx="2" ry="2"></rect>
            <line x1="12" y1="3" x2="12" y2="21"></line>
          </svg>
        </button>
        {% endif %}
        <button class="editor-btn" onclick="editorCancel()">Close</button>
        <button
          class="editor-btn editor-btn-save"
          id="editorSaveBtn"
          onclick="editorSave()"
        >
          Save
        </button>
        {% if not new_file_mode %}
        <button
          class="editor-btn editor-btn-destructive"
          onclick="editorDelete()"
        >
          Delete
        </button>
        {% endif %} {% if has_history %}
        <span class="header-separator"></span>
        <button
          class="editor-btn"
          id="editorHistoryBtn"
          onclick="toggleHistory()"
        >
          Revisions
        </button>
        {% endif %}
        <img src="/static/mdlive.png" alt="mdlive" class="branding-logo" />
      </div>
      <div class="editor-panes" style="position: relative">
        <div class="editor-pane editor-pane-edit">
          <div class="line-numbers" id="lineNumbers"></div>
          <textarea id="editorTextarea" spellcheck="false">
{{ raw_content }}</textarea
          >
          <script>
          (function() {
              var draft = sessionStorage.getItem('tab-draft:' + {{ current_file|tojson }});
              if (draft !== null) {
                  document.getElementById('editorTextarea').value = draft;
              }
          })();
          </script>
        </div>
        {% if file_type == "markdown" %}
        <div class="editor-pane-resize-handle" id="editorResizeHandle"></div>
        <div class="editor-pane" id="previewPaneWrapper">
          <div id="editorPreview" class="editor-preview markdown-body"></div>
        </div>
        {% endif %}
        <div class="revision-overlay" id="revisionOverlay">
          <div class="revision-diff" id="revisionDiff"></div>
          <div
            class="revision-overlay-content markdown-body"
            id="revisionOverlayContent"
          ></div>
        </div>
      </div>
    </div>

    {% if has_history %}
    <div class="history-panel" id="historyPanel">
      <div class="history-panel-header">
        <span>Revisions</span>
        <button class="history-panel-close" onclick="toggleHistory()">x</button>
      </div>
      <div class="history-list" id="historyList"></div>
    </div>
    {% endif %}

    <script src="/marked.min.js"></script>
    <script>
      (function() {
          var textarea = document.getElementById('editorTextarea');
          var lineNumbers = document.getElementById('lineNumbers');
          var preview = document.getElementById('editorPreview'); // null for non-markdown
          var saveBtn = document.getElementById('editorSaveBtn');
          var isNewFile = {{ new_file_mode|default(false)|lower }};
          var filePath = {{ current_file|tojson }};
          var fileType = {{ file_type|default("markdown")|tojson }};
          var debounceTimer = null;
          var hasUnsavedChanges = false;
          var editorHeader = document.querySelector('.editor-header');
          var originalTitle = document.title;

          // detect restored draft from tab switch
          var restoredDraft = sessionStorage.getItem('tab-draft:' + filePath);
          if (restoredDraft !== null) {
              hasUnsavedChanges = true;
          }

          // expose editor content for tab draft caching
          window._tabGetEditorContent = function() {
              if (hasUnsavedChanges) return textarea.value;
              return null;
          };

          function updateUnsavedIndicator() {
              if (hasUnsavedChanges) {
                  editorHeader.classList.add('unsaved');
                  document.title = '\u25CF ' + originalTitle;
              } else {
                  editorHeader.classList.remove('unsaved');
                  document.title = originalTitle;
              }
          }

          // revision overlay state
          var _activeRevisionContent = null;
          var _activeRevisionTimestamp = null;
          var _revisionRequestCounter = 0;

          window.addEventListener('beforeunload', function(e) {
              // cache draft so it survives accidental close + reopen
              if (hasUnsavedChanges) {
                  TabManager.cacheDraft(filePath, textarea.value);
                  e.preventDefault();
              }
          });

          document.querySelectorAll('.file-tree a').forEach(function(link) {
              link.addEventListener('click', function(e) {
                  e.preventDefault();
                  var href = link.getAttribute('href');
                  var path = href.replace(/^\//, '');
                  if (!path) return;

                  var doNavigate = function() {
                      if (!TabManager.addTab(path, 'view')) {
                          showAlert('Tab limit reached', 'Close a tab to open more files.');
                          return;
                      }
                      TabManager.switchTo(path);
                  };

                  if (hasUnsavedChanges) {
                      showConfirm('You have unsaved changes. Leave this page?', function() {
                          TabManager.cacheDraft(filePath, textarea.value);
                          hasUnsavedChanges = false;
                          doNavigate();
                      });
                  } else {
                      doNavigate();
                  }
              });
          });

          // configure marked
          if (typeof marked !== 'undefined') {
              marked.setOptions({
                  gfm: true,
                  breaks: false,
                  headerIds: true
              });
          }

          function updateLineNumbers() {
              var count = textarea.value.split('\n').length;
              var nums = '';
              for (var i = 1; i <= count; i++) nums += i + '\n';
              lineNumbers.textContent = nums;
          }

          function updatePreview() {
              if (!preview) return;
              if (typeof marked !== 'undefined') {
                  preview.innerHTML = marked.parse(textarea.value);
                  if (typeof hljs !== 'undefined') {
                      preview.querySelectorAll('pre code').forEach(function(block) {
                          hljs.highlightElement(block);
                      });
                  }
              }
          }

          // initial render
          updateLineNumbers();
          updatePreview();
          if (hasUnsavedChanges) updateUnsavedIndicator();

          // live preview with debounce
          textarea.addEventListener('input', function() {
              if (!hasUnsavedChanges) {
                  hasUnsavedChanges = true;
                  updateUnsavedIndicator();
              }
              updateLineNumbers();
              clearTimeout(debounceTimer);
              debounceTimer = setTimeout(updatePreview, 300);
          });

          // keyboard shortcuts
          textarea.addEventListener('keydown', function(e) {
              var isMod = e.ctrlKey || e.metaKey;

              // ctrl/cmd+s = save
              if (isMod && e.key === 's') {
                  e.preventDefault();
                  editorSave();
                  return;
              }

              // tab = insert 2 spaces
              if (e.key === 'Tab' && !e.shiftKey) {
                  e.preventDefault();
                  var start = this.selectionStart;
                  var end = this.selectionEnd;
                  this.value = this.value.substring(0, start) + '  ' + this.value.substring(end);
                  this.selectionStart = this.selectionEnd = start + 2;
                  hasUnsavedChanges = true;
                  updateUnsavedIndicator();
                  clearTimeout(debounceTimer);
                  debounceTimer = setTimeout(updatePreview, 300);
                  return;
              }

              // ctrl/cmd+b = bold
              if (isMod && e.key === 'b') {
                  e.preventDefault();
                  wrapSelection('**');
                  return;
              }

              // ctrl/cmd+i = italic
              if (isMod && e.key === 'i') {
                  e.preventDefault();
                  wrapSelection('*');
                  return;
              }
          });

          // esc = cancel (only when not in filename input, and no dialog open)
          document.addEventListener('keydown', function(e) {
              if (e.key !== 'Escape') return;
              if (document.activeElement === document.getElementById('editorFilename')) return;

              // let modal handlers close their own dialogs first
              var shortcuts = document.getElementById('shortcutsModal');
              if (shortcuts && shortcuts.classList.contains('show')) return;
              var ad = document.getElementById('alertDialog');
              if (ad && ad.classList.contains('show')) return;
              var cd = document.getElementById('confirmDialog');
              if (cd && cd.classList.contains('show')) return;
              var fd = document.getElementById('fileDialog');
              if (fd && fd.classList.contains('show')) return;
              var tm = document.getElementById('themeModal');
              if (tm && tm.classList.contains('show')) return;

              // close revision overlay if open
              var revOverlay = document.getElementById('revisionOverlay');
              if (revOverlay && revOverlay.classList.contains('show')) {
                  dismissRevisionOverlay();
                  return;
              }

              // close history panel if open
              var historyPanel = document.getElementById('historyPanel');
              if (historyPanel && historyPanel.classList.contains('show')) {
                  historyPanel.classList.remove('show');
                  return;
              }

              editorCancel();
          });

          // ctrl/cmd+s anywhere on page
          document.addEventListener('keydown', function(e) {
              if ((e.ctrlKey || e.metaKey) && e.key === 's') {
                  e.preventDefault();
                  editorSave();
              }
          });

          function wrapSelection(marker) {
              var start = textarea.selectionStart;
              var end = textarea.selectionEnd;
              var text = textarea.value;
              var selected = text.substring(start, end);
              var replacement = marker + (selected || 'text') + marker;
              textarea.value = text.substring(0, start) + replacement + text.substring(end);
              if (selected) {
                  textarea.selectionStart = start + marker.length;
                  textarea.selectionEnd = end + marker.length;
              } else {
                  textarea.selectionStart = start + marker.length;
                  textarea.selectionEnd = start + marker.length + 4;
              }
              textarea.focus();
              hasUnsavedChanges = true;
              updateUnsavedIndicator();
              clearTimeout(debounceTimer);
              debounceTimer = setTimeout(updatePreview, 300);
          }

          // save
          window.editorSave = function() {
              var content = textarea.value;
              var path = isNewFile
                  ? document.getElementById('editorFilename').value.trim()
                  : filePath;

              if (!path) return;

              // json: validate but don't format before saving
              var savingJson = path.toLowerCase().endsWith('.json') || fileType === 'json';
              if (savingJson && content.trim()) {
                  try {
                      JSON.parse(content);
                  } catch(e) {
                      showAlert('Invalid JSON', e.message);
                      return;
                  }
              }

              var endpoint = isNewFile ? '/api/create_file' : '/api/save_file';
              var body = isNewFile
                  ? { path: path, content: content }
                  : { path: path, content: content };

              saveBtn.disabled = true;
              saveBtn.textContent = 'Saving...';
              _suppressReloadUntil = Date.now() + 3000;

              fetch(endpoint, {
                  method: 'POST',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify(body)
              })
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  if (!data.success) {
                      alert('Save failed: ' + (data.error || 'unknown error'));
                      saveBtn.textContent = 'Save';
                      saveBtn.disabled = false;
                      return;
                  }
                  hasUnsavedChanges = false;
                  updateUnsavedIndicator();
                  TabManager.clearDraft(filePath);
                  TabManager.render();
                  var badge = document.getElementById('revisionBadge');
                  if (badge) { badge.classList.remove('show'); badge.textContent = ''; }
                  saveBtn.textContent = 'Saved';
                  saveBtn.classList.add('saved');
                  setTimeout(function() {
                      saveBtn.textContent = 'Save';
                      saveBtn.classList.remove('saved');
                      saveBtn.disabled = false;
                  }, 1500);

                  // refresh history panel if open
                  var hp = document.getElementById('historyPanel');
                  if (hp && hp.classList.contains('show')) {
                      loadHistory();
                  }

                  // update sidebar timestamp for saved file
                  var nowEpoch = Math.floor(Date.now() / 1000);
                  var sidebarLink = document.querySelector('.file-tree a[href="/' + path + '"]');
                  if (sidebarLink) {
                      sidebarLink.setAttribute('data-modified', nowEpoch);
                      var sortMode = localStorage.getItem(baseDir ? 'mdlive-sort:' + baseDir : 'sidebar-sort') || 'name-asc';
                      applySortMode(sortMode);
                  }

                  // update header timestamp
                  var fmts = document.querySelector('.file-modified-ts');
                  if (fmts) {
                      fmts.setAttribute('data-epoch', nowEpoch);
                      fmts.textContent = 'Modified ' + formatRelativeTime(nowEpoch);
                      fmts.title = 'Last modified: ' + new Date(nowEpoch * 1000).toLocaleString();
                  }

                  // if new file, redirect to edit existing
                  if (isNewFile) {
                      window.location.href = '/edit/' + path;
                  }
              })
              .catch(function(err) {
                  alert('Save failed: ' + err.message);
                  saveBtn.textContent = 'Save';
                  saveBtn.disabled = false;
              });
          };

          // cancel
          window.editorCancel = function() {
              if (hasUnsavedChanges) {
                  showConfirm('Discard unsaved changes?', function() {
                      hasUnsavedChanges = false;
                      TabManager.clearDraft(filePath);
                      editorCancel();
                  });
                  return;
              }
              TabManager.updateMode(filePath, 'view');
              if (isNewFile || !filePath) {
                  window.location.href = '/';
              } else {
                  window.location.href = '/' + filePath;
              }
          };

          // rename from editor
          window.editorRename = function() {
              var proceed = function() {
                  openFileDialog('Move / rename', filePath, 'Enter new path relative to root', function(newPath) {
                      fetch('/api/move_file', {
                          method: 'POST',
                          headers: { 'Content-Type': 'application/json' },
                          body: JSON.stringify({ path: filePath, target: newPath })
                      })
                      .then(function(r) { return r.json(); })
                      .then(function(data) {
                          if (!data.success) {
                              showFileDialogError(data.error || 'unknown error');
                              return;
                          }
                          closeFileDialog();
                          hasUnsavedChanges = false;
                          TabManager.updatePath(filePath, data.path);
                          window.location.href = '/edit/' + data.path;
                      })
                      .catch(function(err) {
                          showFileDialogError(err.message);
                      });
                  });
              };

              if (hasUnsavedChanges) {
                  showConfirm('You have unsaved changes that will be lost. Continue?', proceed);
              } else {
                  proceed();
              }
          };

          // delete from editor
          window.editorDelete = function() {
              var msg = hasUnsavedChanges
                  ? 'You have unsaved changes. Delete ' + filePath + '?'
                  : 'Delete ' + filePath + '?';
              showConfirm(msg, function() {
                  fetch('/api/delete_file', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({ path: filePath })
                  })
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (!data.success) {
                          alert('Delete failed: ' + (data.error || 'unknown error'));
                          return;
                      }
                      hasUnsavedChanges = false;
                      TabManager.clearDraft(filePath);
                      // remove tab and let TabManager handle navigation
                      var tabs = TabManager.tabs();
                      var tabIdx = -1;
                      for (var i = 0; i < tabs.length; i++) {
                          if (tabs[i].path === filePath) { tabIdx = i; break; }
                      }
                      if (tabIdx !== -1) {
                          tabs.splice(tabIdx, 1);
                          TabManager.save();
                          if (tabs.length > 0) {
                              var nextIdx = Math.min(tabIdx, tabs.length - 1);
                              var nextUrl = tabs[nextIdx].mode === 'edit'
                                  ? '/edit/' + tabs[nextIdx].path
                                  : '/' + tabs[nextIdx].path;
                              window.location.href = nextUrl;
                          } else {
                              window.location.href = '/';
                          }
                      } else {
                          window.location.href = '/';
                      }
                  })
                  .catch(function(err) {
                      alert('Delete failed: ' + err.message);
                  });
              }, { destructive: true });
          };

          // websocket: suppress reload in editor mode
          var _suppressReloadUntil = 0;
          window._editorSetupLiveReload = function() {
              var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
              var wsUrl = protocol + '//' + window.location.host + '/ws';
              var socket = new WebSocket(wsUrl);
              var notify = document.getElementById('editorNotify');

              socket.onmessage = function(event) {
                  try {
                      var message = JSON.parse(event.data);
                      if (message.type === 'Reload') {
                          if (Date.now() < _suppressReloadUntil) return;
                          notify.classList.add('show');
                          setTimeout(function() {
                              notify.classList.remove('show');
                          }, 3000);
                      } else if (message.type === 'FileMoved') {
                          if (typeof TabManager !== 'undefined') {
                              TabManager.updatePath(message.from, message.to);
                          }
                          var movedPrefix = message.from + '/';
                          if (currentFile === message.from) {
                              window.location.href = '/edit/' + message.to;
                          } else if (currentFile && currentFile.indexOf(movedPrefix) === 0) {
                              window.location.href = '/edit/' + message.to + '/' + currentFile.substring(movedPrefix.length);
                          }
                      }
                  } catch(e) {}
              };

              socket.onclose = function() {
                  setTimeout(window._editorSetupLiveReload, 3000);
              };
          };

          // history
          window.toggleHistory = function() {
              var panel = document.getElementById('historyPanel');
              if (!panel) return;
              if (panel.classList.contains('show')) {
                  panel.classList.remove('show');
                  return;
              }
              panel.classList.add('show');
              loadHistory();
          };

          function loadHistory() {
              var list = document.getElementById('historyList');
              if (!list) return;
              list.innerHTML = '<div style="padding:16px;opacity:0.6">Loading...</div>';

              fetch('/api/file_history?path=' + encodeURIComponent(filePath))
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (!data.entries || data.entries.length === 0) {
                          list.innerHTML = '<div style="padding:16px;opacity:0.6">No revisions yet</div>';
                          return;
                      }
                      list.innerHTML = '';
                      data.entries.forEach(function(entry) {
                          var btn = document.createElement('div');
                          btn.className = 'history-item';
                          var d = new Date(parseInt(entry.timestamp) * 1000);
                          var timeStr = d.toLocaleString();

                          var content = document.createElement('div');
                          content.className = 'history-item-content';
                          content.innerHTML = '<div class="history-item-time">v' + entry.version + ' &middot; ' + timeStr + '</div>' +
                              '<div class="history-item-preview">' + escapeHtml(entry.preview) + '</div>';
                          content.style.cursor = 'pointer';
                          content.onclick = function() { restoreVersion(entry.timestamp, entry.version); };

                          var del = document.createElement('button');
                          del.className = 'history-item-delete';
                          del.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>';
                          del.title = 'Delete revision';
                          del.onclick = function(e) {
                              e.stopPropagation();
                              deleteHistoryEntry(entry.timestamp);
                          };

                          btn.appendChild(content);
                          btn.appendChild(del);
                          list.appendChild(btn);
                      });
                  })
                  .catch(function() {
                      list.innerHTML = '<div style="padding:16px;opacity:0.6">Failed to load revisions</div>';
                  });
          }

          function deleteHistoryEntry(timestamp) {
              showConfirm('Delete this revision? This cannot be undone.', function() {
                  fetch('/api/delete_history_entry', {
                      method: 'DELETE',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({ path: filePath, timestamp: timestamp })
                  })
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (data.success) {
                          if (_activeRevisionTimestamp === timestamp) {
                              dismissRevisionOverlay();
                          }
                          loadHistory();
                      } else {
                          alert('Failed to delete: ' + (data.error || 'unknown error'));
                      }
                  })
                  .catch(function(err) { alert('Delete failed: ' + err.message); });
              }, { destructive: true });
          }

          function restoreVersion(timestamp, version) {
              var requestId = ++_revisionRequestCounter;
              fetch('/api/restore_version', {
                  method: 'POST',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify({ path: filePath, timestamp: timestamp })
              })
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  if (requestId !== _revisionRequestCounter) return;
                  if (data.content !== undefined) {
                      _activeRevisionContent = data.content;
                      _activeRevisionTimestamp = timestamp;
                      var d = new Date(parseInt(timestamp) * 1000);

                      var overlay = document.getElementById('revisionOverlay');
                      var overlayContent = document.getElementById('revisionOverlayContent');
                      var diffSection = document.getElementById('revisionDiff');
                      var diffToggle = document.getElementById('revisionDiffToggle');
                      var controls = document.getElementById('revisionControls');

                      if (typeof marked !== 'undefined') {
                          overlayContent.innerHTML = marked.parse(data.content);
                          if (typeof hljs !== 'undefined') {
                              overlayContent.querySelectorAll('pre code').forEach(function(block) {
                                  hljs.highlightElement(block);
                              });
                          }
                          if (typeof mermaid !== 'undefined') {
                              overlayContent.querySelectorAll('.language-mermaid').forEach(function(block) {
                                  var pre = block.closest('pre');
                                  if (!pre) return;
                                  var div = document.createElement('div');
                                  div.className = 'mermaid';
                                  div.textContent = block.textContent;
                                  pre.parentNode.replaceChild(div, pre);
                              });
                              mermaid.run();
                          }
                      } else {
                          overlayContent.textContent = data.content;
                      }

                      diffSection.classList.remove('show');
                      diffSection.innerHTML = '';
                      diffToggle.classList.remove('expanded');

                      overlay.classList.add('show');
                      controls.classList.add('show');
                      var badge = document.getElementById('revisionBadge');
                      if (badge) {
                          badge.textContent = 'v' + version + ' \u00b7 ' + d.toLocaleString();
                          badge.classList.add('show');
                      }
                  }
              })
              .catch(function(err) { alert('Failed to load revision: ' + err.message); });
          }

          window.dismissRevisionOverlay = function() {
              document.getElementById('revisionOverlay').classList.remove('show');
              document.getElementById('revisionControls').classList.remove('show');
              document.getElementById('revisionDiff').classList.remove('show');
              _activeRevisionContent = null;
              _activeRevisionTimestamp = null;
              var badge = document.getElementById('revisionBadge');
              if (badge) { badge.classList.remove('show'); badge.textContent = ''; }
          };

          window.revertToRevision = function() {
              if (!_activeRevisionContent || !_activeRevisionTimestamp) return;
              var d = new Date(parseInt(_activeRevisionTimestamp) * 1000);
              showConfirm('Replace current file with revision from ' + d.toLocaleString() + '?', function() {
                  var content = _activeRevisionContent;
                  _suppressReloadUntil = Date.now() + 3000;
                  fetch('/api/save_file', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({ path: filePath, content: content })
                  })
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (!data.success) {
                          alert('Revert failed: ' + (data.error || 'unknown error'));
                          return;
                      }
                      dismissRevisionOverlay();
                      textarea.value = content;
                      updateLineNumbers();
                      updatePreview();
                      hasUnsavedChanges = false;
                      updateUnsavedIndicator();
                      var hp = document.getElementById('historyPanel');
                      if (hp && hp.classList.contains('show')) { loadHistory(); }
                  })
                  .catch(function(err) { alert('Revert failed: ' + err.message); });
              });
          };

          window.toggleRevisionDiff = function() {
              var diffSection = document.getElementById('revisionDiff');
              var toggle = document.getElementById('revisionDiffToggle');
              if (diffSection.classList.contains('show')) {
                  diffSection.classList.remove('show');
                  toggle.classList.remove('expanded');
                  return;
              }
              if (!_activeRevisionContent) return;
              var currentContent = textarea.value;
              var diffHtml = computeUnifiedDiff(currentContent, _activeRevisionContent);
              diffSection.innerHTML = '<pre>' + diffHtml + '</pre>';
              diffSection.classList.add('show');
              toggle.classList.add('expanded');
          };

          // editor pane resize
          var resizeHandle = document.getElementById('editorResizeHandle');
          if (resizeHandle) {
              var panes = document.querySelector('.editor-panes');
              resizeHandle.addEventListener('mousedown', function(e) {
                  e.preventDefault();
                  resizeHandle.classList.add('active');
                  document.body.classList.add('editor-resizing');

                  function onMove(e) {
                      var rect = panes.getBoundingClientRect();
                      var percent = ((e.clientX - rect.left) / rect.width) * 100;
                      percent = Math.min(Math.max(percent, 20), 80);
                      document.documentElement.style.setProperty('--editor-split', percent + '%');
                  }

                  function onUp() {
                      resizeHandle.classList.remove('active');
                      document.body.classList.remove('editor-resizing');
                      var val = getComputedStyle(document.documentElement).getPropertyValue('--editor-split');
                      localStorage.setItem('editor-split', parseFloat(val));
                      document.removeEventListener('mousemove', onMove);
                      document.removeEventListener('mouseup', onUp);
                  }

                  document.addEventListener('mousemove', onMove);
                  document.addEventListener('mouseup', onUp);
              });
          }

          // preview toggle (markdown only)
          var previewToggleBtn = document.getElementById('previewToggle');
          if (previewToggleBtn) {
              var editorPanes = document.querySelector('.editor-panes');
              var previewVisible = localStorage.getItem('preview-visible') !== 'false';

              function applyPreviewState() {
                  editorPanes.classList.toggle('preview-hidden', !previewVisible);
                  previewToggleBtn.classList.toggle('active', previewVisible);
              }

              window.togglePreviewPane = function() {
                  previewVisible = !previewVisible;
                  localStorage.setItem('preview-visible', previewVisible);
                  applyPreviewState();
              };

              applyPreviewState();
          }

          // scroll sync: textarea -> line numbers + preview
          if (preview) {
              var previewPane = preview.parentElement;
              textarea.addEventListener('scroll', function() {
                  lineNumbers.scrollTop = this.scrollTop;
                  var max = this.scrollHeight - this.clientHeight;
                  if (max <= 0) return;
                  var ratio = this.scrollTop / max;
                  previewPane.scrollTop = ratio * (previewPane.scrollHeight - previewPane.clientHeight);
              });
          }
      })();
    </script>
    {% else %}
    {% if no_workspace|default(false) %}
    <div class="workspace-picker-page">
      <div class="workspace-modal-content workspace-picker-card">
        <div class="workspace-picker-cols">
          <div class="picker-col-left">
            <div class="workspace-recent-heading">Recent</div>
            <input
              type="text"
              class="workspace-recent-filter"
              id="pickerPageRecentFilter"
              placeholder="Filter recent..."
              autocomplete="off"
              spellcheck="false"
              autofocus
            />
            <ul class="workspace-recent-list" id="pickerPageRecentList"></ul>
          </div>
          <div class="picker-col-right">
            <img src="/static/mdlive.png" alt="mdlive" />
            <h3>Open Workspace</h3>
            <input
              type="text"
              class="workspace-path-input"
              id="pickerPageInput"
              placeholder="~/dev/my-project"
              autocomplete="off"
              spellcheck="false"
            />
            <button class="workspace-browse-btn picker-btn-block" id="pickerBrowseBtn" type="button">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"></path>
              </svg>
              Browse
            </button>
            <button class="workspace-open-btn picker-btn-block" id="pickerOpenBtn" type="button">Open</button>
            <p class="workspace-error" id="pickerPageError"></p>
          </div>
        </div>
      </div>
      <div class="workspace-picker-version">v{{ app_version }}</div>
    </div>
    <script>
      (function() {
          var input = document.getElementById('pickerPageInput');
          var errEl = document.getElementById('pickerPageError');
          var list = document.getElementById('pickerPageRecentList');
          var browseBtn = document.getElementById('pickerBrowseBtn');
          var openBtn = document.getElementById('pickerOpenBtn');
          var filterEl = document.getElementById('pickerPageRecentFilter');

          if (filterEl) {
              filterEl.addEventListener('input', function() {
                  var q = filterEl.value.trim().toLowerCase();
                  list.querySelectorAll('.workspace-recent-item').forEach(function(it) {
                      var p = it.querySelector('.workspace-recent-path');
                      var txt = p ? p.textContent.toLowerCase() : '';
                      it.style.display = (!q || txt.indexOf(q) !== -1) ? '' : 'none';
                  });
              });
          }

          input.addEventListener('keydown', function(e) {
              if (e.key === 'Enter') {
                  var val = input.value.trim();
                  if (val) doSwitch(val);
              }
          });

          openBtn.addEventListener('click', function() {
              var val = input.value.trim();
              if (val) doSwitch(val);
          });

          browseBtn.addEventListener('click', function() {
              var startPath = input.value.trim() || '~';
              openBrowseModal(startPath, function(path) {
                  input.value = path;
                  doSwitch(path);
              });
          });

          function showErr(msg) {
              if (errEl) { errEl.textContent = msg; errEl.style.display = 'block'; }
          }

          // desktop app: spawn an independent window (own server) so multiple
          // workspaces don't share one daemon state and flip each other
          function doSwitch(path) {
              if (errEl) { errEl.style.display = 'none'; }
              fetch('/api/window/new', {
                  method: 'POST',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify({ path: path })
              })
              .then(function(r) { return r.status === 404 ? null : r.json(); })
              .then(function(data) {
                  if (data === null) { switchInPlace(path); return; }
                  if (data.success) {
                      try { window.close(); } catch (_) {}
                  } else {
                      showErr(data.error || 'Failed to open workspace');
                  }
              })
              .catch(function() { switchInPlace(path); });
          }

          // plain-browser daemon (no native windows): switch shared state in place
          function switchInPlace(path) {
              fetch('/api/workspace/switch', {
                  method: 'POST',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify({ path: path })
              })
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  if (data.success) {
                      fetch('/api/session/persist', { method: 'POST' }).catch(function() {});
                      window.location.href = '/';
                  } else {
                      showErr(data.error || 'Failed to open workspace');
                  }
              })
              .catch(function(e) { showErr('Network error: ' + e.message); });
          }

          fetch('/api/workspace/recent')
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  if (!data.recent || data.recent.length === 0) {
                      list.innerHTML = '<li class="workspace-empty">No recent workspaces</li>';
                      return;
                  }
                  data.recent.forEach(function(entry) {
                      var li = document.createElement('li');
                      li.className = 'workspace-recent-item';
                      li.onclick = function() {
                          var prev = list.querySelector('.workspace-recent-item.active');
                          if (prev) prev.classList.remove('active');
                          li.classList.add('active');
                          input.value = entry.path;
                          input.focus();
                      };
                      li.ondblclick = function() { doSwitch(entry.path); };
                      var icon = entry.mode === 'directory' ? '\uD83D\uDCC1' : '\uD83D\uDCC4';
                      var ts = window.formatRelativeTime ? window.formatRelativeTime(entry.last_opened) : '';
                      var escPath = entry.path.replace(/&/g,'&amp;').replace(/</g,'&lt;');
                      li.innerHTML = '<span class="workspace-recent-icon">' + icon + '</span>' +
                          '<span class="workspace-recent-path">' + escPath + '</span>' +
                          (ts ? '<span class="workspace-recent-ts">' + ts + '</span>' : '');
                      list.appendChild(li);
                  });
              });
      })();
    </script>
    {% else %}
    <div class="page-container">
      <div class="page-header">
        {% if current_file %}
        <span class="editor-filename">{{ current_file }}</span>
        <button
          class="copy-path-btn"
          onclick="copyFilePath(this)"
          title="Copy file path"
        >
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
        </button>
        <a
          class="edit-toggle"
          href="/edit/{{ current_file|safe }}"
          title="Edit"
        >
          <svg
            width="16"
            height="16"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
          >
            <path
              d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
            ></path>
            <path
              d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
            ></path>
          </svg>
        </a>
        {% if has_history %}
        <span class="revision-badge" id="viewRevisionBadge"></span>
        <span class="revision-controls" id="viewRevisionControls">
          <span class="header-separator"></span>
          <button
            class="revision-diff-toggle"
            id="viewRevisionDiffToggle"
            onclick="toggleViewDiff()"
          >
            <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor">
              <path d="M8 5v14l11-7z" />
            </svg>
            Show changes
          </button>
          <button class="editor-btn" onclick="revertToViewRevision()">
            Revert to this version
          </button>
          <button class="editor-btn" onclick="dismissViewRevision()">
            Back to current
          </button>
        </span>
        {% endif %} {% endif %}
        <div class="editor-spacer"></div>
        {% if has_history and current_file %}
        <button class="editor-btn" onclick="toggleHistory()">Revisions</button>
        {% endif %}
        <img src="/static/mdlive.png" alt="mdlive" class="branding-logo" />
      </div>
      <div id="viewRevisionDiff" class="revision-diff"></div>
      <div id="content" {% if file_type != "markdown" %}class="content-code"{% endif %}>{{ content }}</div>
    </div>

    {% if has_history and not editor_mode %}
    <div class="history-panel" id="historyPanel">
      <div class="history-panel-header">
        <span>Revisions</span>
        <button class="history-panel-close" onclick="toggleHistory()">x</button>
      </div>
      <div class="history-list" id="historyList"></div>
    </div>
    <script src="/marked.min.js"></script>
    <script>
      (function() {
          var filePath = {{ current_file|tojson }};

          window.toggleHistory = function() {
              var panel = document.getElementById('historyPanel');
              if (!panel) return;
              if (panel.classList.contains('show')) {
                  panel.classList.remove('show');
                  return;
              }
              panel.classList.add('show');
              loadHistory();
          };

          function loadHistory() {
              var list = document.getElementById('historyList');
              if (!list) return;
              list.innerHTML = '<div style="padding:16px;opacity:0.6">Loading...</div>';

              fetch('/api/file_history?path=' + encodeURIComponent(filePath))
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (!data.entries || data.entries.length === 0) {
                          list.innerHTML = '<div style="padding:16px;opacity:0.6">No revisions yet</div>';
                          return;
                      }
                      list.innerHTML = '';
                      data.entries.forEach(function(entry) {
                          var btn = document.createElement('div');
                          btn.className = 'history-item';
                          var d = new Date(parseInt(entry.timestamp) * 1000);
                          var timeStr = d.toLocaleString();

                          var content = document.createElement('div');
                          content.className = 'history-item-content';
                          content.innerHTML = '<div class="history-item-time">v' + entry.version + ' &middot; ' + timeStr + '</div>' +
                              '<div class="history-item-preview">' + escapeHtml(entry.preview) + '</div>';
                          content.style.cursor = 'pointer';
                          content.onclick = function() { restoreVersion(entry.timestamp, entry.version); };

                          var del = document.createElement('button');
                          del.className = 'history-item-delete';
                          del.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>';
                          del.title = 'Delete revision';
                          del.onclick = function(e) {
                              e.stopPropagation();
                              deleteHistoryEntry(entry.timestamp);
                          };

                          btn.appendChild(content);
                          btn.appendChild(del);
                          list.appendChild(btn);
                      });
                  })
                  .catch(function() {
                      list.innerHTML = '<div style="padding:16px;opacity:0.6">Failed to load revisions</div>';
                  });
          }

          var _viewOriginalContent = null;
          var _viewRevisionContent = null;
          var _viewRevisionTimestamp = null;
          var _viewCurrentRawContent = null;

          function deleteHistoryEntry(timestamp) {
              showConfirm('Delete this revision? This cannot be undone.', function() {
                  fetch('/api/delete_history_entry', {
                      method: 'DELETE',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({ path: filePath, timestamp: timestamp })
                  })
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (data.success) {
                          if (_viewRevisionTimestamp === timestamp) {
                              dismissViewRevision();
                          }
                          loadHistory();
                      } else {
                          alert('Failed to delete: ' + (data.error || 'unknown error'));
                      }
                  })
                  .catch(function(err) { alert('Delete failed: ' + err.message); });
              }, { destructive: true });
          }

          function restoreVersion(timestamp, version) {
              fetch('/api/restore_version', {
                  method: 'POST',
                  headers: { 'Content-Type': 'application/json' },
                  body: JSON.stringify({ path: filePath, timestamp: timestamp })
              })
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  if (data.content !== undefined) {
                      var contentDiv = document.getElementById('content');
                      if (!_viewOriginalContent) {
                          _viewOriginalContent = contentDiv.innerHTML;
                      }
                      _viewRevisionContent = data.content;
                      _viewRevisionTimestamp = timestamp;
                      var d = new Date(parseInt(timestamp) * 1000);

                      var badge = document.getElementById('viewRevisionBadge');
                      var controls = document.getElementById('viewRevisionControls');
                      var diffSection = document.getElementById('viewRevisionDiff');
                      var diffToggle = document.getElementById('viewRevisionDiffToggle');

                      badge.textContent = 'v' + version + ' \u00b7 ' + d.toLocaleString();
                      badge.classList.add('show');
                      controls.classList.add('show');

                      diffSection.classList.remove('show');
                      diffSection.innerHTML = '';
                      diffToggle.classList.remove('expanded');

                      if (typeof marked !== 'undefined') {
                          contentDiv.innerHTML = marked.parse(data.content);
                          if (typeof hljs !== 'undefined') {
                              contentDiv.querySelectorAll('pre code').forEach(function(block) {
                                  hljs.highlightElement(block);
                              });
                          }
                          if (typeof mermaid !== 'undefined') {
                              contentDiv.querySelectorAll('.language-mermaid').forEach(function(block) {
                                  var pre = block.closest('pre');
                                  if (!pre) return;
                                  var div = document.createElement('div');
                                  div.className = 'mermaid';
                                  div.textContent = block.textContent;
                                  pre.parentNode.replaceChild(div, pre);
                              });
                              mermaid.run();
                          }
                      } else {
                          contentDiv.textContent = data.content;
                      }
                  }
              })
              .catch(function(err) { alert('Failed to load revision: ' + err.message); });
          }

          window.dismissViewRevision = function() {
              var contentDiv = document.getElementById('content');
              if (_viewOriginalContent) {
                  contentDiv.innerHTML = _viewOriginalContent;
              }
              _viewOriginalContent = null;
              _viewRevisionContent = null;
              _viewRevisionTimestamp = null;
              document.getElementById('viewRevisionBadge').classList.remove('show');
              document.getElementById('viewRevisionBadge').textContent = '';
              document.getElementById('viewRevisionControls').classList.remove('show');
              document.getElementById('viewRevisionDiff').classList.remove('show');
          };

          window.revertToViewRevision = function() {
              if (!_viewRevisionContent || !_viewRevisionTimestamp) return;
              var d = new Date(parseInt(_viewRevisionTimestamp) * 1000);
              showConfirm('Replace current file with revision from ' + d.toLocaleString() + '?', function() {
                  fetch('/api/save_file', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({ path: filePath, content: _viewRevisionContent })
                  })
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (!data.success) {
                          alert('Revert failed: ' + (data.error || 'unknown error'));
                          return;
                      }
                      _viewOriginalContent = null;
                      window.location.reload();
                  })
                  .catch(function(err) { alert('Revert failed: ' + err.message); });
              });
          };

          window.toggleViewDiff = function() {
              var diffSection = document.getElementById('viewRevisionDiff');
              var toggle = document.getElementById('viewRevisionDiffToggle');
              if (diffSection.classList.contains('show')) {
                  diffSection.classList.remove('show');
                  toggle.classList.remove('expanded');
                  return;
              }
              if (!_viewRevisionContent) return;

              // fetch current raw content for diff
              if (_viewCurrentRawContent !== null) {
                  showViewDiff();
              } else {
                  fetch('/api/raw_content?path=' + encodeURIComponent(filePath))
                      .then(function(r) { return r.text(); })
                      .then(function(text) {
                          _viewCurrentRawContent = text;
                          showViewDiff();
                      })
                      .catch(function() { alert('Failed to load current content for diff'); });
              }
          };

          function showViewDiff() {
              if (!_viewCurrentRawContent || !_viewRevisionContent) return;
              var diffSection = document.getElementById('viewRevisionDiff');
              var toggle = document.getElementById('viewRevisionDiffToggle');
              var diffHtml = computeUnifiedDiff(_viewCurrentRawContent, _viewRevisionContent);
              diffSection.innerHTML = '<pre>' + diffHtml + '</pre>';
              diffSection.classList.add('show');
              toggle.classList.add('expanded');
          }

      })();
    </script>
    {% endif %} {% endif %} {% endif %}

    <div class="status-bar" id="statusBar">
      {% if base_dir %}
      <div class="status-bar-path" title="{{ base_dir }}"><span>{{ base_dir }}</span></div>
      {% if current_file %}<div class="status-bar-mode">{{ current_file }}</div>{% endif %}
      {% endif %}
      <div class="status-bar-spacer"></div>
      {% if editor_mode %}<div class="status-bar-mode">EDIT</div>{% endif %}
      <div class="status-bar-version">v{{ app_version }}</div>
    </div>

    <div class="browse-modal" id="browseModal" onclick="if(event.target===this)closeBrowseModal()">
      <div class="browse-modal-content">
        <div class="browse-modal-header">
          <h3>Browse</h3>
          <button class="browse-modal-close" onclick="closeBrowseModal()" title="Close">&times;</button>
        </div>
        <div class="browse-modal-bar">
          <button class="browse-modal-up" id="browseUp" title="Parent directory">&#8593;</button>
          <input type="text" class="browse-modal-path" id="browsePath" spellcheck="false" autocomplete="off" />
        </div>
        <div class="browse-modal-controls">
          <button class="browse-sort-btn active" id="browseSortName" onclick="browseSortBy('name')">Name</button>
          <button class="browse-sort-btn" id="browseSortModified" onclick="browseSortBy('modified')">Modified</button>
          <label style="margin-left:auto"><input type="checkbox" id="browseShowHidden" onchange="browseToggleHidden()"> Hidden</label>
        </div>
        <ul class="browse-modal-list" id="browseList"></ul>
        <div class="browse-modal-footer">
          <button class="browse-modal-btn" onclick="closeBrowseModal()">Cancel</button>
          <button class="browse-modal-btn browse-modal-btn-primary" id="browseOpenBtn" onclick="browseSelectCurrent()">Open</button>
        </div>
      </div>
    </div>

    <div class="theme-modal" id="themeModal">
      <div class="theme-modal-content">
        <h3>Appearance</h3>
        <div class="theme-grid">
          <div
            class="theme-card"
            data-theme="catppuccin-latte"
            onclick="selectTheme('catppuccin-latte')"
          >
            <div class="theme-card-icon">☕</div>
            <div class="theme-card-name">Catppuccin Latte</div>
            <div class="theme-card-preview">
              <div class="theme-color-swatch" style="background: #eff1f5"></div>
              <div class="theme-color-swatch" style="background: #4c4f69"></div>
              <div class="theme-color-swatch" style="background: #1e66f5"></div>
            </div>
            <div class="theme-card-sample">Warm light theme</div>
          </div>

          <div
            class="theme-card"
            data-theme="catppuccin-macchiato"
            onclick="selectTheme('catppuccin-macchiato')"
          >
            <div class="theme-card-icon">🥛</div>
            <div class="theme-card-name">Catppuccin Macchiato</div>
            <div class="theme-card-preview">
              <div class="theme-color-swatch" style="background: #24273a"></div>
              <div class="theme-color-swatch" style="background: #cad3f5"></div>
              <div class="theme-color-swatch" style="background: #8aadf4"></div>
            </div>
            <div class="theme-card-sample">Medium contrast</div>
          </div>

          <div
            class="theme-card"
            data-theme="catppuccin-mocha"
            onclick="selectTheme('catppuccin-mocha')"
          >
            <div class="theme-card-icon">🐱</div>
            <div class="theme-card-name">Catppuccin Mocha</div>
            <div class="theme-card-preview">
              <div class="theme-color-swatch" style="background: #1e1e2e"></div>
              <div class="theme-color-swatch" style="background: #cdd6f4"></div>
              <div class="theme-color-swatch" style="background: #89b4fa"></div>
            </div>
            <div class="theme-card-sample">Dark and cozy</div>
          </div>

          <div
            class="theme-card"
            data-theme="light"
            onclick="selectTheme('light')"
          >
            <div class="theme-card-icon">☀️</div>
            <div class="theme-card-name">Light</div>
            <div class="theme-card-preview">
              <div class="theme-color-swatch" style="background: #fff"></div>
              <div class="theme-color-swatch" style="background: #333"></div>
              <div class="theme-color-swatch" style="background: #0366d6"></div>
            </div>
            <div class="theme-card-sample">Classic bright</div>
          </div>

          <div
            class="theme-card"
            data-theme="dark"
            onclick="selectTheme('dark')"
          >
            <div class="theme-card-icon">🌙</div>
            <div class="theme-card-name">Dark</div>
            <div class="theme-card-preview">
              <div class="theme-color-swatch" style="background: #0d1117"></div>
              <div class="theme-color-swatch" style="background: #e6edf3"></div>
              <div class="theme-color-swatch" style="background: #58a6ff"></div>
            </div>
            <div class="theme-card-sample">Classic dark</div>
          </div>
        </div>
        <h4 style="margin: 20px 0 12px 0; text-align: center;">Content Width</h4>
        <div class="theme-grid" style="grid-template-columns: repeat(4, 1fr);">
          <button type="button" class="width-card" data-width="narrow" onclick="setContentWidth('narrow')">
            <div class="theme-card-icon">|||</div>
            <div class="theme-card-name">Narrow</div>
            <div class="theme-card-sample">680px</div>
          </button>
          <button type="button" class="width-card" data-width="default" onclick="setContentWidth('default')">
            <div class="theme-card-icon">| |</div>
            <div class="theme-card-name">Default</div>
            <div class="theme-card-sample">900px</div>
          </button>
          <button type="button" class="width-card" data-width="wide" onclick="setContentWidth('wide')">
            <div class="theme-card-icon">|  |</div>
            <div class="theme-card-name">Wide</div>
            <div class="theme-card-sample">1200px</div>
          </button>
          <button type="button" class="width-card" data-width="full" onclick="setContentWidth('full')">
            <div class="theme-card-icon">[  ]</div>
            <div class="theme-card-name">Full</div>
            <div class="theme-card-sample">100%</div>
          </button>
        </div>
      </div>
    </div>

    <div class="find-bar" id="findBar" role="search">
      <input
        type="text"
        id="findInput"
        placeholder="Find in page"
        autocomplete="off"
        spellcheck="false"
      />
      <span class="find-count" id="findCount">0 / 0</span>
      <button type="button" id="findPrev" title="Previous (Shift+Enter)">&#9650;</button>
      <button type="button" id="findNext" title="Next (Enter)">&#9660;</button>
      <button type="button" id="findClose" title="Close (Esc)">&times;</button>
    </div>

    <div class="shortcuts-modal" id="shortcutsModal">
      <div class="shortcuts-modal-content">
        <h3>Keyboard Shortcuts</h3>
        <table class="shortcuts-table">
          <tr>
            <td><span class="shortcuts-key">/</span></td>
            <td>Show shortcuts</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">e</span></td>
            <td>Edit file</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">n</span></td>
            <td>New file</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">d</span></td>
            <td>Delete file</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">k</span></td>
            <td>Toggle sidebar</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">s</span></td>
            <td>Focus search</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">Cmd/Ctrl+F</span></td>
            <td>Find in page</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">Ctrl+S</span></td>
            <td>Save</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">h</span> <span class="shortcuts-key">r</span></td>
            <td>Toggle revisions</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">w</span></td>
            <td>Close tab</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">Shift+W</span></td>
            <td>Cycle content width</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">o</span></td>
            <td>Open workspace</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">?</span></td>
            <td>About / attribution</td>
          </tr>
          <tr>
            <td><span class="shortcuts-key">Esc</span></td>
            <td>Close / cancel</td>
          </tr>
        </table>
      </div>
    </div>

    <div class="about-modal" id="aboutModal">
      <div class="about-modal-content">
        <img src="/static/mdlive.png" alt="mdlive" class="about-logo" />
        <p class="about-company">Bearded Giant, LLC</p>
        <a class="about-github" href="https://github.com/bearded-giant/mdlive" target="_blank" rel="noopener">
          <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
          github.com/bearded-giant/mdlive
        </a>
        <hr class="about-divider" />
        <p class="about-attribution">Originally based on mdserve by Jose Fernandez</p>
        <div class="about-libs-heading">Built with</div>
        <ul class="about-libs">
          <li><span>axum</span><span>Web framework</span></li>
          <li><span>minijinja</span><span>Templating</span></li>
          <li><span>highlight.js</span><span>Syntax highlighting</span></li>
          <li><span>Mermaid</span><span>Diagrams</span></li>
          <li><span>marked</span><span>Markdown preview</span></li>
        </ul>
        <p class="about-license">MIT License</p>
      </div>
    </div>

    {% if daemon_mode|default(false) %}
    <div class="workspace-modal" id="workspaceModal">
      <div class="workspace-modal-content">
        <h3>Open Workspace</h3>
        <div class="workspace-input-row">
          <input
            type="text"
            class="workspace-path-input"
            id="workspacePathInput"
            placeholder="~/dev/my-project or ~/notes/todo.md"
            autocomplete="off"
            spellcheck="false"
          />
          <button class="workspace-browse-btn" id="modalBrowseBtn" type="button">
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"></path>
            </svg>
            Browse
          </button>
          <button class="workspace-open-btn" id="modalOpenBtn" type="button">Open</button>
        </div>
        <p class="workspace-error" id="workspaceError"></p>
        <div class="workspace-recent-heading">Recent</div>
        <input type="text" class="workspace-recent-filter" id="workspaceRecentFilter" placeholder="Filter recent..." autocomplete="off" spellcheck="false" />
        <ul class="workspace-recent-list" id="workspaceRecentList">
        </ul>
      </div>
    </div>
    {% endif %}

    <script>
      function openShortcutsModal() {
          document.getElementById('shortcutsModal').classList.add('show');
      }
      function closeShortcutsModal() {
          document.getElementById('shortcutsModal').classList.remove('show');
      }
      function openAboutModal() {
          document.getElementById('aboutModal').classList.add('show');
      }
      function closeAboutModal() {
          document.getElementById('aboutModal').classList.remove('show');
      }

      var _isDaemonMode = {{ daemon_mode|default(false)|tojson }};

      function openWorkspaceModal() {
          var modal = document.getElementById('workspaceModal');
          if (!modal) return;
          modal.classList.add('show');
          loadRecentWorkspaces();
          var input = document.getElementById('workspacePathInput');
          if (input) setTimeout(function() { input.focus(); }, 100);
      }

      function closeWorkspaceModal() {
          var modal = document.getElementById('workspaceModal');
          if (!modal) return;
          modal.classList.remove('show');
          var err = document.getElementById('workspaceError');
          if (err) { err.style.display = 'none'; err.textContent = ''; }
      }

      function loadRecentWorkspaces() {
          var list = document.getElementById('workspaceRecentList');
          if (!list) return;
          fetch('/api/workspace/recent')
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  list.innerHTML = '';
                  if (!data.recent || data.recent.length === 0) {
                      list.innerHTML = '<li class="workspace-empty">No recent workspaces</li>';
                      return;
                  }
                  var wsInput = document.getElementById('workspacePathInput');
                  data.recent.forEach(function(entry) {
                      var li = document.createElement('li');
                      li.className = 'workspace-recent-item';
                      li.onclick = function() {
                          var prev = list.querySelector('.workspace-recent-item.active');
                          if (prev) prev.classList.remove('active');
                          li.classList.add('active');
                          if (wsInput) { wsInput.value = entry.path; wsInput.focus(); }
                      };
                      li.ondblclick = function() { switchWorkspace(entry.path); };
                      var icon = entry.mode === 'directory' ? '\uD83D\uDCC1' : '\uD83D\uDCC4';
                      var ts = window.formatRelativeTime ? window.formatRelativeTime(entry.last_opened) : '';
                      li.innerHTML = '<span class="workspace-recent-icon">' + icon + '</span>' +
                          '<span class="workspace-recent-path">' + escapeHtml(entry.path) + '</span>' +
                          (ts ? '<span class="workspace-recent-ts">' + ts + '</span>' : '');
                      list.appendChild(li);
                  });
                  var filterEl = document.getElementById('workspaceRecentFilter');
                  if (filterEl) {
                      filterEl.value = '';
                      filterEl.oninput = function() {
                          var q = filterEl.value.trim().toLowerCase();
                          list.querySelectorAll('.workspace-recent-item').forEach(function(it) {
                              var p = it.querySelector('.workspace-recent-path');
                              var txt = p ? p.textContent.toLowerCase() : '';
                              it.style.display = (!q || txt.indexOf(q) !== -1) ? '' : 'none';
                          });
                      };
                  }
              });
      }

      function switchWorkspace(path) {
          var err = document.getElementById('workspaceError');
          if (err) { err.style.display = 'none'; }
          fetch('/api/workspace/switch', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ path: path })
          })
          .then(function(r) { return r.json(); })
          .then(function(data) {
              if (data.success) {
                  fetch('/api/session/persist', { method: 'POST' }).catch(function() {});
                  window.location.href = '/';
              } else {
                  if (err) {
                      err.textContent = data.error || 'Failed to switch workspace';
                      err.style.display = 'block';
                  }
              }
          })
          .catch(function(e) {
              if (err) {
                  err.textContent = 'Network error: ' + e.message;
                  err.style.display = 'block';
              }
          });
      }

      function escapeHtml(str) {
          var div = document.createElement('div');
          div.textContent = str;
          return div.innerHTML;
      }

      function computeUnifiedDiff(oldText, newText) {
          if (!oldText || !newText) return '<span class="diff-context">Unable to compute diff</span>';
          var oldLines = oldText.split('\n');
          var newLines = newText.split('\n');

          var m = oldLines.length, n = newLines.length;
          var dp = [];
          for (var i = 0; i <= m; i++) {
              dp[i] = [];
              for (var j = 0; j <= n; j++) {
                  if (i === 0 || j === 0) dp[i][j] = 0;
                  else if (oldLines[i-1] === newLines[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
                  else dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
              }
          }

          var ops = [];
          var oi = m, ni = n;
          while (oi > 0 || ni > 0) {
              if (oi > 0 && ni > 0 && oldLines[oi-1] === newLines[ni-1]) {
                  ops.unshift({ type: 'context', text: oldLines[oi-1], oldIdx: oi, newIdx: ni });
                  oi--; ni--;
              } else if (ni > 0 && (oi === 0 || dp[oi][ni-1] >= dp[oi-1][ni])) {
                  ops.unshift({ type: 'add', text: newLines[ni-1], newIdx: ni });
                  ni--;
              } else {
                  ops.unshift({ type: 'del', text: oldLines[oi-1], oldIdx: oi });
                  oi--;
              }
          }

          var hunks = [];
          var currentHunk = null;
          var trailingContext = 0;

          for (var k = 0; k < ops.length; k++) {
              var op = ops[k];
              if (op.type === 'context') {
                  if (currentHunk) {
                      currentHunk.lines.push(op);
                      trailingContext++;
                      if (trailingContext >= 3) {
                          var moreChanges = false;
                          for (var look = k + 1; look < ops.length; look++) {
                              if (ops[look].type !== 'context') { moreChanges = true; break; }
                          }
                          if (!moreChanges || (look - k) > 3) {
                              hunks.push(currentHunk);
                              currentHunk = null;
                              trailingContext = 0;
                          }
                      }
                  }
              } else {
                  trailingContext = 0;
                  if (!currentHunk) {
                      currentHunk = { lines: [] };
                      var start = k - 1;
                      var contextCount = 0;
                      while (start >= 0 && ops[start].type === 'context' && contextCount < 3) {
                          start--;
                          contextCount++;
                      }
                      for (var c = start + 1; c < k; c++) {
                          if (ops[c].type === 'context') currentHunk.lines.push(ops[c]);
                      }
                  }
                  currentHunk.lines.push(op);
              }
          }
          if (currentHunk) hunks.push(currentHunk);

          if (hunks.length === 0) return '<span class="diff-context">No changes</span>';

          var html = '';
          hunks.forEach(function(hunk) {
              var firstOld = null, firstNew = null;
              hunk.lines.forEach(function(l) {
                  if (firstOld === null && l.oldIdx) firstOld = l.oldIdx;
                  if (firstNew === null && l.newIdx) firstNew = l.newIdx;
              });
              html += '<span class="diff-hunk">@@ -' + (firstOld || 1) + ' +' + (firstNew || 1) + ' @@</span>\n';
              hunk.lines.forEach(function(l) {
                  var escaped = escapeHtml(l.text);
                  if (l.type === 'del') html += '<span class="diff-del">-' + escaped + '</span>\n';
                  else if (l.type === 'add') html += '<span class="diff-add">+' + escaped + '</span>\n';
                  else html += '<span class="diff-context"> ' + escaped + '</span>\n';
              });
          });
          return html;
      }

      var _browseCallback = null;
      var _browseCurrentPath = '';
      var _browseSelectedFile = null;
      var _browseTreeCache = {};
      var _browseTreeRoot = '';
      var _browseSortMode = localStorage.getItem('mdlive_browse_sort') || 'name';
      var _browseShowHidden = localStorage.getItem('mdlive_browse_hidden') === 'true';

      function browseRelativeTime(epoch) {
          if (!epoch) return '';
          var now = Date.now() / 1000;
          var diff = now - epoch;
          if (diff < 60) return 'just now';
          if (diff < 3600) return Math.floor(diff / 60) + 'm ago';
          if (diff < 86400) return Math.floor(diff / 3600) + 'h ago';
          if (diff < 604800) return Math.floor(diff / 86400) + 'd ago';
          if (diff < 2592000) return Math.floor(diff / 604800) + 'w ago';
          var d = new Date(epoch * 1000);
          return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
      }

      function browseBuildUrl(path) {
          var params = [];
          if (path) params.push('path=' + encodeURIComponent(path));
          if (_browseShowHidden) params.push('show_hidden=true');
          if (_browseSortMode !== 'name') params.push('sort=' + _browseSortMode);
          return '/api/workspace/browse' + (params.length ? '?' + params.join('&') : '');
      }

      function browseGetExpandedDirs() {
          var dirs = [];
          for (var key in _browseTreeCache) {
              if (_browseTreeCache[key].expanded && key !== _browseTreeRoot) dirs.push(key);
          }
          return dirs;
      }

      function browseRefetchExpanded(expandedDirs) {
          if (expandedDirs.length === 0) { browseRenderTree(); return; }
          var remaining = expandedDirs.length;
          expandedDirs.forEach(function(dir) {
              fetch(browseBuildUrl(dir))
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (data.success) {
                          _browseTreeCache[dir] = { entries: data.entries, expanded: true };
                      } else {
                          delete _browseTreeCache[dir];
                      }
                  })
                  .catch(function() { delete _browseTreeCache[dir]; })
                  .finally(function() {
                      remaining--;
                      if (remaining === 0) browseRenderTree();
                  });
          });
      }

      function browseSortBy(mode) {
          _browseSortMode = mode;
          localStorage.setItem('mdlive_browse_sort', mode);
          document.getElementById('browseSortName').classList.toggle('active', mode === 'name');
          document.getElementById('browseSortModified').classList.toggle('active', mode === 'modified');
          browseRefresh();
      }

      function browseToggleHidden() {
          _browseShowHidden = document.getElementById('browseShowHidden').checked;
          localStorage.setItem('mdlive_browse_hidden', _browseShowHidden);
          browseRefresh();
      }

      function browseRefresh() {
          if (!_browseCurrentPath) return;
          var expandedDirs = browseGetExpandedDirs();
          fetch(browseBuildUrl(_browseCurrentPath))
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  if (!data.success) return;
                  _browseTreeCache = {};
                  _browseTreeCache[data.path] = { entries: data.entries, expanded: true };
                  _browseTreeRoot = data.path;
                  browseRefetchExpanded(expandedDirs);
              });
      }

      function openBrowseModal(startPath, onSelect) {
          _browseCallback = onSelect;
          _browseSelectedFile = null;
          _browseTreeCache = {};
          var modal = document.getElementById('browseModal');
          modal.classList.add('show');

          var hiddenCb = document.getElementById('browseShowHidden');
          if (hiddenCb) hiddenCb.checked = _browseShowHidden;
          document.getElementById('browseSortName').classList.toggle('active', _browseSortMode === 'name');
          document.getElementById('browseSortModified').classList.toggle('active', _browseSortMode === 'modified');

          var pathInput = document.getElementById('browsePath');
          if (!pathInput._bound) {
              pathInput._bound = true;
              pathInput.addEventListener('keydown', function(e) {
                  if (e.key === 'Enter') {
                      e.preventDefault();
                      var val = pathInput.value.trim();
                      if (val) browseNavigateTo(val);
                  }
                  if (e.key === 'Escape') {
                      e.stopPropagation();
                      closeBrowseModal();
                  }
              });
          }
          var initial = startPath && startPath !== '~' ? startPath : '';
          browseNavigateTo(initial);
      }

      function closeBrowseModal() {
          var modal = document.getElementById('browseModal');
          modal.classList.remove('show');
          _browseCallback = null;
          _browseSelectedFile = null;
      }

      function browseUpdateOpenBtn() {
          var btn = document.getElementById('browseOpenBtn');
          if (!btn) return;
          if (_browseSelectedFile) {
              var parts = _browseSelectedFile.split('/');
              btn.textContent = 'Open ' + parts[parts.length - 1];
          } else {
              btn.textContent = 'Open folder';
          }
      }

      function browseNavigateTo(path, autoExpandChild) {
          var listEl = document.getElementById('browseList');
          var pathInput = document.getElementById('browsePath');
          var upBtn = document.getElementById('browseUp');

          _browseSelectedFile = null;
          _browseTreeCache = {};
          browseUpdateOpenBtn();

          listEl.innerHTML = '<li style="padding:16px;text-align:center;opacity:0.5;font-size:13px">Loading...</li>';

          fetch(browseBuildUrl(path))
              .then(function(r) { return r.json(); })
              .then(function(data) {
                  if (!data.success) {
                      listEl.innerHTML = '<li style="padding:16px;color:#e74c3c;font-size:13px">' + escapeHtml(data.error || 'Error') + '</li>';
                      return;
                  }
                  _browseCurrentPath = data.path;
                  _browseTreeRoot = data.path;
                  pathInput.value = data.path;

                  upBtn.disabled = !data.parent;
                  upBtn.onclick = data.parent ? function() { browseNavigateTo(data.parent, data.path); } : null;

                  _browseTreeCache[data.path] = { entries: data.entries, expanded: true };

                  if (autoExpandChild) {
                      _browseScrollTarget = autoExpandChild;
                      browseToggleDir(autoExpandChild);
                  } else {
                      browseRenderTree();
                  }
              })
              .catch(function() {
                  listEl.innerHTML = '<li style="padding:16px;color:#e74c3c;font-size:13px">Network error</li>';
              });
      }

      var _browseScrollTarget = null;

      function browseRenderTree() {
          var listEl = document.getElementById('browseList');
          listEl.innerHTML = '';

          var rootCache = _browseTreeCache[_browseTreeRoot];
          if (!rootCache || rootCache.entries.length === 0) {
              listEl.innerHTML = '<li style="padding:16px;text-align:center;opacity:0.5;font-size:13px">No supported files</li>';
              return;
          }
          browseRenderLevel(listEl, _browseTreeRoot, 0);

          if (_browseScrollTarget) {
              var target = document.querySelector('[data-browse-path="' + CSS.escape(_browseScrollTarget) + '"]');
              if (target) target.scrollIntoView({ block: 'center' });
              _browseScrollTarget = null;
          }
      }

      function browseRenderLevel(container, dirPath, depth) {
          var cached = _browseTreeCache[dirPath];
          if (!cached) return;

          cached.entries.forEach(function(entry) {
              var li = document.createElement('li');
              li.className = 'browse-modal-item';
              li.style.paddingLeft = (depth * 20 + 16) + 'px';
              li.setAttribute('data-browse-path', entry.path);

              if (_browseSelectedFile === entry.path) {
                  li.classList.add('selected');
              }

              if (entry.is_dir) {
                  var arrow = document.createElement('span');
                  arrow.className = 'browse-tree-arrow';
                  var isExpanded = _browseTreeCache[entry.path] && _browseTreeCache[entry.path].expanded;
                  arrow.textContent = '\u25B6';
                  if (isExpanded) arrow.classList.add('expanded');
                  arrow.onclick = function(e) {
                      e.stopPropagation();
                      browseToggleDir(entry.path);
                  };
                  li.appendChild(arrow);

                  var icon = document.createElement('span');
                  icon.className = 'browse-modal-item-icon';
                  icon.textContent = '\uD83D\uDCC1';
                  li.appendChild(icon);

                  var nameEl = document.createElement('span');
                  nameEl.className = 'browse-modal-item-name';
                  nameEl.textContent = entry.name;
                  li.appendChild(nameEl);

                  if (entry.modified) {
                      var timeEl = document.createElement('span');
                      timeEl.className = 'browse-modal-item-time';
                      timeEl.textContent = browseRelativeTime(entry.modified);
                      li.appendChild(timeEl);
                  }

                  li.onclick = function(e) {
                      if (e.target === arrow) return;
                      browseSelectItem(entry);
                  };
                  li.ondblclick = function(e) {
                      e.stopPropagation();
                      browseToggleDir(entry.path);
                  };
              } else {
                  var placeholder = document.createElement('span');
                  placeholder.className = 'browse-tree-arrow-placeholder';
                  li.appendChild(placeholder);

                  var icon = document.createElement('span');
                  icon.className = 'browse-modal-item-icon';
                  icon.textContent = '\uD83D\uDCC4';
                  li.appendChild(icon);

                  var nameEl = document.createElement('span');
                  nameEl.className = 'browse-modal-item-name';
                  nameEl.textContent = entry.name;
                  li.appendChild(nameEl);

                  if (entry.modified) {
                      var timeEl = document.createElement('span');
                      timeEl.className = 'browse-modal-item-time';
                      timeEl.textContent = browseRelativeTime(entry.modified);
                      li.appendChild(timeEl);
                  }

                  li.onclick = function() { browseSelectItem(entry); };
                  li.ondblclick = function() {
                      _browseSelectedFile = entry.path;
                      browseSelectCurrent();
                  };
              }

              container.appendChild(li);

              if (entry.is_dir && _browseTreeCache[entry.path]) {
                  var childCache = _browseTreeCache[entry.path];
                  if (childCache.loading && childCache.entries.length === 0) {
                      var loadingLi = document.createElement('li');
                      loadingLi.className = 'browse-modal-item browse-tree-loading';
                      loadingLi.style.paddingLeft = ((depth + 1) * 20 + 16) + 'px';
                      loadingLi.textContent = 'Loading...';
                      container.appendChild(loadingLi);
                  } else if (childCache.error) {
                      var errLi = document.createElement('li');
                      errLi.className = 'browse-modal-item browse-tree-loading';
                      errLi.style.paddingLeft = ((depth + 1) * 20 + 16) + 'px';
                      errLi.style.color = '#e74c3c';
                      errLi.textContent = childCache.error;
                      container.appendChild(errLi);
                  } else if (childCache.expanded) {
                      browseRenderLevel(container, entry.path, depth + 1);
                  }
              }
          });
      }

      function browseToggleDir(dirPath) {
          var cached = _browseTreeCache[dirPath];
          if (cached) {
              cached.expanded = !cached.expanded;
              browseRenderTree();
          } else {
              _browseTreeCache[dirPath] = { entries: [], expanded: true, loading: true };
              browseRenderTree();

              fetch(browseBuildUrl(dirPath))
                  .then(function(r) { return r.json(); })
                  .then(function(data) {
                      if (!data.success) {
                          _browseTreeCache[dirPath] = { entries: [], expanded: true, error: data.error || 'Error' };
                      } else {
                          _browseTreeCache[dirPath] = { entries: data.entries, expanded: true };
                      }
                      browseRenderTree();
                  })
                  .catch(function() {
                      _browseTreeCache[dirPath] = { entries: [], expanded: true, error: 'Network error' };
                      browseRenderTree();
                  });
          }
      }

      function browseSelectItem(entry) {
          if (_browseSelectedFile === entry.path) {
              _browseSelectedFile = null;
          } else {
              _browseSelectedFile = entry.path;
          }
          browseUpdateOpenBtn();
          browseRenderTree();
      }

      function browseSelectCurrent() {
          var selected = _browseSelectedFile || _browseCurrentPath;
          var callback = _browseCallback;
          closeBrowseModal();
          if (callback && selected) callback(selected);
      }

      // wire up modal browse + open buttons (daemon workspace switcher)
      (function() {
          var btn = document.getElementById('modalBrowseBtn');
          if (!btn) return;
          var input = document.getElementById('workspacePathInput');
          btn.addEventListener('click', function() {
              var startPath = input.value.trim() || '~';
              openBrowseModal(startPath, function(path) {
                  input.value = path;
                  switchWorkspace(path);
              });
          });
          var openBtn = document.getElementById('modalOpenBtn');
          if (openBtn) {
              openBtn.addEventListener('click', function() {
                  var val = input.value.trim();
                  if (val) switchWorkspace(val);
              });
          }
      })();

      document.addEventListener('keydown', function(e) {
          if (e.ctrlKey || e.metaKey || e.altKey) return;

          var tag = document.activeElement.tagName;
          if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') {
              if (e.key === 'Escape') document.activeElement.blur();
              return;
          }

          var shortcutsModal = document.getElementById('shortcutsModal');
          var themeModal = document.getElementById('themeModal');
          var confirmDialog = document.getElementById('confirmDialog');
          var fileDialog = document.getElementById('fileDialog');

          // when shortcuts modal is open, only escape closes it
          if (shortcutsModal && shortcutsModal.classList.contains('show')) {
              if (e.key === 'Escape') closeShortcutsModal();
              return;
          }

          var aboutModal = document.getElementById('aboutModal');
          if (aboutModal && aboutModal.classList.contains('show')) {
              if (e.key === 'Escape') closeAboutModal();
              return;
          }

          var browseModal = document.getElementById('browseModal');
          if (browseModal && browseModal.classList.contains('show')) {
              if (e.key === 'Escape') closeBrowseModal();
              return;
          }

          var workspaceModal = document.getElementById('workspaceModal');
          if (workspaceModal && workspaceModal.classList.contains('show')) {
              if (e.key === 'Escape') closeWorkspaceModal();
              return;
          }

          // defer to existing escape handlers for other modals
          var alertDialog = document.getElementById('alertDialog');
          if (alertDialog && alertDialog.classList.contains('show')) return;
          if (themeModal && themeModal.classList.contains('show')) return;
          if (confirmDialog && confirmDialog.classList.contains('show')) return;
          if (fileDialog && fileDialog.classList.contains('show')) return;

          switch (e.key) {
              case '/':
                  e.preventDefault();
                  openShortcutsModal();
                  break;
              case 'e':
                  if (currentFile && !{{ editor_mode|default(false)|tojson }}) {
                      window.location.href = '/edit/' + currentFile;
                  }
                  break;
              case 'n':
                  if ({{ show_navigation|default(false)|tojson }}) {
                      window.location.href = '/new';
                  }
                  break;
              case 'd':
                  if (currentFile && !{{ editor_mode|default(false)|tojson }}) {
                      deleteFile(currentFile);
                  }
                  break;
              case 'k':
                  if ({{ show_navigation|default(false)|tojson }}) {
                      toggleSidebar();
                  }
                  break;
              case 'h':
              case 'r':
                  if (typeof toggleHistory === 'function') {
                      toggleHistory();
                  }
                  break;
              case 's':
                  if ({{ show_navigation|default(false)|tojson }}) {
                      e.preventDefault();
                      var searchInput = document.getElementById('sidebarSearch');
                      if (searchInput) searchInput.focus();
                  }
                  break;
              case 'w':
                  if (showNavigation && currentFile) {
                      TabManager.removeTab(currentFile);
                  }
                  break;
              case '?':
                  e.preventDefault();
                  openAboutModal();
                  break;
              case 'o':
                  if (_isDaemonMode) {
                      e.preventDefault();
                      openWorkspaceModal();
                  }
                  break;
              case 'W':
                  if (e.shiftKey) {
                      e.preventDefault();
                      cycleContentWidth();
                  }
                  break;
          }
      });

      // close shortcuts modal on click outside
      document.getElementById('shortcutsModal').addEventListener('click', function(e) {
          if (e.target === this) closeShortcutsModal();
      });

      // find-in-page
      (function() {
          var bar = document.getElementById('findBar');
          var input = document.getElementById('findInput');
          var countEl = document.getElementById('findCount');
          var prevBtn = document.getElementById('findPrev');
          var nextBtn = document.getElementById('findNext');
          var closeBtn = document.getElementById('findClose');
          if (!bar || !input) return;

          var matches = [];
          var activeIdx = -1;
          var lastQuery = '';

          function findRoot() {
              return document.getElementById('content')
                  || document.getElementById('editorPreview');
          }

          function clearMarks() {
              var root = findRoot();
              if (!root) return;
              var hits = root.querySelectorAll('mark.find-hit');
              hits.forEach(function(m) {
                  var t = document.createTextNode(m.textContent);
                  m.parentNode.replaceChild(t, m);
              });
              if (hits.length) root.normalize();
              matches = [];
              activeIdx = -1;
          }

          function wrapMatches(query) {
              var root = findRoot();
              if (!root || !query) return [];
              var lc = query.toLowerCase();
              var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
                  acceptNode: function(n) {
                      if (!n.nodeValue || !n.nodeValue.length) return NodeFilter.FILTER_REJECT;
                      var p = n.parentNode;
                      while (p && p !== root) {
                          var t = p.nodeName;
                          if (t === 'SCRIPT' || t === 'STYLE' || t === 'MARK') return NodeFilter.FILTER_REJECT;
                          p = p.parentNode;
                      }
                      return NodeFilter.FILTER_ACCEPT;
                  }
              });
              var nodes = [];
              var n;
              while ((n = walker.nextNode())) nodes.push(n);
              var hits = [];
              nodes.forEach(function(node) {
                  var txt = node.nodeValue;
                  var lower = txt.toLowerCase();
                  if (lower.indexOf(lc) === -1) return;
                  var frag = document.createDocumentFragment();
                  var last = 0;
                  var pos = 0;
                  while ((pos = lower.indexOf(lc, last)) !== -1) {
                      if (pos > last) frag.appendChild(document.createTextNode(txt.slice(last, pos)));
                      var m = document.createElement('mark');
                      m.className = 'find-hit';
                      m.textContent = txt.slice(pos, pos + lc.length);
                      frag.appendChild(m);
                      hits.push(m);
                      last = pos + lc.length;
                  }
                  if (last < txt.length) frag.appendChild(document.createTextNode(txt.slice(last)));
                  node.parentNode.replaceChild(frag, node);
              });
              return hits;
          }

          function updateCount() {
              countEl.textContent = matches.length
                  ? (activeIdx + 1) + ' / ' + matches.length
                  : '0 / 0';
          }

          function setActive(idx) {
              if (!matches.length) { activeIdx = -1; updateCount(); return; }
              if (activeIdx >= 0 && matches[activeIdx]) matches[activeIdx].classList.remove('active');
              activeIdx = ((idx % matches.length) + matches.length) % matches.length;
              var el = matches[activeIdx];
              el.classList.add('active');
              el.scrollIntoView({ block: 'center', behavior: 'smooth' });
              updateCount();
          }

          function runSearch(query) {
              clearMarks();
              lastQuery = query;
              if (!query) { updateCount(); return; }
              matches = wrapMatches(query);
              if (matches.length) setActive(0); else updateCount();
          }

          window.openFindBar = function() {
              bar.classList.add('show');
              input.focus();
              input.select();
              if (input.value && input.value !== lastQuery) runSearch(input.value);
          };

          window.closeFindBar = function() {
              bar.classList.remove('show');
              clearMarks();
              lastQuery = '';
              input.blur();
              updateCount();
          };

          var debounce;
          input.addEventListener('input', function() {
              clearTimeout(debounce);
              var q = input.value;
              debounce = setTimeout(function() { runSearch(q); }, 80);
          });

          input.addEventListener('keydown', function(e) {
              if (e.key === 'Enter') {
                  e.preventDefault();
                  if (!matches.length && input.value) { runSearch(input.value); return; }
                  setActive(activeIdx + (e.shiftKey ? -1 : 1));
              } else if (e.key === 'Escape') {
                  e.preventDefault();
                  closeFindBar();
              }
          });

          nextBtn.addEventListener('click', function() { setActive(activeIdx + 1); });
          prevBtn.addEventListener('click', function() { setActive(activeIdx - 1); });
          closeBtn.addEventListener('click', closeFindBar);

          document.addEventListener('keydown', function(e) {
              if ((e.ctrlKey || e.metaKey) && (e.key === 'f' || e.key === 'F')) {
                  e.preventDefault();
                  openFindBar();
              } else if (e.key === 'F3') {
                  e.preventDefault();
                  if (!bar.classList.contains('show')) openFindBar();
                  else setActive(activeIdx + (e.shiftKey ? -1 : 1));
              }
          });
      })();

      // close about modal on click outside
      document.getElementById('aboutModal').addEventListener('click', function(e) {
          if (e.target === this) closeAboutModal();
      });

      // workspace modal: close on click outside, enter to submit
      var wsModal = document.getElementById('workspaceModal');
      if (wsModal) {
          wsModal.addEventListener('click', function(e) {
              if (e.target === this) closeWorkspaceModal();
          });
          var wsInput = document.getElementById('workspacePathInput');
          if (wsInput) {
              wsInput.addEventListener('keydown', function(e) {
                  if (e.key === 'Enter') {
                      var val = wsInput.value.trim();
                      if (val) switchWorkspace(val);
                  }
                  if (e.key === 'Escape') {
                      closeWorkspaceModal();
                  }
              });
          }
      }
    </script>
  </body>
</html>
