${escapeHtml(section.title)}
${escapeHtml(section.source_anchor)} owns ${Number(section.link_count || 0)} links until ${escapeHtml(section.owns_until || "next")}${escapeHtml(section.excerpt || "")}
${section.layout ? `(() => { const $ = (sel, root = document) => root.querySelector(sel); const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel)); const toast = $("#miniToast"); const showToast = (message) => { if (!toast) return; toast.textContent = message; toast.classList.add("show"); window.clearTimeout(showToast.t); showToast.t = window.setTimeout(() => toast.classList.remove("show"), 2400); }; const bottomNav = $("[data-bottom-nav]"); const syncNav = () => bottomNav?.classList.toggle("visible", window.scrollY > 8); window.addEventListener("scroll", syncNav, { passive: true }); syncNav(); $$("[data-section-jump], .bottom-icons a, .top-links a, .scroll-cue, .chapter-link").forEach((link) => { link.addEventListener("click", () => { const label = link.getAttribute("data-title") || link.textContent.trim() || "section"; showToast(`Navigating to ${label}`); }); }); const themeToggle = $("[data-theme-toggle]"); const storedTheme = localStorage.getItem("landscaper-theme"); if (storedTheme === "night") { document.documentElement.dataset.theme = "night"; if (themeToggle) { themeToggle.textContent = "Night"; themeToggle.setAttribute("aria-pressed", "true"); } } themeToggle?.addEventListener("click", () => { const next = document.documentElement.dataset.theme === "night" ? "day" : "night"; if (next === "night") document.documentElement.dataset.theme = "night"; else delete document.documentElement.dataset.theme; themeToggle.textContent = next === "night" ? "Night" : "Day"; themeToggle.setAttribute("aria-pressed", String(next === "night")); localStorage.setItem("landscaper-theme", next === "night" ? "night" : "day"); showToast(`${next === "night" ? "Night" : "Day"} mode enabled`); }); const grid = $("[data-section-grid]"); $$(".mode-switch button").forEach((button) => { button.addEventListener("click", () => { $$(".mode-switch button").forEach((b) => b.classList.remove("active")); button.classList.add("active"); grid?.classList.remove("blocks", "files", "text"); grid?.classList.add(button.dataset.mode); showToast(`${button.dataset.mode} mode`); }); }); const pdfLibrary = $("[data-pdf-library]"); $$("[data-pdf-view]").forEach((button) => { button.addEventListener("click", () => { $$("[data-pdf-view]").forEach((b) => b.classList.remove("active")); button.classList.add("active"); if (pdfLibrary) pdfLibrary.dataset.pdfMode = button.dataset.pdfView || "intro"; showToast(`PDF view: ${button.textContent.trim()}`); }); }); const referencePage = $("[data-reference-page]"); const referenceModeButtons = $$("button[data-reference-mode]"); const referencePanels = $$("[data-mode-panel]"); const filter = $("#linkFilter"); const filterDimToggle = $("#filterDimToggle"); const filterStatus = $("#filterStatus"); const filterModeLabel = $("[data-filter-mode-label]"); try { const savedFilterMode = localStorage.getItem("curated-filter-mode"); if (filterDimToggle && savedFilterMode === "hide") filterDimToggle.checked = false; } catch {} function setReferenceMode(mode, options = {}) { if (!referencePage || !mode) return; referencePage.dataset.referenceMode = mode; referenceModeButtons.forEach((button) => { const active = button.dataset.referenceMode === mode; button.classList.toggle("active", active); button.setAttribute("aria-selected", String(active)); }); referencePanels.forEach((panel) => { const active = panel.dataset.modePanel === mode; panel.hidden = !active; panel.classList.toggle("is-active", active); }); if (!options.quiet) showToast(mode === "pdfs" ? "PDF block ready" : (mode === "chapters" ? "Chapter groups ready" : "Icon boxes ready")); scheduleVisibleHighlights(); } function panelForMode(mode) { return referencePanels.find((panel) => panel.dataset.modePanel === mode) || null; } referenceModeButtons.forEach((button) => { button.addEventListener("click", () => { const mode = button.dataset.referenceMode; setReferenceMode(mode, { quiet: true }); const panel = panelForMode(mode); if (panel?.id) window.setTimeout(() => markTarget(panel.id, { scroll: false, switchMode: false }), 30); }); }); $$("[data-reference-mode-jump]").forEach((link) => { link.addEventListener("click", () => setReferenceMode(link.dataset.referenceModeJump, { quiet: true })); }); document.addEventListener("click", (event) => { const control = event.target.closest("[data-highlight-target]"); if (!control) return; const targetId = control.dataset.highlightTarget; if (!targetId) return; const href = control.getAttribute("href") || ""; const external = control.matches("a[href]") && href && !href.startsWith("#"); if (!external) event.preventDefault(); markTarget(targetId, { scroll: !external, switchMode: true }); }); document.addEventListener("click", (event) => { const link = event.target.closest("a[href^=\"#\"]"); if (!link || link.matches("[data-highlight-target]") || link.matches("[data-map-target]")) return; const raw = link.getAttribute("href") || ""; if (raw.length <= 1) return; const targetId = decodeURIComponent(raw.slice(1)); if (!document.getElementById(targetId)) return; event.preventDefault(); if (link.dataset.referenceModeJump) setReferenceMode(link.dataset.referenceModeJump, { quiet: true }); window.setTimeout(() => markTarget(targetId, { scroll: true, switchMode: true }), 30); }); function previewOwner(control, persist = false) { const targetId = control?.dataset?.ownerTarget; if (!targetId) return; $$(".is-owner-preview").forEach((el) => el.classList.remove("is-owner-preview")); $$(".is-owner-link").forEach((el) => el.classList.remove("is-owner-link")); control.classList.add("is-owner-link"); markRelatedControls(targetId, true); const target = document.getElementById(targetId); const hiddenPanel = target?.closest("[data-mode-panel]")?.hidden; if (target && !hiddenPanel) target.classList.add("is-owner-preview"); if (persist && target && !hiddenPanel) markTarget(targetId, { scroll: false, switchMode: false, toast: false }); } document.addEventListener("mouseover", (event) => { const control = event.target.closest("[data-owner-target]"); if (control) previewOwner(control, false); }); document.addEventListener("focusin", (event) => { const control = event.target.closest("[data-owner-target]"); if (control) previewOwner(control, false); }); document.addEventListener("click", (event) => { const control = event.target.closest("[data-owner-target]"); if (control) previewOwner(control, true); }); const applyFilter = () => { const anchorState = captureScrollAnchor(); const q = filter?.value.trim().toLowerCase() || ""; const dimOut = filterDimToggle ? filterDimToggle.checked : true; let total = 0; let hits = 0; const setFiltered = (el, hit) => { const miss = Boolean(q && !hit); el.classList.toggle("is-filter-muted", miss && dimOut); el.classList.toggle("is-hidden", miss && !dimOut); el.classList.toggle("is-filter-hit", Boolean(q && hit)); }; $$("[data-pdf-card]").forEach((card) => { total += 1; const hit = !q || (card.dataset.search || "").includes(q); if (hit) hits += 1; setFiltered(card, hit); }); $$("[data-section-card]").forEach((card) => { const sectionMatch = !q || (card.dataset.title || "").includes(q) || (card.dataset.chapter || "").toLowerCase().includes(q); let any = sectionMatch; $$("[data-link-row]", card).forEach((row) => { total += 1; const hit = !q || (row.dataset.search || "").includes(q) || sectionMatch; if (hit) hits += 1; if (hit) any = true; setFiltered(row, hit); }); setFiltered(card, any); }); if (filterModeLabel) filterModeLabel.textContent = dimOut ? "dim" : "hide"; try { localStorage.setItem("curated-filter-mode", dimOut ? "dim" : "hide"); } catch {} if (filterStatus) filterStatus.textContent = q ? `${hits}/${total} · ${dimOut ? "dim" : "hide"}` : `All · ${dimOut ? "dim" : "hide"}`; restoreScrollAnchor(anchorState); scheduleVisibleHighlights(); }; filter?.addEventListener("input", applyFilter); filterDimToggle?.addEventListener("change", applyFilter); applyFilter(); const mapBtn = $("[data-open-map]"); mapBtn?.addEventListener("click", () => { const modalElement = $("#mapModal"); if (!modalElement || !window.bootstrap) return; const modal = new bootstrap.Modal(modalElement); modal.show(); }); $$("[data-map-target]").forEach((link) => { link.addEventListener("click", (event) => { event.preventDefault(); const targetId = link.getAttribute("data-map-target"); const modalEl = $("#mapModal"); if (modalEl && window.bootstrap) bootstrap.Modal.getInstance(modalEl)?.hide(); window.setTimeout(() => openSection(targetId), 170); }); }); const scanBtn = $("#scanLinks"); const auditStatus = $("#auditStatus"); const auditResults = $("#auditResults"); scanBtn?.addEventListener("click", async () => { scanBtn.disabled = true; auditStatus.textContent = "Scanning live source…"; auditResults.innerHTML = ""; try { const response = await fetch("api/scan_links.php", { headers: { "Accept": "application/json" }}); if (!response.ok) throw new Error("Scanner returned " + response.status); const payload = await response.json(); const known = new Set(JSON.parse(auditResults.dataset.known || "[]").map((u) => normalize(u))); const rows = (payload.links || []).map((link) => ({ ...link, known: known.has(normalize(link.href)) })); const newCount = rows.filter((row) => !row.known).length; const ignored = Number(payload.ignored_count || 0); const suppressed = Number(payload.suppressed_count || 0); auditStatus.textContent = `${rows.length} visible source links found · ${newCount} not curated · ${ignored} noise/asset links ignored · ${suppressed} deliberately removed · scanned ${payload.scanned_at || "now"}.`; auditResults.innerHTML = rows.map(renderAuditRow).join(""); showToast("Live scan complete"); } catch (error) { auditStatus.textContent = "Scan failed. The curated structure remains available."; showToast("Scanner unavailable"); } finally { scanBtn.disabled = false; } }); const structureButtons = [$("#loadStructure"), $("#loadStructureBottom")].filter(Boolean); const structureStatus = $("#sourceStructureStatus"); const structureTarget = $("#sourceStructure"); structureButtons.forEach((button) => { button.addEventListener("click", () => loadSourceStructure()); }); async function loadSourceStructure() { if (!structureTarget || !structureStatus) return; structureButtons.forEach((button) => { button.disabled = true; }); structureStatus.textContent = "Reading live source icon ownership…"; structureTarget.innerHTML = ""; try { const response = await fetch("api/scan_structure.php", { headers: { "Accept": "application/json" }}); if (!response.ok) throw new Error("Structure scanner returned " + response.status); const payload = await response.json(); if (!payload.success) throw new Error(payload.error || "Structure scanner failed"); structureStatus.textContent = `${payload.section_count} source owner icons · ${payload.link_count} grouped branch links · ${Number(payload.utility_count || 0)} separated utility links · scanned ${payload.scanned_at}.`; structureTarget.innerHTML = `
${escapeHtml(section.excerpt || "")}
${section.layout ? `