PageSourceSearch

https://andersaamodt.com/static/page-head.js?v=1376469157

js andersaamodt.com collected 2026-10-08 10:31:46 UTC 101,279 bytes, 2,680 lines download raw bytes

1(function () {
2  var ROUTE_REFRESH_PARAM = '__route_refresh';
3  var ROUTE_REPAIR_PARAM = '__route_repair';
4  var SITE_TITLE_CACHE_KEY = 'wizardry_blog_site_title_v1';
5  var APPEND_SITE_TITLE_CACHE_KEY = 'wizardry_blog_append_site_title_to_page_title_v1';
6  var routeFailureTimer = 0;
7  var pageInitialContentReady = false;
8  var cachedBasePageTitle = '';
9  var nostrPublishDialogPromise = null;
10
11  function normalizeSiteTitle(value) {
12    var text = String(value || '').replace(/\s+/g, ' ').trim();
13    return text || 'Site';
14  }
15
16  function normalizeAppendSiteTitleEnabled(value) {
17    if (value === true || value === 1 || value === '1') {
18      return true;
19    }
20    if (typeof value === 'string') {
21      var text = value.trim().toLowerCase();
22      return text === 'true' || text === 'yes' || text === 'on';
23    }
24    return false;
25  }
26
27  function readCachedSiteTitle() {
28    try {
29      return normalizeSiteTitle(localStorage.getItem(SITE_TITLE_CACHE_KEY) || '');
30    } catch (_err) {
31      return 'Site';
32    }
33  }
34
35  function readCachedAppendSiteTitleEnabled() {
36    try {
37      return normalizeAppendSiteTitleEnabled(localStorage.getItem(APPEND_SITE_TITLE_CACHE_KEY) || '');
38    } catch (_err) {
39      return false;
40    }
41  }
42
43  function titleConfig(overrides) {
44    var opts = overrides && typeof overrides === 'object' ? overrides : {};
45    var siteTitle = Object.prototype.hasOwnProperty.call(opts, 'siteTitle')
46      ? normalizeSiteTitle(opts.siteTitle)
47      : readCachedSiteTitle();
48    var appendSiteTitle = Object.prototype.hasOwnProperty.call(opts, 'appendSiteTitle')
49      ? normalizeAppendSiteTitleEnabled(opts.appendSiteTitle)
50      : readCachedAppendSiteTitleEnabled();
51    return { siteTitle: siteTitle, appendSiteTitle: appendSiteTitle };
52  }
53
54  function renderPageTitle(baseTitle, config) {
55    var base = String(baseTitle || '').trim();
56    var siteTitle = normalizeSiteTitle(config && config.siteTitle);
57    if (!base || !config || config.appendSiteTitle !== true || !siteTitle) {
58      return base;
59    }
60    if (base.toLowerCase() === siteTitle.toLowerCase()) {
61      return base;
62    }
63    var suffix = ' - ' + siteTitle;
64    return base.slice(-suffix.length) === suffix ? base : base + suffix;
65  }
66
67  function applyPageTitle(baseTitle, overrides) {
68    if (typeof baseTitle !== 'undefined' && baseTitle !== null) {
69      cachedBasePageTitle = String(baseTitle).trim();
70    } else if (!cachedBasePageTitle) {
71      cachedBasePageTitle = String(document.title || '').trim();
72    }
73    var nextTitle = renderPageTitle(cachedBasePageTitle, titleConfig(overrides));
74    if (document.title !== nextTitle) {
75      document.title = nextTitle;
76    }
77    return nextTitle;
78  }
79
80  function removeLegacyTitleBlock(rootNode) {
81    var root = rootNode || null;
82    if (!root) {
83      return;
84    }
85    var prev = root.previousElementSibling;
86    if (!prev || prev.tagName !== 'HEADER') {
87      return;
88    }
89    if (!prev.querySelector || !prev.querySelector('.title')) {
90      return;
91    }
92    if (prev.parentNode) {
93      prev.parentNode.removeChild(prev);
94    }
95  }
96
97  function ensureReadOnlyTitleShell(titleNode) {
98    if (!titleNode) {
99      return { text: null, actions: null };
100    }
101    var existingActions = titleNode.querySelector('.list-page-title-actions');
102    var actionsId = String(existingActions && existingActions.id || '').trim();
103    var actionsClassName = String(existingActions && existingActions.className || 'list-page-title-actions').trim() || 'list-page-title-actions';
104    var text = titleNode.querySelector('.list-page-title-text');
105    var actions = actionsId ? document.getElementById(actionsId) : existingActions;
106    if (!text) {
107      text = document.createElement('span');
108      text.className = 'list-page-title-text';
109      var child = titleNode.firstChild;
110      while (child) {
111        var next = child.nextSibling;
112        if (child !== actions) {
113          text.appendChild(child);
114        }
115        child = next;
116      }
117      if (actions && actions.parentNode === titleNode) {
118        titleNode.insertBefore(text, actions);
119      } else {
120        titleNode.appendChild(text);
121      }
122    }
123    if (!actions) {
124      actions = document.createElement('span');
125      if (actionsId) {
126        actions.id = actionsId;
127      }
128      actions.className = actionsClassName;
129      titleNode.appendChild(actions);
130    } else {
131      if (actionsId && actions.id !== actionsId) {
132        actions.id = actionsId;
133      }
134      if (actions.className !== actionsClassName) {
135        actions.className = actionsClassName;
136      }
137      if (actions.parentNode !== titleNode) {
138        titleNode.appendChild(actions);
139      }
140    }
141    return { text: text, actions: actions };
142  }
143
144  function titleActionsHostHtml(titleNode) {
145    var existingActions = titleNode && titleNode.querySelector
146      ? titleNode.querySelector('.list-page-title-actions')
147      : null;
148    var actionsId = String(existingActions && existingActions.id || '').trim();
149    var actionsClassName = String(existingActions && existingActions.className || 'list-page-title-actions').trim() || 'list-page-title-actions';
150    return '<span' +
151      (actionsId ? ' id="' + escapeHtml(actionsId) + '"' : '') +
152      ' class="' + escapeHtml(actionsClassName) + '"></span>';
153  }
154
155  function ensureReadOnlyDescriptionShell(descriptionNode) {
156    if (!descriptionNode) {
157      return null;
158    }
159    var text = descriptionNode.querySelector('.list-page-description-text');
160    if (!text) {
161      text = document.createElement('span');
162      text.className = 'list-page-description-text';
163      while (descriptionNode.firstChild) {
164        text.appendChild(descriptionNode.firstChild);
165      }
166      descriptionNode.appendChild(text);
167    }
168    return text;
169  }
170
171  function renderReadOnlyTitleShell(titleNode, textValue) {
172    var shell = ensureReadOnlyTitleShell(titleNode);
173    if (shell && shell.text) {
174      var nextText = String(textValue || '');
175      if (shell.text.textContent !== nextText) {
176        shell.text.textContent = nextText;
177      }
178    }
179    return shell;
180  }
181
182  function renderReadOnlyDescriptionShell(descriptionNode, options) {
183    var opts = options && typeof options === 'object' ? options : {};
184    var text = ensureReadOnlyDescriptionShell(descriptionNode);
185    if (!text) {
186      return null;
187    }
188    if (Object.prototype.hasOwnProperty.call(opts, 'html')) {
189      var nextHtml = String(opts.html || '');
190      if (text.innerHTML !== nextHtml) {
191        text.innerHTML = nextHtml;
192      }
193    } else if (Object.prototype.hasOwnProperty.call(opts, 'text')) {
194      var nextText = String(opts.text || '');
195      if (text.textContent !== nextText) {
196        text.textContent = nextText;
197      }
198    }
199    if (descriptionNode && Object.prototype.hasOwnProperty.call(opts, 'hidden')) {
200      var nextHidden = !!opts.hidden;
201      if (descriptionNode.hidden !== nextHidden) {
202        descriptionNode.hidden = nextHidden;
203      }
204    }
205    return text;
206  }
207
208  function htmlAttr(name, value) {
209    var attrName = String(name || '').trim();
210    if (!attrName) {
211      return '';
212    }
213    return ' ' + attrName + '="' + escapeHtml(value) + '"';
214  }
215
216  function renderEditablePageHeadTitle(targetNode, options) {
217    if (!targetNode) {
218      return false;
219    }
220    var opts = options && typeof options === 'object' ? options : {};
221    var activeField = String(opts.activeField || '').trim().toLowerCase();
222    var value = String(opts.value || opts.fallbackText || '');
223    var actionsHtml = titleActionsHostHtml(targetNode);
224    var editLabel = String(opts.editLabel || 'Edit...');
225    var inputId = String(opts.inputId || '').trim();
226    var inputAttrName = String(opts.inputAttrName || '').trim();
227    var editAttrName = String(opts.editAttrName || '').trim();
228    var saveAttrName = String(opts.saveAttrName || '').trim();
229    var showSaveButton = opts.showSaveButton === true;
230    if (activeField === 'title') {
231      targetNode.innerHTML = '<span class="list-page-title-edit-wrap"><input id="' + escapeHtml(inputId) + '" class="list-head-inline-input" type="text" value="' + escapeHtml(value) + '"' + htmlAttr(inputAttrName, 'title') + '></span>' +
232        (showSaveButton ? ' <button type="button" class="list-inline-edit-link"' + htmlAttr(saveAttrName, 'title') + '>Save</button>' : '') +
233        actionsHtml;
234      return true;
235    }
236    targetNode.innerHTML = '<span class="list-page-title-text">' + escapeHtml(value) + '</span>' +
237      (opts.editMode ? ' <button type="button" class="list-inline-edit-link"' + htmlAttr(editAttrName, 'title') + '>' + escapeHtml(editLabel) + '</button>' : '') +
238      actionsHtml;
239    return true;
240  }
241
242  function renderEditablePageHeadDescription(targetNode, options) {
243    if (!targetNode) {
244      return false;
245    }
246    var opts = options && typeof options === 'object' ? options : {};
247    var activeField = String(opts.activeField || '').trim().toLowerCase();
248    var text = String(opts.text || '');
249    var textHtml = String(opts.textHtml || '');
250    var editLabel = String(opts.editLabel || 'Edit...');
251    var emptyHtml = String(opts.emptyHtml || '<span class="list-page-description-empty">No description.</span>');
252    var inputId = String(opts.inputId || '').trim();
253    var inputAttrName = String(opts.inputAttrName || '').trim();
254    var editAttrName = String(opts.editAttrName || '').trim();
255    var saveAttrName = String(opts.saveAttrName || '').trim();
256    var editingExtraHtml = String(opts.editingExtraHtml || '');
257    if (opts.suppressEmpty === true) {
258      targetNode.hidden = true;
259      targetNode.innerHTML = '';
260      return true;
261    }
262    targetNode.hidden = false;
263    if (activeField === 'description') {
264      targetNode.innerHTML = '<span class="list-page-description-edit-wrap"><textarea id="' + escapeHtml(inputId) + '" class="list-head-description-input" rows="4"' + htmlAttr(inputAttrName, 'description') + '>' + escapeHtml(text) + '</textarea></span> <button type="button" class="list-inline-edit-link"' + htmlAttr(saveAttrName, 'description') + '>Save</button>' + editingExtraHtml;
265      return true;
266    }
267    if (opts.editMode) {
268      targetNode.innerHTML = (text.trim()
269        ? '<span class="list-page-description-text">' + textHtml + '</span>'
270        : emptyHtml) +
271        ' <button type="button" class="list-inline-edit-link"' + htmlAttr(editAttrName, 'description') + '>' + escapeHtml(editLabel) + '</button>';
272      return true;
273    }
274    if (text.trim()) {
275      targetNode.innerHTML = '<span class="list-page-description-text">' + textHtml + '</span>';
276      return true;
277    }
278    if (opts.hideWhenEmpty === true) {
279      targetNode.hidden = true;
280      targetNode.innerHTML = '';
281      return true;
282    }
283    targetNode.innerHTML = emptyHtml;
284    return true;
285  }
286
287  function managedPageHeadDescriptionState(options) {
288    var opts = options && typeof options === 'object' ? options : {};
289    var format = String(opts.format || '').trim().toLowerCase() === 'text' ? 'text' : 'html';
290    var text = String(opts.text || '');
291    var hidden = Object.prototype.hasOwnProperty.call(opts, 'hidden')
292      ? !!opts.hidden
293      : (!text.trim() && opts.hideWhenEmpty === true);
294    if (format === 'text') {
295      return {
296        descriptionFallback: {
297          text: text,
298          hidden: hidden
299        }
300      };
301    }
302    return {
303      descriptionFallback: {
304        html: String(opts.html || ''),
305        hidden: hidden
306      }
307    };
308  }
309
310  function managedPageHeadTitleState(options) {
311    var opts = options && typeof options === 'object' ? options : {};
312    var renderState = opts.renderState && typeof opts.renderState === 'object' ? opts.renderState : null;
313    var payload = opts.payload && typeof opts.payload === 'object' ? opts.payload : null;
314    var fallbackTitleText = String(opts.fallbackTitleText || '').trim() || 'Untitled';
315    var explicitTitleText = Object.prototype.hasOwnProperty.call(opts, 'titleText')
316      ? String(opts.titleText || '').trim()
317      : '';
318    var renderTitle = String(renderState && renderState.title || '').trim();
319    var titleText = explicitTitleText || renderTitle || fallbackTitleText;
320    var pageTitle = null;
321    if (Object.prototype.hasOwnProperty.call(opts, 'pageTitle')) {
322      pageTitle = opts.pageTitle === null || typeof opts.pageTitle === 'undefined'
323        ? null
324        : String(opts.pageTitle || '').trim();
325    } else if (renderTitle) {
326      pageTitle = renderTitle;
327    } else if (opts.useFallbackForPageTitle === true) {
328      pageTitle = titleText;
329    }
330    var syncStatus = payload && Object.prototype.hasOwnProperty.call(payload, 'sync_status')
331      ? payload.sync_status
332      : null;
333    var syncMessageVariant = String(opts.syncMessageVariant || '').trim();
334    return {
335      pageTitle: pageTitle,
336      titleText: titleText,
337      syncStatus: syncStatus,
338      titleSyncOptions: syncMessageVariant ? { messageVariant: syncMessageVariant } : null
339    };
340  }
341
342  function managedPageHeadFieldState(options) {
343    var opts = options && typeof options === 'object' ? options : {};
344    var renderState = opts.renderState && typeof opts.renderState === 'object' ? opts.renderState : null;
345    var titleState = managedPageHeadTitleState({
346      renderState: renderState,
347      payload: opts.payload,
348      fallbackTitleText: opts.fallbackTitleText,
349      syncMessageVariant: opts.syncMessageVariant
350    });
351    var titleText = titleState.titleText;
352    var activeField = String(opts.activeField || '').trim().toLowerCase();
353    var isAdmin = opts.isAdmin === true;
354    var titleInputId = String(opts.titleInputId || '').trim();
355    var descriptionInputId = String(opts.descriptionInputId || '').trim();
356    var inputAttrName = String(opts.inputAttrName || '').trim();
357    var editAttrName = String(opts.editAttrName || '').trim();
358    var saveAttrName = String(opts.saveAttrName || '').trim();
359    var descriptionText = String(opts.descriptionText || '');
360    var descriptionHtml = String(opts.descriptionHtml || '');
361    var hasMainContent = opts.hasMainContent === true;
362    var focusOptions = null;
363    if (isAdmin && activeField && opts.enableFocus === true) {
364      focusOptions = {
365        activeField: activeField,
366        titleInputId: titleInputId,
367        descriptionInputId: descriptionInputId
368      };
369      if (Object.prototype.hasOwnProperty.call(opts, 'focusSelectOnFocus')) {
370        focusOptions.selectOnFocus = opts.focusSelectOnFocus;
371      }
372      if (typeof opts.focusAfter === 'function') {
373        focusOptions.afterFocus = opts.focusAfter;
374      }
375    }
376    return {
377      pageTitle: titleState.pageTitle,
378      titleText: titleState.titleText,
379      syncStatus: titleState.syncStatus,
380      titleSyncOptions: titleState.titleSyncOptions,
381      titleEditOptions: {
382        activeField: activeField,
383        editMode: opts.editMode === true,
384        value: titleText,
385        fallbackText: String(opts.fallbackTitleText || '').trim() || 'Untitled',
386        inputId: titleInputId,
387        inputAttrName: inputAttrName,
388        editAttrName: editAttrName,
389        saveAttrName: saveAttrName,
390        showSaveButton: opts.showTitleSaveButton === true
391      },
392      descriptionEditOptions: {
393        activeField: activeField,
394        editMode: opts.editMode === true,
395        text: descriptionText,
396        textHtml: descriptionHtml,
397        suppressEmpty: !descriptionText.trim() && !hasMainContent && activeField !== 'description',
398        hideWhenEmpty: opts.descriptionHideWhenEmpty === true,
399        inputId: descriptionInputId,
400        inputAttrName: inputAttrName,
401        editAttrName: editAttrName,
402        saveAttrName: saveAttrName,
403        editingExtraHtml: String(opts.descriptionEditingExtraHtml || '')
404      },
405      focusOptions: focusOptions
406    };
407  }
408
409  function renderManagedPageHeadForPage(options) {
410    var opts = options && typeof options === 'object' ? options : {};
411    var payload = opts.payload && typeof opts.payload === 'object' ? opts.payload : null;
412    var titleNode = opts.titleNode || null;
413    var descriptionNode = opts.descriptionNode || null;
414    var usingFieldState = opts.fieldStateOptions && typeof opts.fieldStateOptions === 'object';
415    var headStateOptions = usingFieldState
416      ? Object.assign({}, opts.fieldStateOptions)
417      : Object.assign({}, opts.titleStateOptions && typeof opts.titleStateOptions === 'object'
418          ? opts.titleStateOptions
419          : {});
420    if (!Object.prototype.hasOwnProperty.call(headStateOptions, 'payload')) {
421      headStateOptions.payload = payload;
422    }
423    var headState = usingFieldState
424      ? managedPageHeadFieldState(headStateOptions)
425      : managedPageHeadTitleState(headStateOptions);
426    var navbarTitleOptions = null;
427    if (opts.navbarTitleOptions && typeof opts.navbarTitleOptions === 'object') {
428      navbarTitleOptions = managedNavbarTitlePageOptions(Object.assign({}, opts.navbarTitleOptions, {
429        payload: Object.prototype.hasOwnProperty.call(opts.navbarTitleOptions, 'payload')
430          ? opts.navbarTitleOptions.payload
431          : payload,
432        titleNode: Object.prototype.hasOwnProperty.call(opts.navbarTitleOptions, 'titleNode')
433          ? opts.navbarTitleOptions.titleNode
434          : titleNode
435      }));
436    }
437    var renderOptions = {
438      isAdmin: opts.isAdmin === true,
439      pageTitle: headState.pageTitle,
440      titleNode: titleNode,
441      titleText: headState.titleText,
442      titleSyncOptions: headState.titleSyncOptions,
443      syncStatus: headState.syncStatus,
444      navbarTitleOptions: navbarTitleOptions
445    };
446    if (descriptionNode && opts.descriptionStateOptions && typeof opts.descriptionStateOptions === 'object') {
447      renderOptions.descriptionNode = descriptionNode;
448      renderOptions.descriptionPayload = payload;
449      renderOptions.descriptionFallback = managedPageHeadDescriptionState(opts.descriptionStateOptions).descriptionFallback;
450      if (Object.prototype.hasOwnProperty.call(opts, 'allowPrerenderDescription')) {
451        renderOptions.allowPrerenderDescription = opts.allowPrerenderDescription;
452      }
453    }
454    if (usingFieldState) {
455      renderOptions.titleEditOptions = headState.titleEditOptions;
456      renderOptions.descriptionEditOptions = headState.descriptionEditOptions;
457      renderOptions.focusOptions = headState.focusOptions;
458    }
459    renderManagedPageHead(renderOptions);
460    return {
461      headState: headState,
462      navbarTitleOptions: navbarTitleOptions,
463      renderOptions: renderOptions
464    };
465  }
466
467  function renderManagedPageHead(options) {
468    var opts = options && typeof options === 'object' ? options : {};
469    var admin = opts.isAdmin === true;
470    if (admin) {
471      if (opts.titleNode) {
472        renderEditablePageHeadTitle(opts.titleNode, opts.titleEditOptions);
473      }
474      if (opts.descriptionNode) {
475        renderEditablePageHeadDescription(opts.descriptionNode, opts.descriptionEditOptions);
476      }
477      if (opts.focusOptions && typeof opts.focusOptions === 'object') {
478        focusEditablePageHeadField(opts.focusOptions);
479      }
480      if (opts.navbarTitleOptions && typeof opts.navbarTitleOptions === 'object') {
481        renderManagedNavbarTitleState(opts.navbarTitleOptions);
482      }
483      return true;
484    }
485    if (Object.prototype.hasOwnProperty.call(opts, 'pageTitle') && opts.pageTitle !== null && typeof opts.pageTitle !== 'undefined') {
486      var pageTitle = String(opts.pageTitle || '').trim();
487      if (pageTitle) {
488        applyPageTitle(pageTitle);
489      }
490    }
491    if (opts.titleNode) {
492      var titleShell = renderReadOnlyTitleShell(opts.titleNode, opts.titleText);
493      opts.titleNode.hidden = false;
494      if (titleShell && titleShell.actions) {
495        renderSyncStatusPill(titleShell.actions, opts.syncStatus, opts.titleSyncOptions);
496      }
497    }
498    if (opts.descriptionNode && Object.prototype.hasOwnProperty.call(opts, 'descriptionFallback')) {
499      var descriptionFragment = null;
500      if (opts.allowPrerenderDescription !== false) {
501        descriptionFragment = readPrerenderHtmlFragment(opts.descriptionPayload, 'description');
502      }
503      if (descriptionFragment) {
504        renderReadOnlyDescriptionShell(opts.descriptionNode, {
505          html: descriptionFragment.html,
506          hidden: descriptionFragment.hidden
507        });
508      } else {
509        renderReadOnlyDescriptionShell(opts.descriptionNode, opts.descriptionFallback);
510      }
511    }
512    if (opts.navbarTitleOptions && typeof opts.navbarTitleOptions === 'object') {
513      renderManagedNavbarTitleState(opts.navbarTitleOptions);
514    }
515    return true;
516  }
517
518  function renderEditableNavbarTitleRow(targetNode, options) {
519    if (!targetNode) {
520      return false;
521    }
522    var opts = options && typeof options === 'object' ? options : {};
523    if (opts.hidden === true) {
524      targetNode.hidden = true;
525      targetNode.innerHTML = '';
526      return true;
527    }
528    var currentText = String(opts.currentText || '');
529    var editing = opts.editing === true;
530    var labelText = String(opts.labelText || 'Navbar title');
531    var inputValue = String(opts.inputValue || currentText);
532    var inputAriaLabel = String(opts.inputAriaLabel || labelText);
533    var editButtonClassName = String(opts.editButtonClassName || 'list-inline-edit-link').trim() || 'list-inline-edit-link';
534    var saveButtonClassName = String(opts.saveButtonClassName || editButtonClassName).trim() || editButtonClassName;
535    var saveDisabled = opts.saveDisabled === true;
536    var html = '<div class="list-page-nav-title-row">';
537    html += '<span class="list-page-nav-title-label">' + escapeHtml(labelText) + '</span>';
538    if (editing) {
539      html += '<span class="list-page-nav-title-edit-wrap">';
540      html += '<input type="text" class="list-page-nav-title-input" value="' + escapeHtml(inputValue) + '" data-page-nav-title-input="true" aria-label="' + escapeHtml(inputAriaLabel) + '">';
541      html += '<button type="button" class="' + escapeHtml(saveButtonClassName) + '" data-page-nav-title-action="save"' + (saveDisabled ? ' disabled aria-disabled="true"' : '') + '>OK</button>';
542      html += '</span>';
543    } else {
544      html += '<span class="list-page-nav-title-value">' + escapeHtml(currentText) + '</span>';
545      html += '<button type="button" class="' + escapeHtml(editButtonClassName) + '" data-page-nav-title-action="edit">Edit...</button>';
546    }
547    html += '</div>';
548    targetNode.hidden = false;
549    targetNode.innerHTML = html;
550    return true;
551  }
552
553  function focusEditablePageHeadField(options) {
554    var opts = options && typeof options === 'object' ? options : {};
555    var activeField = String(opts.activeField || '').trim().toLowerCase();
556    if (!activeField) {
557      return false;
558    }
559    requestAnimationFrame(function () {
560      var inputId = activeField === 'title'
561        ? String(opts.titleInputId || '').trim()
562        : String(opts.descriptionInputId || '').trim();
563      var input = inputId ? document.getElementById(inputId) : null;
564      if (input && typeof input.focus === 'function') {
565        input.focus();
566        if (opts.selectOnFocus !== false && typeof input.select === 'function') {
567          input.select();
568        }
569      }
570      if (typeof opts.afterFocus === 'function') {
571        opts.afterFocus(input || null);
572      }
573    });
574    return true;
575  }
576
577  function focusEditableNavbarTitleInput(options) {
578    var opts = options && typeof options === 'object' ? options : {};
579    var targetNode = opts.targetNode || null;
580    if (!targetNode || !targetNode.querySelector) {
581      return false;
582    }
583    requestAnimationFrame(function () {
584      var input = targetNode.querySelector('[data-page-nav-title-input="true"]');
585      if (input && typeof input.focus === 'function') {
586        input.focus();
587        if (opts.selectOnFocus !== false && typeof input.select === 'function') {
588          input.select();
589        }
590      }
591    });
592    return true;
593  }
594
595  function renderManagedNavbarTitleRow(options) {
596    var opts = options && typeof options === 'object' ? options : {};
597    var titleNode = opts.titleNode || null;
598    var resolvedTarget = titleNode && titleNode.querySelector
599      ? titleNode.querySelector('[data-page-nav-title-host="true"]')
600      : null;
601    if (!resolvedTarget) {
602      return false;
603    }
604    var shouldShow = opts.isAdmin === true && opts.editMode === true;
605    if (titleNode && titleNode.classList) {
606      titleNode.classList.toggle('has-nav-title-row', shouldShow);
607    }
608    if (!shouldShow) {
609      return renderEditableNavbarTitleRow(resolvedTarget, { hidden: true });
610    }
611    var editing = opts.editing === true;
612    var rendered = renderEditableNavbarTitleRow(resolvedTarget, {
613      currentText: opts.currentText,
614      editing: editing,
615      inputValue: opts.inputValue,
616      labelText: opts.labelText,
617      inputAriaLabel: opts.inputAriaLabel,
618      editButtonClassName: opts.editButtonClassName,
619      saveButtonClassName: opts.saveButtonClassName,
620      saveDisabled: opts.saveDisabled
621    });
622    if (rendered && editing) {
623      focusEditableNavbarTitleInput({
624        targetNode: resolvedTarget,
625        selectOnFocus: opts.selectOnFocus
626      });
627    }
628    return rendered;
629  }
630
631  function resolveRootAttributeFallbackText(rootNode, attributeNames, fallbackText) {
632    var root = rootNode || null;
633    var names = Array.isArray(attributeNames) ? attributeNames : [];
634    if (root && typeof root.getAttribute === 'function') {
635      for (var i = 0; i < names.length; i += 1) {
636        var attrName = String(names[i] || '').trim();
637        if (!attrName) {
638          continue;
639        }
640        var attrValue = String(root.getAttribute(attrName) || '').trim();
641        if (attrValue) {
642          return attrValue;
643        }
644      }
645    }
646    return String(fallbackText || '').trim();
647  }
648
649  function resolveManagedNavbarTitle(options) {
650    var opts = options && typeof options === 'object' ? options : {};
651    var configured = String(opts.configuredText || '').trim();
652    if (configured) {
653      return configured;
654    }
655    var payload = opts.payload && typeof opts.payload === 'object' ? opts.payload : null;
656    var payloadTitle = String(payload && payload.nav_title || '').trim();
657    if (payloadTitle) {
658      return payloadTitle;
659    }
660    var renderState = opts.renderState && typeof opts.renderState === 'object' ? opts.renderState : null;
661    var renderTitle = String(renderState && renderState.title || '').trim();
662    if (renderTitle) {
663      return renderTitle;
664    }
665    var fallbackText = resolveRootAttributeFallbackText(
666      opts.rootNode || null,
667      Array.isArray(opts.fallbackAttributeNames) ? opts.fallbackAttributeNames : ['data-page-title'],
668      opts.fallbackText
669    );
670    if (fallbackText) {
671      return fallbackText;
672    }
673    return 'Untitled';
674  }
675
676  function renderManagedNavbarTitleState(options) {
677    var opts = options && typeof options === 'object' ? options : {};
678    var current = resolveManagedNavbarTitle({
679      configuredText: opts.configuredText,
680      payload: opts.payload,
681      renderState: opts.renderState,
682      rootNode: opts.rootNode,
683      fallbackAttributeNames: opts.fallbackAttributeNames,
684      fallbackText: opts.fallbackText
685    });
686    renderManagedNavbarTitleRow({
687      isAdmin: opts.isAdmin,
688      editMode: opts.editMode,
689      titleNode: opts.titleNode,
690      currentText: current,
691      editing: opts.editing,
692      inputValue: Object.prototype.hasOwnProperty.call(opts, 'inputValue') ? opts.inputValue : current,
693      labelText: opts.labelText,
694      inputAriaLabel: opts.inputAriaLabel,
695      editButtonClassName: opts.editButtonClassName,
696      saveButtonClassName: opts.saveButtonClassName,
697      saveDisabled: opts.saveDisabled,
698      selectOnFocus: opts.selectOnFocus
699    });
700    return current;
701  }
702
703  function managedNavbarTitleOptions(options) {
704    var opts = options && typeof options === 'object' ? options : {};
705    var result = {
706      rootNode: opts.rootNode || null,
707      fallbackAttributeNames: Array.isArray(opts.fallbackAttributeNames)
708        ? opts.fallbackAttributeNames.slice()
709        : ['data-page-title'],
710      fallbackText: String(opts.fallbackText || '').trim() || 'Untitled'
711    };
712    [
713      'configuredText',
714      'payload',
715      'renderState',
716      'isAdmin',
717      'editMode',
718      'titleNode',
719      'editing',
720      'inputValue',
721      'labelText',
722      'inputAriaLabel',
723      'editButtonClassName',
724      'saveButtonClassName',
725      'saveDisabled',
726      'selectOnFocus',
727      'currentText'
728    ].forEach(function (key) {
729      if (Object.prototype.hasOwnProperty.call(opts, key)) {
730        result[key] = opts[key];
731      }
732    });
733    return result;
734  }
735
736  function managedNavbarTitlePageOptions(options) {
737    var opts = options && typeof options === 'object' ? options : {};
738    return Object.assign(
739      managedNavbarTitleOptions({
740        configuredText: opts.configuredText,
741        payload: opts.payload,
742        renderState: opts.renderState,
743        rootNode: opts.rootNode,
744        fallbackAttributeNames: opts.fallbackAttributeNames,
745        fallbackText: opts.fallbackText,
746        isAdmin: opts.isAdmin,
747        editMode: opts.editMode,
748        titleNode: opts.titleNode,
749        editing: opts.editing,
750        inputValue: opts.inputValue,
751        labelText: opts.labelText,
752        inputAriaLabel: opts.inputAriaLabel,
753        editButtonClassName: opts.editButtonClassName,
754        saveButtonClassName: opts.saveButtonClassName,
755        saveDisabled: opts.saveDisabled,
756        selectOnFocus: opts.selectOnFocus
757      }),
758      {
759        state: opts.state,
760        payload: opts.payload,
761        rootNode: opts.rootNode || null,
762        slug: opts.slug,
763        isAdmin: opts.isAdmin,
764        renderHead: opts.renderHead
765      }
766    );
767  }
768
769  function renderManagedValidationSummary(options) {
770    var opts = options && typeof options === 'object' ? options : {};
771    var containerNode = opts.containerNode || null;
772    if (!containerNode) {
773      return false;
774    }
775    var visible = opts.visible === true;
776    var errors = Array.isArray(opts.errors) ? opts.errors : [];
777    var warnings = Array.isArray(opts.warnings) ? opts.warnings : [];
778    if (!visible || (!errors.length && !warnings.length)) {
779      containerNode.hidden = true;
780      containerNode.innerHTML = '';
781      return false;
782    }
783    var html = '';
784    if (errors.length) {
785      html += '<div class="list-validation-block is-error"><strong>Validation errors</strong><ul>';
786      errors.forEach(function (msg) {
787        html += '<li>' + escapeHtml(msg) + '</li>';
788      });
789      html += '</ul></div>';
790    }
791    if (warnings.length) {
792      html += '<div class="list-validation-block is-warn"><strong>Validation warnings</strong><ul>';
793      warnings.forEach(function (msg) {
794        html += '<li>' + escapeHtml(msg) + '</li>';
795      });
796      html += '</ul></div>';
797    }
798    containerNode.hidden = false;
799    containerNode.innerHTML = html;
800    return true;
801  }
802
803  function filterManagedValidationMessages(messages, options) {
804    var list = Array.isArray(messages) ? messages : [];
805    var opts = options && typeof options === 'object' ? options : {};
806    if (opts.suppressTransientStateErrors !== true) {
807      return list.slice();
808    }
809    return list.filter(function (msg) {
810      var text = String(msg || '').trim().toLowerCase();
811      if (!text) {
812        return false;
813      }
814      return !(/could not validate .*state/.test(text) || /validation .*temporarily unavailable/.test(text));
815    });
816  }
817
818  function renderManagedPayloadValidationSummary(options) {
819    var opts = options && typeof options === 'object' ? options : {};
820    var payload = opts.payload && typeof opts.payload === 'object' ? opts.payload : null;
821    var validation = payload && payload.validation && typeof payload.validation === 'object'
822      ? payload.validation
823      : {};
824    return renderManagedValidationSummary({
825      containerNode: opts.containerNode || null,
826      visible: opts.visible === true,
827      errors: filterManagedValidationMessages(validation.errors, {
828        suppressTransientStateErrors: opts.suppressTransientStateErrors === true
829      }),
830      warnings: opts.includeWarnings === false
831        ? []
832        : filterManagedValidationMessages(validation.warnings, {
833            suppressTransientStateErrors: opts.suppressTransientStateErrors === true
834          })
835    });
836  }
837
838  function renderManagedSaveStatus(node, status) {
839    if (!node) {
840      return false;
841    }
842    var nextStatus = String(status || '').trim();
843    node.classList.toggle('is-error', nextStatus === 'error');
844    if (nextStatus === 'saving') {
845      node.innerHTML = '<span class="save-spinner" aria-hidden="true"></span>Saving...';
846      return true;
847    }
848    if (nextStatus === 'error') {
849      node.textContent = 'Save failed';
850      return true;
851    }
852    node.textContent = 'Saved';
853    return true;
854  }
855
856  function managedSaveStatusHtml(options) {
857    var opts = options && typeof options === 'object' ? options : {};
858    if (opts.visible !== true) {
859      return '';
860    }
861    var statusId = String(opts.statusId || '').trim();
862    var status = String(opts.status || '').trim();
863    var html = '<span';
864    if (statusId) {
865      html += ' id="' + escapeHtml(statusId) + '"';
866    }
867    html += ' class="list-admin-save-status" aria-live="polite">';
868    if (status === 'saving') {
869      html += '<span class="save-spinner" aria-hidden="true"></span>Saving...';
870    } else if (status === 'error') {
871      html += 'Save failed';
872    } else {
873      html += 'Saved';
874    }
875    html += '</span>';
876    return html;
877  }
878
879  function renderManagedAdminActionBarHtml(options) {
880    var opts = options && typeof options === 'object' ? options : {};
881    function actionAttr(name, value) {
882      var attrName = String(name || '').trim();
883      if (!attrName) {
884        return '';
885      }
886      return ' ' + attrName + '="' + escapeHtml(String(value || '')) + '"';
887    }
888    var html = '<span class="list-page-admin-bar">';
889    html += managedSaveStatusHtml({
890      visible: opts.saveIndicatorVisible === true,
891      statusId: opts.saveStatusId,
892      status: opts.saveStatus
893    });
894    if (opts.showRevert === true) {
895      html += '<button type="button"'
896        + actionAttr(opts.revertActionAttrName || 'data-action', String(opts.revertAction || 'revert'))
897        + htmlAttr('title', String(opts.revertTitle || ''))
898        + (opts.canRevert === true ? '' : ' disabled aria-disabled="true"')
899        + '>Revert</button>';
900    }
901    html += syncStatusPillHtml(opts.syncStatus, opts.syncOptions);
902    if (opts.showPublish === true) {
903      html += '<button type="button" class="' + escapeHtml(String(opts.primaryButtonClassName || 'list-admin-primary-btn')) + '"'
904        + actionAttr(opts.publishActionAttrName || 'data-action', String(opts.publishAction || 'publish'))
905        + '>' + escapeHtml(String(opts.publishLabel || 'Publish to Nostr...')) + '</button>';
906    }
907    html += '<button type="button" class="' + escapeHtml(String(opts.primaryButtonClassName || 'list-admin-primary-btn')) + '"'
908      + actionAttr(opts.editActionAttrName || 'data-action', String(opts.editAction || 'toggle-edit'))
909      + '>' + escapeHtml(opts.editMode ? String(opts.doneLabel || 'Done') : String(opts.editLabel || 'Edit')) + '</button>';
910    html += '</span>';
911    return html;
912  }
913
914  function renderManagedAdminActionBar(options) {
915    var opts = options && typeof options === 'object' ? options : {};
916    var adminNode = opts.adminNode || null;
917    var actionsHostNode = opts.actionsHostNode || null;
918    if (actionsHostNode && opts.clearActionsHost !== false) {
919      actionsHostNode.innerHTML = '';
920    }
921    if (opts.isAdmin !== true) {
922      if (typeof opts.onHide === 'function') {
923        opts.onHide();
924      }
925      if (adminNode) {
926        adminNode.hidden = true;
927        adminNode.innerHTML = '';
928      }
929      return false;
930    }
931    var payload = opts.payload && typeof opts.payload === 'object' ? opts.payload : {};
932    var hasCanonical = !!payload.canonical_exists;
933    var hasDraftChanges = !!payload.draft_differs;
934    var canRevert = Object.prototype.hasOwnProperty.call(opts, 'canRevert')
935      ? opts.canRevert === true
936      : (hasCanonical && hasDraftChanges);
937    var html = renderManagedAdminActionBarHtml({
938      saveIndicatorVisible: opts.saveIndicatorVisible === true,
939      saveStatusId: opts.saveStatusId,
940      saveStatus: opts.saveStatus,
941      showRevert: Object.prototype.hasOwnProperty.call(opts, 'showRevert')
942        ? opts.showRevert === true
943        : opts.editMode === true,
944      revertActionAttrName: opts.revertActionAttrName,
945      revertAction: opts.revertAction,
946      revertTitle: String(
947        opts.revertTitle || (
948          canRevert
949            ? 'Revert draft to Nostr version'
950            : (hasCanonical ? 'No local changes to revert' : 'No Nostr version found')
951        )
952      ),
953      canRevert: canRevert,
954      syncStatus: payload.sync_status,
955      syncOptions: opts.syncOptions,
956      showPublish: Object.prototype.hasOwnProperty.call(opts, 'showPublish')
957        ? opts.showPublish === true
958        : (opts.editMode === true || hasDraftChanges),
959      publishActionAttrName: opts.publishActionAttrName,
960      publishAction: opts.publishAction,
961      publishLabel: opts.publishLabel,
962      editActionAttrName: opts.editActionAttrName,
963      editAction: opts.editAction,
964      editMode: opts.editMode === true,
965      editLabel: opts.editLabel,
966      doneLabel: opts.doneLabel,
967      primaryButtonClassName: opts.primaryButtonClassName
968    });
969    if (actionsHostNode) {
970      actionsHostNode.innerHTML = html;
971    }
972    if (adminNode) {
973      adminNode.hidden = true;
974      adminNode.innerHTML = '';
975    }
976    return true;
977  }
978
979  function startManagedNavbarTitleEdit(options) {
980    var opts = options && typeof options === 'object' ? options : {};
981    var state = opts.state && typeof opts.state === 'object' ? opts.state : null;
982    if (!state) {
983      return false;
984    }
985    state.navTitleEditing = true;
986    state.navTitleInput = resolveManagedNavbarTitle(opts);
987    if (typeof opts.renderHead === 'function') {
988      opts.renderHead();
989    }
990    return true;
991  }
992
993  function saveManagedNavbarTitle(options) {
994    var opts = options && typeof options === 'object' ? options : {};
995    var state = opts.state && typeof opts.state === 'object' ? opts.state : null;
996    var isAdmin = typeof opts.isAdmin === 'function' ? opts.isAdmin() : opts.isAdmin === true;
997    if (!state || !isAdmin || state.navTitleBusy) {
998      return Promise.resolve(false);
999    }
1000    var rootNode = opts.rootNode || null;
1001    var input = rootNode && rootNode.querySelector ? rootNode.querySelector('[data-page-nav-title-input="true"]') : null;
1002    if (input instanceof HTMLInputElement) {
1003      state.navTitleInput = String(input.value || '');
1004    }
1005    var nextTitle = String(state.navTitleInput || '').trim();
1006    var slug = String(opts.slug || '').trim();
1007    state.navTitleBusy = true;
1008    var auth = authPayload();
1009    return postFormJson('/cgi/blog-update-nostr-page-nav-title', {
1010      page_slug: slug,
1011      nav_title: nextTitle,
1012      session_token: auth.session_token,
1013      csrf_token: auth.csrf_token
1014    }).then(function (data) {
1015      var updated = String((data && data.nav_title) || nextTitle || resolveManagedNavbarTitle(opts)).trim();
1016      state.navTitle = updated;
1017      state.navTitleEditing = false;
1018      state.navTitleInput = '';
1019      if (opts.payload && typeof opts.payload === 'object') {
1020        opts.payload.nav_title = updated;
1021      } else if (state.payload && typeof state.payload === 'object') {
1022        state.payload.nav_title = updated;
1023      }
1024      try {
1025        window.dispatchEvent(new CustomEvent('wizardry-navbar-refresh-request'));
1026      } catch (_err) {
1027        // Ignore navbar refresh dispatch failures.
1028      }
1029      if (typeof opts.renderHead === 'function') {
1030        opts.renderHead();
1031      }
1032      return true;
1033    }).catch(function (err) {
1034      window.alert(err && err.message ? err.message : 'Could not save navbar title');
1035      return false;
1036    }).finally(function () {
1037      state.navTitleBusy = false;
1038      if (typeof opts.renderHead === 'function') {
1039        opts.renderHead();
1040      }
1041    });
1042  }
1043
1044  function saveManagedNavbarTitleForPage(options) {
1045    return saveManagedNavbarTitle(managedNavbarTitlePageOptions(options));
1046  }
1047
1048  function startManagedNavbarTitleEditForPage(options) {
1049    return startManagedNavbarTitleEdit(managedNavbarTitlePageOptions(options));
1050  }
1051
1052  function handleManagedNavbarTitleAction(event, target, options) {
1053    var targetNode = target instanceof Element ? target : null;
1054    var opts = options && typeof options === 'object' ? options : {};
1055    if (!targetNode) {
1056      return false;
1057    }
1058    var actionNode = targetNode.closest('[data-page-nav-title-action]');
1059    if (!(actionNode instanceof HTMLElement)) {
1060      return false;
1061    }
1062    var isAdmin = typeof opts.isAdmin === 'function' ? opts.isAdmin() : opts.isAdmin === true;
1063    if (!isAdmin || opts.editMode !== true) {
1064      return false;
1065    }
1066    if (event && typeof event.preventDefault === 'function') {
1067      event.preventDefault();
1068    }
1069    var action = String(actionNode.getAttribute('data-page-nav-title-action') || '');
1070    if (action === 'edit') {
1071      if (typeof opts.beginEdit === 'function') {
1072        opts.beginEdit();
1073      }
1074      return true;
1075    }
1076    if (action === 'save') {
1077      if (typeof opts.save === 'function') {
1078        opts.save();
1079      }
1080      return true;
1081    }
1082    return false;
1083  }
1084
1085  function resetManagedNavbarTitleState(state, options) {
1086    var targetState = state && typeof state === 'object' ? state : null;
1087    var opts = options && typeof options === 'object' ? options : {};
1088    if (!targetState) {
1089      return false;
1090    }
1091    if (Object.prototype.hasOwnProperty.call(opts, 'payload')) {
1092      targetState.navTitle = String(opts.payload && opts.payload.nav_title || '').trim();
1093    } else if (Object.prototype.hasOwnProperty.call(opts, 'navTitle')) {
1094      targetState.navTitle = String(opts.navTitle || '').trim();
1095    } else if (!Object.prototype.hasOwnProperty.call(targetState, 'navTitle')) {
1096      targetState.navTitle = '';
1097    }
1098    targetState.navTitleEditing = false;
1099    targetState.navTitleInput = '';
1100    targetState.navTitleBusy = false;
1101    return true;
1102  }
1103
1104  function renderResolvedReadOnlyContent(options) {
1105    var opts = options && typeof options === 'object' ? options : {};
1106    var targetNode = opts.targetNode || null;
1107    var resolved = null;
1108    var matchedStaticPrerender = false;
1109    if (opts.allowPrerender !== false) {
1110      var fragment = readPrerenderHtmlFragment(opts.payload, 'content');
1111      if (fragment) {
1112        resolved = {
1113          adopted: true,
1114          html: fragment.html,
1115          hidden: fragment.hidden
1116        };
1117        matchedStaticPrerender = hasMatchingStaticPrerender(targetNode, targetNode, opts.payload);
1118      }
1119    }
1120    if (!resolved && typeof opts.renderFallback === 'function') {
1121      var fallback = opts.renderFallback();
1122      resolved = {
1123        adopted: false,
1124        html: typeof fallback === 'string' ? fallback : '',
1125        hidden: false
1126      };
1127    }
1128    if (!resolved || !targetNode) {
1129      return resolved;
1130    }
1131    if (resolved.adopted) {
1132      if (!matchedStaticPrerender) {
1133        mountPrerenderHtmlFragment(targetNode, opts.payload, 'content', opts.mountOptions);
1134      } else {
1135        targetNode.hidden = !!resolved.hidden;
1136      }
1137      if (typeof opts.afterAdopt === 'function') {
1138        opts.afterAdopt(resolved);
1139      }
1140    } else {
1141      var mountOptions = opts.mountOptions && typeof opts.mountOptions === 'object' ? opts.mountOptions : {};
1142      if (typeof mountOptions.applyHtml === 'function') {
1143        mountOptions.applyHtml(resolved.html);
1144      } else {
1145        targetNode.innerHTML = resolved.html;
1146      }
1147      targetNode.hidden = !!resolved.hidden;
1148    }
1149    if (typeof opts.afterRender === 'function') {
1150      opts.afterRender(resolved);
1151    }
1152    return resolved;
1153  }
1154
1155  function escapeHtml(value) {
1156    return String(value || '')
1157      .replace(/&/g, '&amp;')
1158      .replace(/</g, '&lt;')
1159      .replace(/>/g, '&gt;')
1160      .replace(/"/g, '&quot;')
1161      .replace(/'/g, '&#39;');
1162  }
1163
1164  function syncStatusDefaults(status, options) {
1165    var opts = options && typeof options === 'object' ? options : {};
1166    var variant = String(opts.messageVariant || 'server_copy').trim().toLowerCase();
1167    switch (status) {
1168      case 'local_newer_than_nostr':
1169        return {
1170          label: 'Server newer',
1171          message: variant === 'local_source'
1172            ? 'Local source is newer than latest published Nostr state.'
1173            : 'Server copy is newer than the latest published Nostr state. Visitors see the server copy.',
1174          className: 'status-local-newer-than-nostr'
1175        };
1176      case 'nostr_newer_than_local':
1177        return {
1178          label: 'Nostr newer',
1179          message: variant === 'local_source'
1180            ? 'Published Nostr state is newer than local source.'
1181            : 'Published Nostr state is newer than the server copy. Visitors still see the server copy until the site source changes.',
1182          className: 'status-nostr-newer-than-local'
1183        };
1184      case 'in_sync':
1185        return {
1186          label: 'Synced',
1187          message: variant === 'local_source'
1188            ? 'Local source and published state are in sync.'
1189            : 'Server copy and published Nostr state are in sync.',
1190          className: 'status-in-sync'
1191        };
1192      case 'unpublished_local_changes':
1193        return {
1194          label: 'Server only',
1195          message: variant === 'local_source'
1196            ? 'No published Nostr state yet for this page.'
1197            : 'This page exists only on the server so far. Visitors see the server copy.',
1198          className: 'status-unpublished-local-changes'
1199        };
1200      default:
1201        return {
1202          label: 'Sync unknown',
1203          message: 'Cannot determine local-vs-Nostr sync status yet.',
1204          className: 'status-unknown'
1205        };
1206    }
1207  }
1208
1209  function syncStatusPillHtml(syncStatus, options) {
1210    var sync = syncStatus && typeof syncStatus === 'object' ? syncStatus : {};
1211    var status = String(sync.status || 'unknown').trim();
1212    var config = syncStatusDefaults(status, options);
1213    var message = String(sync.message || config.message).trim();
1214    return '<span class="page-sync-status-pill ' + config.className + '" title="' + escapeHtml(message) + '">' + escapeHtml(config.label) + '</span>';
1215  }
1216
1217  function renderSyncStatusPill(actionsHostOrId, syncStatus, options) {
1218    var host = typeof actionsHostOrId === 'string'
1219      ? document.getElementById(String(actionsHostOrId || '').trim())
1220      : actionsHostOrId;
1221    if (!host) {
1222      return false;
1223    }
1224    var html = syncStatusPillHtml(syncStatus, options);
1225    if (host.innerHTML !== html) {
1226      host.innerHTML = html;
1227    }
1228    return true;
1229  }
1230
1231  function stripLegacyNostrSyncPills(value) {
1232    return String(value || '').replace(/<\s*(?:nostr-sync-pill|gazeta-sync-pill)\b[^>]*>(?:\s*<\/\s*(?:nostr-sync-pill|gazeta-sync-pill)\s*>)?/gi, '').trim();
1233  }
1234
1235  function readNostrPageBootstrap(slug, isExpectedPayload) {
1236    try {
1237      var allPayloads = window.__wizardryNostrPageBootstrap;
1238      if (!allPayloads || typeof allPayloads !== 'object') {
1239        return null;
1240      }
1241      var payload = allPayloads[String(slug || '')];
1242      if (!payload || typeof payload !== 'object') {
1243        return null;
1244      }
1245      if (typeof isExpectedPayload === 'function' && !isExpectedPayload(payload)) {
1246        return null;
1247      }
1248      return payload;
1249    } catch (_err) {
1250      return null;
1251    }
1252  }
1253
1254  function prerenderFragment(payload, key) {
1255    return String(payload && payload.prerender && payload.prerender[key] || '');
1256  }
1257
1258  function readPrerenderHtmlFragment(payload, name, options) {
1259    var opts = options && typeof options === 'object' ? options : {};
1260    var fragmentName = String(name || '').trim();
1261    if (!fragmentName) {
1262      return null;
1263    }
1264    var html = prerenderFragment(payload, fragmentName + '_html');
1265    if (!html && opts.allowEmpty !== true) {
1266      return null;
1267    }
1268    return {
1269      html: html,
1270      hidden: /\bhidden\b/i.test(prerenderFragment(payload, fragmentName + '_attrs'))
1271    };
1272  }
1273
1274  function mountPrerenderHtmlFragment(targetNode, payload, name, options) {
1275    var fragment = readPrerenderHtmlFragment(payload, name, options);
1276    if (!targetNode || !fragment) {
1277      return false;
1278    }
1279    var opts = options && typeof options === 'object' ? options : {};
1280    if (typeof opts.applyHtml === 'function') {
1281      opts.applyHtml(fragment.html);
1282    } else {
1283      targetNode.innerHTML = fragment.html;
1284    }
1285    targetNode.hidden = fragment.hidden;
1286    return true;
1287  }
1288
1289  function resolveManagedPagePreviewHtml(options) {
1290    var opts = options && typeof options === 'object' ? options : {};
1291    var payload = opts.payload && typeof opts.payload === 'object' ? opts.payload : null;
1292    if (!payload) {
1293      return '';
1294    }
1295    if (typeof opts.normalizeState !== 'function') {
1296      return '';
1297    }
1298    var normalizeState = opts.normalizeState;
1299    var payloadState = normalizeState((payload && payload.state) || null);
1300    var renderState = normalizeState(opts.renderState || null);
1301    if (JSON.stringify(payloadState) !== JSON.stringify(renderState)) {
1302      return '';
1303    }
1304    var fragment = readPrerenderHtmlFragment(payload, 'content');
1305    if (!fragment || fragment.hidden) {
1306      return '';
1307    }
1308    return String(fragment.html || '');
1309  }
1310
1311  function hasPaintedPrerenderShell(rootNode, contentNode) {
1312    if (!rootNode || rootNode.getAttribute('data-prerender-painted') !== 'true') {
1313      return false;
1314    }
1315    if (!contentNode) {
1316      return true;
1317    }
1318    return contentNode.getAttribute('data-prerender-painted') === 'true';
1319  }
1320
1321  function hasMatchingStaticPrerender(rootNode, contentNode, payload) {
1322    var signature = String(payload && payload.prerender_signature || '').trim();
1323    if (!signature || !rootNode || !contentNode) {
1324      return false;
1325    }
1326    if (!hasPaintedPrerenderShell(rootNode, contentNode)) {
1327      return false;
1328    }
1329    return rootNode.getAttribute('data-prerender-signature') === signature ||
1330      contentNode.getAttribute('data-prerender-signature') === signature;
1331  }
1332
1333  function pageBootstrapCacheKey(slug) {
1334    return 'nostr_page_bootstrap_v1:' + String(slug || '').trim();
1335  }
1336
1337  function readBootstrapCache(options) {
1338    var opts = options && typeof options === 'object' ? options : {};
1339    var storageKey = String(opts.storageKey || '').trim();
1340    if (!storageKey) {
1341      return null;
1342    }
1343    var clearOnDeny = opts.clearOnDeny !== false;
1344    try {
1345      if (typeof opts.allowRead === 'function' && opts.allowRead() === false) {
1346        if (clearOnDeny) {
1347          localStorage.removeItem(storageKey);
1348        }
1349        return null;
1350      }
1351      var raw = localStorage.getItem(storageKey);
1352      if (!raw) {
1353        return null;
1354      }
1355      var parsed = JSON.parse(raw);
1356      if (!parsed || typeof parsed !== 'object') {
1357        return null;
1358      }
1359      var savedAt = Number(parsed.saved_at || 0);
1360      var maxAgeMs = Number(opts.maxAgeMs || 0);
1361      if (!isFinite(savedAt) || savedAt <= 0 || (maxAgeMs > 0 && (Date.now() - savedAt) > maxAgeMs)) {
1362        localStorage.removeItem(storageKey);
1363        return null;
1364      }
1365      var expectedAuthSignature = typeof opts.authSignature === 'function'
1366        ? String(opts.authSignature() || '')
1367        : String(opts.authSignature || '');
1368      if (String(parsed.auth_signature || '') !== expectedAuthSignature) {
1369        return null;
1370      }
1371      if (!parsed.payload || typeof parsed.payload !== 'object') {
1372        return null;
1373      }
1374      if (typeof opts.isExpectedPayload === 'function' && !opts.isExpectedPayload(parsed.payload)) {
1375        localStorage.removeItem(storageKey);
1376        return null;
1377      }
1378      return parsed.payload;
1379    } catch (_err) {
1380      return null;
1381    }
1382  }
1383
1384  function writeBootstrapCache(payload, options) {
1385    var opts = options && typeof options === 'object' ? options : {};
1386    var storageKey = String(opts.storageKey || '').trim();
1387    if (!storageKey || !payload || typeof payload !== 'object') {
1388      return;
1389    }
1390    var clearOnDeny = opts.clearOnDeny !== false;
1391    try {
1392      if (typeof opts.allowWrite === 'function' && opts.allowWrite(payload) === false) {
1393        if (clearOnDeny) {
1394          localStorage.removeItem(storageKey);
1395        }
1396        return;
1397      }
1398      var authSignature = typeof opts.authSignature === 'function'
1399        ? String(opts.authSignature() || '')
1400        : String(opts.authSignature || '');
1401      localStorage.setItem(storageKey, JSON.stringify({
1402        auth_signature: authSignature,
1403        payload: payload,
1404        saved_at: Date.now()
1405      }));
1406    } catch (_err) {
1407      // Ignore storage failures.
1408    }
1409  }
1410
1411  function sessionAuthSignature() {
1412    var auth = authPayload();
1413    return String(auth.session_token || '') + '|' + String(auth.csrf_token || '');
1414  }
1415
1416  function writePageBootstrapCache(payload, options) {
1417    var opts = options && typeof options === 'object' ? options : {};
1418    return writeBootstrapCache(payload, {
1419      storageKey: pageBootstrapCacheKey(opts.slug),
1420      authSignature: opts.authSignature || sessionAuthSignature,
1421      allowWrite: opts.allowWrite,
1422      clearOnDeny: opts.clearOnDeny
1423    });
1424  }
1425
1426  function commitManagedPagePayload(targetPayload, sourcePayload, options) {
1427    var opts = options && typeof options === 'object' ? options : {};
1428    var target = mergeManagedPagePayload(targetPayload, sourcePayload, {
1429      includeState: opts.includeState,
1430      validationFallback: opts.validationFallback,
1431      passthroughFields: opts.passthroughFields
1432    });
1433    if (!target) {
1434      return target;
1435    }
1436    if (Object.prototype.hasOwnProperty.call(opts, 'draftExists')) {
1437      target.draft_exists = !!opts.draftExists;
1438    }
1439    if (Object.prototype.hasOwnProperty.call(opts, 'draftDiffers')) {
1440      target.draft_differs = !!opts.draftDiffers;
1441    }
1442    if (Object.prototype.hasOwnProperty.call(opts, 'statePayload')) {
1443      target.state = opts.statePayload;
1444    }
1445    if (opts.persist !== false && opts.slug) {
1446      writePageBootstrapCache(target, {
1447        slug: opts.slug,
1448        authSignature: opts.authSignature || sessionAuthSignature,
1449        clearOnDeny: opts.clearOnDeny,
1450        allowWrite: managedBootstrapAllowWriteForPersistMode(opts.persistMode)
1451      });
1452    }
1453    return target;
1454  }
1455
1456  function reconcileManagedPageRefreshRender(options) {
1457    var opts = options && typeof options === 'object' ? options : {};
1458    var state = opts.state && typeof opts.state === 'object' ? opts.state : null;
1459    if (!state) {
1460      return false;
1461    }
1462    var previousSignature = String(opts.previousSignature || '');
1463    var nextRenderSignature = String(opts.nextRenderSignature || '');
1464    var shouldRepaint = !state.initialContentPainted || previousSignature !== nextRenderSignature;
1465    if (!shouldRepaint || (typeof opts.shouldPreserveAdoptedPrerender === 'function' && opts.shouldPreserveAdoptedPrerender() === true)) {
1466      if (typeof opts.renderPreserved === 'function') {
1467        opts.renderPreserved();
1468      }
1469      state.renderSignature = nextRenderSignature;
1470      return false;
1471    }
1472    if (typeof opts.beforeRenderAll === 'function') {
1473      opts.beforeRenderAll();
1474    }
1475    if (typeof opts.renderAll === 'function') {
1476      opts.renderAll();
1477    }
1478    state.renderSignature = nextRenderSignature;
1479    return true;
1480  }
1481
1482  function bindSessionAuthRefresh(options) {
1483    var opts = options && typeof options === 'object' ? options : {};
1484    var onChange = typeof opts.onChange === 'function' ? opts.onChange : null;
1485    if (!onChange) {
1486      return false;
1487    }
1488    var onVisible = typeof opts.onVisible === 'function' ? opts.onVisible : null;
1489    var onHidden = typeof opts.onHidden === 'function' ? opts.onHidden : null;
1490    var storageKeys = Array.isArray(opts.storageKeys) ? opts.storageKeys.map(function (key) {
1491      return String(key || '');
1492    }).filter(Boolean) : ['session_token', 'csrf_token'];
1493    window.addEventListener('blog-auth-changed', onChange);
1494    window.addEventListener('storage', function (event) {
1495      if (!event || !event.key) {
1496        return;
1497      }
1498      if (storageKeys.indexOf(String(event.key || '')) !== -1) {
1499        onChange(event);
1500      }
1501    });
1502    window.addEventListener('focus', onChange);
1503    document.addEventListener('visibilitychange', function () {
1504      if (document.visibilityState === 'visible') {
1505        if (onVisible) {
1506          onVisible();
1507          return;
1508        }
1509        onChange();
1510        return;
1511      }
1512      if (onHidden) {
1513        onHidden();
1514      }
1515    });
1516    var pollState = opts.pollState && typeof opts.pollState === 'object' ? opts.pollState : null;
1517    var pollDurationMs = Math.max(0, Number(opts.pollDurationMs || 0) || 0);
1518    if (pollState && pollDurationMs > 0 && !pollState.timer) {
1519      pollState.startedAt = Date.now();
1520      pollState.timer = window.setInterval(function () {
1521        if (Date.now() - Number(pollState.startedAt || 0) > pollDurationMs) {
1522          window.clearInterval(pollState.timer);
1523          pollState.timer = 0;
1524          return;
1525        }
1526        onChange();
1527        if (typeof opts.stopWhen === 'function' && opts.stopWhen()) {
1528          window.clearInterval(pollState.timer);
1529          pollState.timer = 0;
1530        }
1531      }, Math.max(100, Number(opts.pollIntervalMs || 500) || 500));
1532    }
1533    return true;
1534  }
1535
1536  function authPayload() {
1537    try {
1538      return {
1539        session_token: String(localStorage.getItem('session_token') || '').trim(),
1540        csrf_token: String(localStorage.getItem('csrf_token') || '').trim()
1541      };
1542    } catch (_err) {
1543      return { session_token: '', csrf_token: '' };
1544    }
1545  }
1546
1547  function hasLikelyAuthenticatedSession() {
1548    var auth = authPayload();
1549    return !!(auth && auth.session_token && auth.csrf_token);
1550  }
1551
1552  function hasLikelyAdminSession() {
1553    if (!hasLikelyAuthenticatedSession()) {
1554      return false;
1555    }
1556    try {
1557      return String(localStorage.getItem('last_auth_is_admin') || '') 
1557=== '1';
1558    } catch (_err) {
1559      return false;
1560    }
1561  }
1562
1563  function viewerAuthSignature() {
1564    return sessionAuthSignature() + '|' + (hasLikelyAdminSession() ? 'admin' : 'visitor');
1565  }
1566
1567  function managedBootstrapAllowWriteForPersistMode(persistMode) {
1568    var mode = String(persistMode || 'always').trim().toLowerCase();
1569    return function (nextPayload) {
1570      if (mode === 'authenticated_admin') {
1571        return !!(nextPayload && nextPayload.is_admin && hasLikelyAuthenticatedSession());
1572      }
1573      return true;
1574    };
1575  }
1576
1577  function eventHasVerifiedAdminState(event) {
1578    return !!(event && event.detail && event.detail.authenticated === true && typeof event.detail.is_admin !== 'undefined');
1579  }
1580
1581  function authEventIsLikelyAdmin(event) {
1582    if (eventHasVerifiedAdminState(event)) {
1583      return event.detail.is_admin === true;
1584    }
1585    return hasLikelyAdminSession();
1586  }
1587
1588  function canUseVisitorPrerenderReadOnly(options) {
1589    var opts = options && typeof options === 'object' ? options : {};
1590    if (opts.isAdmin === true && opts.allowAdmin !== true) {
1591      return false;
1592    }
1593    if (opts.allowAuthenticated !== true && hasLikelyAuthenticatedSession()) {
1594      return false;
1595    }
1596    if (typeof opts.extraCheck === 'function') {
1597      return opts.extraCheck() !== false;
1598    }
1599    if (Object.prototype.hasOwnProperty.call(opts, 'extraAllowed')) {
1600      return opts.extraAllowed !== false;
1601    }
1602    return true;
1603  }
1604
1605  function canUsePayloadPrerenderReadOnly(payload, options) {
1606    if (!payload || typeof payload !== 'object') {
1607      return false;
1608    }
1609    var opts = options && typeof options === 'object' ? options : {};
1610    var allowAuthenticated = false;
1611    var allowAdmin = false;
1612    if (typeof opts.allowAuthenticated === 'function') {
1613      allowAuthenticated = opts.allowAuthenticated(payload) === true;
1614    } else if (typeof opts.allowAuthenticatedField === 'string' && opts.allowAuthenticatedField) {
1615      allowAuthenticated = payload[opts.allowAuthenticatedField] === true;
1616    } else if (Object.prototype.hasOwnProperty.call(opts, 'allowAuthenticated')) {
1617      allowAuthenticated = opts.allowAuthenticated === true;
1618    }
1619    if (typeof opts.allowAdmin === 'function') {
1620      allowAdmin = opts.allowAdmin(payload) === true;
1621    } else if (typeof opts.allowAdminField === 'string' && opts.allowAdminField) {
1622      allowAdmin = payload[opts.allowAdminField] === true;
1623    } else if (Object.prototype.hasOwnProperty.call(opts, 'allowAdmin')) {
1624      allowAdmin = opts.allowAdmin === true;
1625    }
1626    return canUseVisitorPrerenderReadOnly({
1627      isAdmin: !!payload.is_admin,
1628      allowAuthenticated: allowAuthenticated,
1629      allowAdmin: allowAdmin,
1630      extraCheck: opts.extraCheck,
1631      extraAllowed: opts.extraAllowed
1632    });
1633  }
1634
1635  function ensureNostrPublishDialog() {
1636    if (window.blogNostrPublishDialog && typeof window.blogNostrPublishDialog.open === 'function') {
1637      return Promise.resolve(true);
1638    }
1639    if (nostrPublishDialogPromise) {
1640      return nostrPublishDialogPromise;
1641    }
1642    nostrPublishDialogPromise = new Promise(function (resolve) {
1643      var script = document.createElement('script');
1644      script.src = '/static/nostr-publish-dialog.js';
1645      script.async = true;
1646      script.onload = function () {
1647        resolve(!!(window.blogNostrPublishDialog && typeof window.blogNostrPublishDialog.open === 'function'));
1648      };
1649      script.onerror = function () {
1650        nostrPublishDialogPromise = null;
1651        resolve(false);
1652      };
1653      document.head.appendChild(script);
1654    });
1655    return nostrPublishDialogPromise;
1656  }
1657
1658  var managedMarkdownParserPromise = null;
1659  var MANAGED_MARKDOWN_PARSER_SRC = 'https://cdn.jsdelivr.net/npm/[email protected]/marked.min.js';
1660
1661  function markedParserReady() {
1662    return !!(window.marked && typeof window.marked.parse === 'function' && typeof window.marked.parseInline === 'function');
1663  }
1664
1665  function ensureManagedMarkdownParser() {
1666    if (markedParserReady()) {
1667      return Promise.resolve(true);
1668    }
1669    if (managedMarkdownParserPromise) {
1670      return managedMarkdownParserPromise;
1671    }
1672    managedMarkdownParserPromise = new Promise(function (resolve) {
1673      var script = document.querySelector('script[src="' + MANAGED_MARKDOWN_PARSER_SRC + '"]');
1674      function finish(ok) {
1675        if (!ok) {
1676          managedMarkdownParserPromise = null;
1677        }
1678        resolve(ok);
1679      }
1680      function handleLoad() {
1681        finish(markedParserReady());
1682      }
1683      function handleError() {
1684        finish(false);
1685      }
1686      if (!script) {
1687        script = document.createElement('script');
1688        script.src = MANAGED_MARKDOWN_PARSER_SRC;
1689        script.async = true;
1690        script.setAttribute('data-managed-markdown-parser', 'true');
1691      }
1692      script.addEventListener('load', handleLoad, { once: true });
1693      script.addEventListener('error', handleError, { once: true });
1694      if (!script.parentNode) {
1695        document.head.appendChild(script);
1696      }
1697    });
1698    return managedMarkdownParserPromise;
1699  }
1700
1701  function scheduleMarkedUpgrade(upgradeState, onReady, options) {
1702    var state = upgradeState && typeof upgradeState === 'object' ? upgradeState : null;
1703    var opts = options && typeof options === 'object' ? options : {};
1704    if (!state || typeof onReady !== 'function' || markedParserReady()) {
1705      return false;
1706    }
1707    if (state.timer) {
1708      return false;
1709    }
1710    if (opts.loadParser) {
1711      ensureManagedMarkdownParser();
1712    }
1713    state.attempts = 0;
1714    function pollForMarked() {
1715      if (markedParserReady()) {
1716        state.timer = 0;
1717        onReady();
1718        return;
1719      }
1720      state.attempts += 1;
1721      if (state.attempts >= 50) {
1722        state.timer = 0;
1723        return;
1724      }
1725      state.timer = window.setTimeout(pollForMarked, 100);
1726    }
1727    state.timer = window.setTimeout(pollForMarked, 100);
1728    return true;
1729  }
1730
1731  function renderManagedMarkdownInline(md, options) {
1732    var value = String(md || '');
1733    var opts = options && typeof options === 'object' ? options : {};
1734    if (!value) {
1735      return '';
1736    }
1737    if (window.marked && typeof window.marked.parseInline === 'function') {
1738      return window.marked.parseInline(value);
1739    }
1740    if (opts.upgradeState && typeof opts.onUpgrade === 'function') {
1741      scheduleMarkedUpgrade(opts.upgradeState, opts.onUpgrade, opts);
1742    }
1743    if (typeof opts.renderFallback === 'function') {
1744      return opts.renderFallback(value);
1745    }
1746    return escapeHtml(value);
1747  }
1748
1749  function safeManagedMarkdownHref(raw) {
1750    var href = String(raw || '').trim().replace(/^<|>$/g, '');
1751    if (!href) {
1752      return '';
1753    }
1754    if (/^(https?:|mailto:|\/|#)/i.test(href)) {
1755      return href;
1756    }
1757    if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(href)) {
1758      return '';
1759    }
1760    return href;
1761  }
1762
1763  function renderManagedMarkdownInlineLinkFallback(md) {
1764    var value = String(md || '');
1765    var linkPattern = /\[([^\]]+)\]\(([^)\s]+)(?:\s+["'][^"']*["'])?\)/g;
1766    var html = '';
1767    var lastIndex = 0;
1768    var match;
1769    while ((match = linkPattern.exec(value)) !== null) {
1770      html += escapeHtml(value.slice(lastIndex, match.index));
1771      var href = safeManagedMarkdownHref(match[2] || '');
1772      var label = escapeHtml(match[1] || '');
1773      if (href) {
1774        html += '<a href="' + escapeHtml(href) + '">' + label + '</a>';
1775      } else {
1776        html += label;
1777      }
1778      lastIndex = linkPattern.lastIndex;
1779    }
1780    html += escapeHtml(value.slice(lastIndex));
1781    return html;
1782  }
1783
1784  function renderManagedMarkdownBlock(md, options) {
1785    var value = String(md || '');
1786    var opts = options && typeof options === 'object' ? options : {};
1787    if (!value) {
1788      return '';
1789    }
1790    if (window.marked && typeof window.marked.parse === 'function') {
1791      return window.marked.parse(value);
1792    }
1793    if (opts.upgradeState && typeof opts.onUpgrade === 'function') {
1794      scheduleMarkedUpgrade(opts.upgradeState, opts.onUpgrade, opts);
1795    }
1796    if (typeof opts.renderFallback === 'function') {
1797      return opts.renderFallback(value);
1798    }
1799    var inlineFallback = typeof opts.renderInlineFallback === 'function'
1800      ? opts.renderInlineFallback
1801      : escapeHtml;
1802    return '<p>' + inlineFallback(value).replace(/\n/g, '<br>') + '</p>';
1803  }
1804
1805  function normalizeSlug(value) {
1806    return String(value || '').trim().toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, '');
1807  }
1808
1809  function slugFromPath(pathname) {
1810    var path = String(pathname || '').trim();
1811    if (!path) {
1812      return 'index';
1813    }
1814    path = path.split('?')[0].split('#')[0].replace(/\/+$/, '');
1815    if (!path || path === '/') {
1816      return 'index';
1817    }
1818    if (path.indexOf('/pages/') === 0) {
1819      path = path.slice('/pages/'.length);
1820    } else if (path.charAt(0) === '/') {
1821      path = path.slice(1);
1822    }
1823    path = path.replace(/\.html?$/i, '');
1824    return path.indexOf('/') >= 0 ? '' : normalizeSlug(path);
1825  }
1826
1827  function routeRootSlugFromDom() {
1828    var blogRoot = document.getElementById('blog-page-root');
1829    if (blogRoot) {
1830      return normalizeSlug(blogRoot.getAttribute('data-page-slug') || blogRoot.getAttribute('data-blog-slug') || '');
1831    }
1832    var nip23Root = document.getElementById('nip23-page-root');
1833    if (nip23Root) {
1834      return normalizeSlug(nip23Root.getAttribute('data-page-slug') || '');
1835    }
1836    var listRoot = document.getElementById('list-page-root') || document.getElementById('icon-gallery-root');
1837    if (listRoot) {
1838      return normalizeSlug(listRoot.getAttribute('data-list-slug') || '');
1839    }
1840    var rankingRoot = document.getElementById('public-ranking-root');
1841    if (rankingRoot) {
1842      return normalizeSlug(rankingRoot.getAttribute('data-ranking-slug') || '');
1843    }
1844    var contactRoot = document.getElementById('contact-page-root');
1845    if (contactRoot) {
1846      return normalizeSlug(contactRoot.getAttribute('data-page-slug') || '');
1847    }
1848    return '';
1849  }
1850
1851  function slugsEquivalent(expected, root) {
1852    var a = normalizeSlug(expected);
1853    var b = normalizeSlug(root);
1854    return !!(a && b && (a === b || (a === 'index' && b === 'blog') || (a === 'blog' && b === 'index')));
1855  }
1856
1857  function forceHydrationReveal() {
1858    try {
1859      var gate = window.__wizardryHydration;
1860      if (gate && typeof gate.forceReveal === 'function') {
1861        gate.forceReveal();
1862        return;
1863      }
1864    } catch (_gateErr) {
1865      // Ignore hydration gate issues.
1866    }
1867    if (document.documentElement) {
1868      document.documentElement.classList.remove('app-hydrating');
1869    }
1870  }
1871
1872  function markHydrationPageReady() {
1873    try {
1874      var gate = window.__wizardryHydration;
1875      if (gate && typeof gate.markPageReady === 'function') {
1876        gate.markPageReady();
1877      }
1878    } catch (_gateErr) {
1879      // Ignore hydration gate issues.
1880    }
1881  }
1882
1883  function resolveManagedPageReadySlug(slug) {
1884    var explicitSlug = String(slug || '').trim();
1885    if (explicitSlug) {
1886      return explicitSlug;
1887    }
1888    return routeRootSlugFromDom() || slugFromPath(window.location.pathname || '/') || '';
1889  }
1890
1891  function hasPaintedManagedContent(contentNode) {
1892    return !!(
1893      contentNode &&
1894      contentNode.getAttribute &&
1895      contentNode.getAttribute('data-prerender-painted') === 'true'
1896    );
1897  }
1898
1899  function notifyInitialContentPainted(slug, options) {
1900    var opts = options && typeof options === 'object' ? options : {};
1901    var state = opts.state && typeof opts.state === 'object' ? opts.state : null;
1902    if (state && state.initialContentPainted) {
1903      return false;
1904    }
1905    if (state) {
1906      state.initialContentPainted = true;
1907    }
1908    var rootNode = opts.rootNode || null;
1909    var loadingClass = String(opts.loadingClass || '').trim();
1910    if (rootNode && rootNode.classList && loadingClass) {
1911      rootNode.classList.remove(loadingClass);
1912    }
1913    pageInitialContentReady = true;
1914    try {
1915      window.dispatchEvent(new CustomEvent('blog-page-initial-content-ready', {
1916        detail: { slug: resolveManagedPageReadySlug(slug) }
1917      }));
1918    } catch (_err) {
1919      // Ignore event dispatch failures.
1920    }
1921    if (opts.markPageReady === true) {
1922      markHydrationPageReady();
1923    }
1924    return true;
1925  }
1926
1927  function notifyCurrentManagedPageReady(options) {
1928    var opts = options && typeof options === 'object' ? options : {};
1929    return notifyInitialContentPainted(
1930      Object.prototype.hasOwnProperty.call(opts, 'slug') ? opts.slug : '',
1931      opts
1932    );
1933  }
1934
1935  function renderLoadFallback(err, options) {
1936    var opts = options && typeof options === 'object' ? options : {};
1937    var consoleLabel = String(opts.consoleLabel || 'Page').trim() || 'Page';
1938    if (err && window.console && typeof window.console.warn === 'function') {
1939      window.console.warn(consoleLabel + ' refresh failed:', err);
1940    }
1941    var state = opts.state && typeof opts.state === 'object' ? opts.state : null;
1942    var contentNode = opts.contentNode || null;
1943    if ((state && state.initialContentPainted) || !contentNode) {
1944      return false;
1945    }
1946    if (hasPaintedManagedContent(contentNode)) {
1947      return notifyInitialContentPainted(opts.slug || '', opts);
1948    }
1949    var fallbackText = String(opts.fallbackText || 'Page content is still loading.');
1950    contentNode.innerHTML = '<p class="placeholder">' + fallbackText
1951      .replace(/&/g, '&amp;')
1952      .replace(/</g, '&lt;')
1953      .replace(/>/g, '&gt;')
1954      .replace(/"/g, '&quot;')
1955      .replace(/'/g, '&#39;') + '</p>';
1956    return notifyInitialContentPainted(opts.slug || '', opts);
1957  }
1958
1959  function loadPublicPageFragment(options) {
1960    var opts = options && typeof options === 'object' ? options : {};
1961    var endpoint = String(opts.endpoint || '').trim();
1962    var contentNode = opts.contentNode || null;
1963    if (!endpoint || !contentNode) {
1964      return Promise.resolve(false);
1965    }
1966
1967    var requestOptions = Object.assign({
1968      cache: 'no-store',
1969      credentials: 'same-origin'
1970    }, opts.requestOptions || {});
1971    var didNotify = false;
1972
1973    function notifyReady() {
1974      if (didNotify) {
1975        return false;
1976      }
1977      didNotify = true;
1978      return notifyInitialContentPainted(opts.slug || '', opts);
1979    }
1980
1981    return fetch(endpoint, requestOptions)
1982      .then(function (res) { return res.text(); })
1983      .then(function (html) {
1984        var rendered = String(html || '').trim();
1985        if (!rendered) {
1986          throw new Error(String(opts.emptyMessage || 'Public page fragment returned no content.'));
1987        }
1988        if (typeof opts.renderFragment === 'function') {
1989          opts.renderFragment(rendered);
1990        } else {
1991          contentNode.innerHTML = rendered;
1992        }
1993        if (typeof opts.afterRender === 'function') {
1994          opts.afterRender(rendered);
1995        }
1996        notifyReady();
1997        return true;
1998      })
1999      .catch(function (err) {
2000        if (typeof opts.afterError === 'function') {
2001          opts.afterError(err);
2002        }
2003        if (renderLoadFallback(err, opts)) {
2004          didNotify = true;
2005        }
2006        return false;
2007      });
2008  }
2009
2010  function renderManagedNostrBootstrapPayload(payload, options) {
2011    var opts = options && typeof options === 'object' ? options : {};
2012    var isExpectedPayload = typeof opts.isExpectedPayload === 'function' ? opts.isExpectedPayload : null;
2013    if (!payload || (isExpectedPayload && !isExpectedPayload(payload))) {
2014      return false;
2015    }
2016    var authenticated = window.__wizardryHasLikelyAuthenticatedSession();
2017    var likelyAdmin = hasLikelyAdminSession();
2018    var optimisticPayload = payload;
2019    if (opts.promoteAuthenticated !== false && !optimisticPayload.is_admin && likelyAdmin) {
2020      optimisticPayload = Object.assign({}, optimisticPayload, { is_admin: true });
2021    }
2022    if (typeof opts.applyState !== 'function') {
2023      return false;
2024    }
2025    opts.applyState(optimisticPayload, payload, authenticated);
2026    var canAdoptStaticPrerender = typeof opts.canAdoptStaticPrerender === 'function'
2027      ? opts.canAdoptStaticPrerender(optimisticPayload, payload, authenticated)
2028      : true;
2029    var matchesStaticPrerender = canAdoptStaticPrerender
2030      && typeof opts.hasMatchingStaticPrerender === 'function'
2031      && opts.hasMatchingStaticPrerender(optimisticPayload, payload, authenticated);
2032    if (matchesStaticPrerender) {
2033      if (typeof opts.renderAdoptedPrerender === 'function') {
2034        opts.renderAdoptedPrerender(optimisticPayload, payload, authenticated);
2035      }
2036      if (typeof opts.afterRender === 'function') {
2037        opts.afterRender(optimisticPayload, payload, authenticated);
2038      }
2039      if (typeof opts.markInitialContentPainted === 'function') {
2040        opts.markInitialContentPainted();
2041      }
2042      return true;
2043    }
2044    if (typeof opts.renderAll !== 'function') {
2045      return false;
2046    }
2047    opts.renderAll(optimisticPayload, payload, authenticated);
2048    if (typeof opts.afterRender === 'function') {
2049      opts.afterRender(optimisticPayload, payload, authenticated);
2050    }
2051    if (typeof opts.markInitialContentPainted === 'function') {
2052      opts.markInitialContentPainted();
2053    }
2054    return true;
2055  }
2056
2057  function renderManagedNostrPageBootstrapPayload(payload, options) {
2058    var opts = options && typeof options === 'object' ? options : {};
2059    var rootNode = opts.rootNode || null;
2060    var contentNode = opts.contentNode || null;
2061    var bootstrapNotify = opts.markInitialContentPainted;
2062    if (!bootstrapNotify && opts.notifyInitialContentPainted && typeof opts.notifyInitialContentPainted === 'object') {
2063      bootstrapNotify = function () {
2064        notifyInitialContentPainted(
2065          Object.prototype.hasOwnProperty.call(opts.notifyInitialContentPainted, 'slug')
2066            ? opts.notifyInitialContentPainted.slug
2067            : '',
2068          opts.notifyInitialContentPainted
2069        );
2070      };
2071    }
2072    if (!bootstrapNotify && opts.notifyInitialContentPainted !== false) {
2073      var shouldSynthesizeNotify = Object.prototype.hasOwnProperty.call(opts, 'state')
2074        || Object.prototype.hasOwnProperty.call(opts, 'rootNode')
2075        || Object.prototype.hasOwnProperty.call(opts, 'loadingClass')
2076        || Object.prototype.hasOwnProperty.call(opts, 'markPageReady')
2077        || Object.prototype.hasOwnProperty.call(opts, 'slug');
2078      if (shouldSynthesizeNotify) {
2079        var notifyOptions = {};
2080        if (Object.prototype.hasOwnProperty.call(opts, 'state')) {
2081          notifyOptions.state = opts.state;
2082        }
2083        if (Object.prototype.hasOwnProperty.call(opts, 'rootNode')) {
2084          notifyOptions.rootNode = opts.rootNode;
2085        }
2086        if (Object.prototype.hasOwnProperty.call(opts, 'loadingClass')) {
2087          notifyOptions.loadingClass = opts.loadingClass;
2088        }
2089        if (Object.prototype.hasOwnProperty.call(opts, 'markPageReady')) {
2090          notifyOptions.markPageReady = opts.markPageReady;
2091        }
2092        if (Object.prototype.hasOwnProperty.call(opts, 'slug')) {
2093          notifyOptions.slug = opts.slug;
2094        }
2095        bootstrapNotify = function () {
2096          notifyInitialContentPainted(
2097            Object.prototype.hasOwnProperty.call(notifyOptions, 'slug') ? notifyOptions.slug : '',
2098            notifyOptions
2099          );
2100        };
2101      }
2102    }
2103    return renderManagedNostrBootstrapPayload(payload, {
2104      isExpectedPayload: opts.isExpectedPayload,
2105      applyState: opts.applyState,
2106      canAdoptStaticPrerender: opts.canAdoptStaticPrerender,
2107      promoteAuthenticated: opts.promoteAuthenticated,
2108      hasMatchingStaticPrerender: typeof opts.hasMatchingStaticPrerender === 'function'
2109        ? opts.hasMatchingStaticPrerender
2110        : function (optimisticPayload) {
2111            return hasMatchingStaticPrerender(rootNode, contentNode, optimisticPayload);
2112          },
2113      renderAdoptedPrerender: typeof opts.renderAdoptedPrerender === 'function'
2114        ? opts.renderAdoptedPrerender
2115        : function () {
2116            if (typeof opts.renderHead === 'function') {
2117              opts.renderHead();
2118            }
2119            if (typeof opts.renderAdmin === 'function') {
2120              opts.renderAdmin();
2121            }
2122            if (typeof opts.renderValidation === 'function') {
2123              opts.renderValidation();
2124            }
2125          },
2126      renderAll: opts.renderAll,
2127      afterRender: opts.afterRender,
2128      markInitialContentPainted: bootstrapNotify
2129    });
2130  }
2131
2132  function renderManagedNostrBootstrapSources(options) {
2133    var opts = options && typeof options === 'object' ? options : {};
2134    var renderPayload = typeof opts.renderPayload === 'function' ? opts.renderPayload : null;
2135    if (!renderPayload) {
2136      return false;
2137    }
2138    var cachedPayload = readBootstrapCache({
2139      storageKey: pageBootstrapCacheKey(opts.slug),
2140      maxAgeMs: opts.maxAgeMs,
2141      authSignature: opts.authSignature || sessionAuthSignature,
2142      isExpectedPayload: opts.isExpectedPayload,
2143      allowRead: opts.allowRead,
2144      clearOnDeny: opts.clearOnDeny
2145    });
2146    if (renderPayload(cachedPayload)) {
2147      return true;
2148    }
2149    var prerenderedPayload = readNostrPageBootstrap(opts.slug, opts.isExpectedPayload);
2150    if (!prerenderedPayload || !renderPayload(prerenderedPayload)) {
2151      return false;
2152    }
2153    writePageBootstrapCache(prerenderedPayload, {
2154      slug: opts.slug,
2155      authSignature: opts.authSignature || sessionAuthSignature,
2156      allowWrite: opts.allowWrite || managedBootstrapAllowWriteForPersistMode(opts.persistMode),
2157      clearOnDeny: opts.clearOnDeny
2158    });
2159    return true;
2160  }
2161
2162  function refreshManagedNostrPage(options) {
2163    var opts = options && typeof options === 'object' ? options : {};
2164    var endpoint = String(opts.endpoint || '/cgi/blog-get-nostr-page').trim() || '/cgi/blog-get-nostr-page';
2165    var slug = String(opts.slug || '').trim();
2166    var requestSlug = Object.prototype.hasOwnProperty.call(opts, 'pageSlug')
2167      ? String(opts.pageSlug || slug).trim()
2168      : slug;
2169    var retryAttempts = Math.max(1, Math.floor(Number(opts.retryAttempts || 1) || 1
2169));
2170    var auth = authPayload();
2171    var params = new URLSearchParams({
2172      page_slug: requestSlug,
2173      session_token: auth.session_token,
2174      csrf_token: auth.csrf_token
2175    });
2176    var extraParams = opts.extraParams && typeof opts.extraParams === 'object' ? opts.extraParams : null;
2177    if (extraParams) {
2178      Object.keys(extraParams).forEach(function (key) {
2179        var name = String(key || '').trim();
2180        if (!name) {
2181          return;
2182        }
2183        var value = extraParams[key];
2184        if (value === undefined || value === null) {
2185          return;
2186        }
2187        params.set(name, String(value));
2188      });
2189    }
2190
2191    function resolveRetryDelayMs(attempt, err) {
2192      if (attempt >= retryAttempts) {
2193        return -1;
2194      }
2195      var configured = opts.retryDelayMs;
2196      if (typeof configured === 'function') {
2197        configured = configured(attempt, err);
2198      }
2199      var delayMs = Number(configured);
2200      if (!isFinite(delayMs) || delayMs < 0) {
2201        delayMs = 0;
2202      }
2203      return delayMs;
2204    }
2205
2206    function fetchManagedPageOnce() {
2207      return fetch(endpoint, {
2208        method: 'POST',
2209        cache: 'no-store',
2210        headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
2211        body: params.toString()
2212      }).then(function (res) {
2213        return res.text().then(function (text) {
2214          var data;
2215          try {
2216            data = JSON.parse(text);
2217          } catch (_err) {
2218            throw new Error('Invalid JSON response');
2219          }
2220          if (!res.ok || !data || data.success === false) {
2221            if (typeof opts.handleFailurePayload === 'function' && opts.handleFailurePayload(data || null, res) === true) {
2222              return null;
2223            }
2224            var err = new Error((data && data.error) || ('Request failed (' + res.status + ')'));
2225            err.code = data && data.code ? String(data.code) : '';
2226            err.payload = data || null;
2227            throw err;
2228          }
2229          return data;
2230        });
2231      }).then(function (payload) {
2232        if (!payload) {
2233          return null;
2234        }
2235        if (typeof opts.isExpectedPayload === 'function' && !opts.isExpectedPayload(payload)) {
2236          throw new Error(String(opts.unexpectedPayloadMessage || 'Unexpected managed page payload'));
2237        }
2238        if (opts.persist !== false) {
2239          writePageBootstrapCache(payload, {
2240            slug: slug || requestSlug,
2241            authSignature: opts.authSignature || sessionAuthSignature,
2242            allowWrite: opts.allowWrite || managedBootstrapAllowWriteForPersistMode(opts.persistMode),
2243            clearOnDeny: opts.clearOnDeny
2244          });
2245        }
2246        if (typeof opts.renderPayload === 'function') {
2247          opts.renderPayload(payload);
2248        }
2249        if (typeof opts.afterRender === 'function') {
2250          opts.afterRender(payload);
2251        }
2252        return payload;
2253      });
2254    }
2255
2256    function fetchManagedPageAttempt(attempt) {
2257      return fetchManagedPageOnce().catch(function (err) {
2258        var delayMs = resolveRetryDelayMs(attempt, err);
2259        if (delayMs >= 0) {
2260          return new Promise(function (resolve) {
2261            window.setTimeout(resolve, delayMs);
2262          }).then(function () {
2263            return fetchManagedPageAttempt(attempt + 1);
2264          });
2265        }
2266        throw err;
2267      });
2268    }
2269
2270    return fetchManagedPageAttempt(1).catch(function (err) {
2271      if (typeof opts.handleError === 'function') {
2272        opts.handleError(err);
2273        return null;
2274      }
2275      if (opts.loadFallback && typeof opts.loadFallback === 'object') {
2276        var fallbackOptions = Object.assign({}, opts.loadFallback);
2277        if (!Object.prototype.hasOwnProperty.call(fallbackOptions, 'slug')) {
2278          fallbackOptions.slug = slug || requestSlug;
2279        }
2280        renderLoadFallback(err, fallbackOptions);
2281        return null;
2282      }
2283      throw err;
2284    }).finally(function () {
2285      if (typeof opts.onFinally === 'function') {
2286        opts.onFinally();
2287        return;
2288      }
2289      if (opts.notifyInitialContentPainted && typeof opts.notifyInitialContentPainted === 'object') {
2290        var notifyOptions = Object.assign({}, opts.notifyInitialContentPainted);
2291        notifyInitialContentPainted(
2292          Object.prototype.hasOwnProperty.call(notifyOptions, 'slug') ? notifyOptions.slug : (slug || requestSlug),
2293          notifyOptions
2294        );
2295      }
2296    });
2297  }
2298
2299  function refreshManagedNostrPageView(options) {
2300    var opts = options && typeof options === 'object' ? options : {};
2301    var refreshOptions = Object.assign({}, opts);
2302    delete refreshOptions.consoleLabel;
2303    delete refreshOptions.state;
2304    delete refreshOptions.contentNode;
2305    delete refreshOptions.fallbackText;
2306    delete refreshOptions.rootNode;
2307    delete refreshOptions.loadingClass;
2308    delete refreshOptions.markPageReady;
2309
2310    if (opts.loadFallback !== false) {
2311      var loadFallback = opts.loadFallback && typeof opts.loadFallback === 'object'
2312        ? Object.assign({}, opts.loadFallback)
2313        : {};
2314      if (!Object.prototype.hasOwnProperty.call(loadFallback, 'consoleLabel') && Object.prototype.hasOwnProperty.call(opts, 'consoleLabel')) {
2315        loadFallback.consoleLabel = opts.consoleLabel;
2316      }
2317      if (!Object.prototype.hasOwnProperty.call(loadFallback, 'state') && Object.prototype.hasOwnProperty.call(opts, 'state')) {
2318        loadFallback.state = opts.state;
2319      }
2320      if (!Object.prototype.hasOwnProperty.call(loadFallback, 'contentNode') && Object.prototype.hasOwnProperty.call(opts, 'contentNode')) {
2321        loadFallback.contentNode = opts.contentNode;
2322      }
2323      if (!Object.prototype.hasOwnProperty.call(loadFallback, 'fallbackText') && Object.prototype.hasOwnProperty.call(opts, 'fallbackText')) {
2324        loadFallback.fallbackText = opts.fallbackText;
2325      }
2326      if (!Object.prototype.hasOwnProperty.call(loadFallback, 'rootNode') && Object.prototype.hasOwnProperty.call(opts, 'rootNode')) {
2327        loadFallback.rootNode = opts.rootNode;
2328      }
2329      if (!Object.prototype.hasOwnProperty.call(loadFallback, 'loadingClass') && Object.prototype.hasOwnProperty.call(opts, 'loadingClass')) {
2330        loadFallback.loadingClass = opts.loadingClass;
2331      }
2332      refreshOptions.loadFallback = loadFallback;
2333    } else {
2334      delete refreshOptions.loadFallback;
2335    }
2336
2337    if (opts.notifyInitialContentPainted !== false) {
2338      var notifyOptions = opts.notifyInitialContentPainted && typeof opts.notifyInitialContentPainted === 'object'
2339        ? Object.assign({}, opts.notifyInitialContentPainted)
2340        : {};
2341      if (!Object.prototype.hasOwnProperty.call(notifyOptions, 'state') && Object.prototype.hasOwnProperty.call(opts, 'state')) {
2342        notifyOptions.state = opts.state;
2343      }
2344      if (!Object.prototype.hasOwnProperty.call(notifyOptions, 'rootNode') && Object.prototype.hasOwnProperty.call(opts, 'rootNode')) {
2345        notifyOptions.rootNode = opts.rootNode;
2346      }
2347      if (!Object.prototype.hasOwnProperty.call(notifyOptions, 'loadingClass') && Object.prototype.hasOwnProperty.call(opts, 'loadingClass')) {
2348        notifyOptions.loadingClass = opts.loadingClass;
2349      }
2350      if (!Object.prototype.hasOwnProperty.call(notifyOptions, 'markPageReady') && Object.prototype.hasOwnProperty.call(opts, 'markPageReady')) {
2351        notifyOptions.markPageReady = opts.markPageReady;
2352      }
2353      refreshOptions.notifyInitialContentPainted = notifyOptions;
2354    } else {
2355      delete refreshOptions.notifyInitialContentPainted;
2356    }
2357
2358    if (
2359      hasPaintedManagedContent(opts.contentNode) &&
2360      refreshOptions.notifyInitialContentPainted &&
2361      typeof refreshOptions.notifyInitialContentPainted === 'object'
2362    ) {
2363      notifyInitialContentPainted(
2364        Object.prototype.hasOwnProperty.call(refreshOptions.notifyInitialContentPainted, 'slug')
2365          ? refreshOptions.notifyInitialContentPainted.slug
2366          : opts.slug,
2367        refreshOptions.notifyInitialContentPainted
2368      );
2369    }
2370
2371    return refreshManagedNostrPage(refreshOptions);
2372  }
2373
2374  function mergeManagedPagePayload(targetPayload, sourcePayload, options) {
2375    var target = targetPayload && typeof targetPayload === 'object' ? targetPayload : null;
2376    var source = sourcePayload && typeof sourcePayload === 'object' ? sourcePayload : null;
2377    var opts = options && typeof options === 'object' ? options : {};
2378    if (!target || !source) {
2379      return target;
2380    }
2381    if (opts.includeState !== false && source.state && typeof source.state === 'object') {
2382      target.state = source.state;
2383    }
2384    if (Object.prototype.hasOwnProperty.call(source, 'sync_status')) {
2385      target.sync_status = source.sync_status;
2386    }
2387    var hasValidationFallback = Object.prototype.hasOwnProperty.call(opts, 'validationFallback');
2388    if (Object.prototype.hasOwnProperty.call(source, 'validation')) {
2389      target.validation = source.validation || (hasValidationFallback ? opts.validationFallback : target.validation);
2390    } else if (hasValidationFallback) {
2391      target.validation = opts.validationFallback;
2392    }
2393    ['canonical_exists', 'draft_exists', 'draft_differs'].forEach(function (fieldName) {
2394      if (Object.prototype.hasOwnProperty.call(source, fieldName)) {
2395        target[fieldName] = !!source[fieldName];
2396      }
2397    });
2398    ['prerender', 'prerender_signature'].forEach(function (fieldName) {
2399      if (Object.prototype.hasOwnProperty.call(source, fieldName)) {
2400        target[fieldName] = source[fieldName];
2401      }
2402    });
2403    var passthroughFields = Array.isArray(opts.passthroughFields) ? opts.passthroughFields : [];
2404    passthroughFields.forEach(function (fieldName) {
2405      if (!fieldName || !Object.prototype.hasOwnProperty.call(source, fieldName)) {
2406        return;
2407      }
2408      target[fieldName] = source[fieldName];
2409    });
2410    return target;
2411  }
2412
2413  function postFormJson(url, payload, options) {
2414    var opts = options && typeof options === 'object' ? options : {};
2415    var body = new URLSearchParams(payload || {});
2416    return fetch(String(url || ''), {
2417      method: 'POST',
2418      cache: 'no-store',
2419      headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
2420      body: body.toString()
2421    }).then(function (res) {
2422      return res.text().then(function (text) {
2423        var data;
2424        try {
2425          data = JSON.parse(text);
2426        } catch (_err) {
2427          throw new Error(String(opts.invalidJsonMessage || 'Invalid JSON response'));
2428        }
2429        if (!res.ok || !data || data.success === false) {
2430          var err = new Error((data && data.error) || ('Request failed (' + res.status + ')'));
2431          err.code = data && data.code ? String(data.code) : '';
2432          err.payload = data || null;
2433          throw err;
2434        }
2435        return data;
2436      });
2437    });
2438  }
2439
2440  function showRouteLoadFailure() {
2441    var mainContainer = document.querySelector('main');
2442    var nav = document.querySelector('nav.site-nav');
2443    var body = document.body;
2444    var parent = mainContainer || (nav && nav.parentNode) || body;
2445    if (!parent) {
2446      return;
2447    }
2448    var existing = document.getElementById('route-load-failure');
2449    if (existing && existing.parentNode) {
2450      existing.parentNode.removeChild(existing);
2451    }
2452    var panel = document.createElement('section');
2453    panel.id = 'route-load-failure';
2454    panel.className = 'route-load-failure';
2455    panel.innerHTML = '<h1>Page is still loading.</h1><p>Try refreshing in a moment.</p>';
2456    if (mainContainer) {
2457      mainContainer.insertBefore(panel, mainContainer.firstChild || null);
2458    } else if (nav && nav.parentNode) {
2459      nav.insertAdjacentElement('afterend', panel);
2460    } else {
2461      body.insertBefore(panel, body.firstChild || null);
2462    }
2463    forceHydrationReveal();
2464  }
2465
2466  function cancelRouteLoadFailure() {
2467    if (routeFailureTimer) {
2468      window.clearTimeout(routeFailureTimer);
2469      routeFailureTimer = 0;
2470    }
2471    var existing = document.getElementById('route-load-failure');
2472    if (existing && existing.parentNode) {
2473      existing.parentNode.removeChild(existing);
2474    }
2475  }
2476
2477  function scheduleRouteLoadFailure() {
2478    cancelRouteLoadFailure();
2479    routeFailureTimer = window.setTimeout(function () {
2480      routeFailureTimer = 0;
2481      if (!pageInitialContentReady) {
2482        showRouteLoadFailure();
2483      }
2484    }, 2200);
2485  }
2486
2487  function clearManagedRouteParams(url, options) {
2488    var opts = options && typeof options === 'object' ? options : {};
2489    if (!url || typeof url !== 'object' || !url.searchParams) {
2490      return false;
2491    }
2492    if (opts.removeRefresh !== false) {
2493      url.searchParams.delete(ROUTE_REFRESH_PARAM);
2494    }
2495    if (opts.removeRepair !== false) {
2496      url.searchParams.delete(ROUTE_REPAIR_PARAM);
2497    }
2498    if (!window.history || typeof window.history.replaceState !== 'function') {
2499      return false;
2500    }
2501    var next = url.pathname;
2502    var query = url.searchParams.toString();
2503    if (query) {
2504      next += '?' + query;
2505    }
2506    if (url.hash) {
2507      next += url.hash;
2508    }
2509    window.history.replaceState(null, '', next);
2510    return true;
2511  }
2512
2513  function themeFromConfig() {
2514    var theme = 'lapidarist';
2515    try {
2516      var bootstrap = window.__wizardrySiteBootstrap || {};
2517      var config = bootstrap && bootstrap.config && typeof bootstrap.config === 'object' ? bootstrap.config : {};
2518      var hasConfiguredTheme = Object.prototype.hasOwnProperty.call(config, 'theme');
2519      var cachedTheme = hasConfiguredTheme ? '' : (localStorage.getItem('wizardry_blog_theme_v1') || '');
2520      var nextTheme = String(hasConfiguredTheme ? config.theme : cachedTheme).trim();
2521      if (nextTheme) {
2522        theme = nextTheme;
2523      }
2524    } catch (_err) {
2525      // Ignore storage failures.
2526    }
2527    return theme;
2528  }
2529
2530  function themeStylesheetVersion() {
2531    return String(window.__wizardryThemeStylesheetVersion || '20260622-lapidarist-restore1');
2532  }
2533
2534  function reconcileThemeLink() {
2535    var theme = themeFromConfig();
2536    var href = '/static/themes/' + encodeURIComponent(theme) + '.css?v=' + encodeURIComponent(themeStylesheetVersion());
2537    var link = document.getElementById('theme-stylesheet');
2538    if (!link) {
2539      link = document.createElement('link');
2540      link.id = 'theme-stylesheet';
2541      link.rel = 'stylesheet';
2542      (document.head || document.documentElement).appendChild(link);
2543    }
2544    var currentHref = String(link.getAttribute('data-theme-href') || link.getAttribute('href') || '').trim();
2545    if (currentHref !== href) {
2546      var preloader = document.createElement('link');
2547      preloader.rel = 'stylesheet';
2548      preloader.href = href;
2549      preloader.media = 'not all';
2550      preloader.setAttribute('data-theme-preload', 'true');
2551      var committed = false;
2552      function commit() {
2553        if (committed) {
2554          return;
2555        }
2556        committed = true;
2557        link.setAttribute('href', href);
2558        if (preloader.parentNode) {
2559          preloader.parentNode.removeChild(preloader);
2560        }
2561      }
2562      preloader.addEventListener('load', commit, { once: true });
2563      preloader.addEventListener('error', commit, { once: true });
2564      (link.parentNode || document.head || document.documentElement).appendChild(preloader);
2565      window.setTimeout(commit, 1500);
2566    }
2567    link.setAttribute('data-theme-href', href);
2568  }
2569
2570  window.__wizardryNotifyInitialContentPainted = notifyInitialContentPainted;
2571  window.__wizardryNotifyCurrentManagedPageReady = notifyCurrentManagedPageReady;
2572  window.__wizardryLoadPublicPageFragment = loadPublicPageFragment;
2573  window.__wizardryRenderManagedNostrPageBootstrapPayload = renderManagedNostrPageBootstrapPayload;
2574  window.__wizardryRemoveLegacyTitleBlock = removeLegacyTitleBlock;
2575  window.__wizardryRenderManagedPageHeadForPage = renderManagedPageHeadForPage;
2576  window.__wizardryRenderManagedPageHead = renderManagedPageHead;
2577  window.__wizardryHandleManagedNavbarTitleAction = handleManagedNavbarTitleAction;
2578  window.__wizardryRenderManagedPayloadValidationSummary = renderManagedPayloadValidationSummary;
2579  window.__wizardryRenderManagedSaveStatus = renderManagedSaveStatus;
2580  window.__wizardryRenderManagedAdminActionBar = renderManagedAdminActionBar;
2581  window.__wizardryStartManagedNavbarTitleEditForPage = startManagedNavbarTitleEditForPage;
2582  window.__wizardrySaveManagedNavbarTitleForPage = saveManagedNavbarTitleForPage;
2583  window.__wizardryResolveRootAttributeFallbackText = resolveRootAttributeFallbackText;
2584  window.__wizardryResetManagedNavbarTitleState = resetManagedNavbarTitleState;
2585  window.__wizardryRenderResolvedReadOnlyContent = renderResolvedReadOnlyContent;
2586  window.__wizardryStripLegacyNostrSyncPills = stripLegacyNostrSyncPills;
2587  window.__wizardryAuthPayload = authPayload;
2588  window.__wizardrySessionAuthSignature = sessionAuthSignature;
2589  window.__wizardryViewerAuthSignature = viewerAuthSignature;
2590  window.__wizardryBindSessionAuthRefresh = bindSessionAuthRefresh;
2591  window.__wizardryHasLikelyAuthenticatedSession = hasLikelyAuthenticatedSession;
2592  window.__wizardryAuthEventIsLikelyAdmin = authEventIsLikelyAdmin;
2593  window.__wizardryCanUseVisitorPrerenderReadOnly = canUseVisitorPrerenderReadOnly;
2594  window.__wizardryCanUsePayloadPrerenderReadOnly = canUsePayloadPrerenderReadOnly;
2595  window.__wizardryEnsureNostrPublishDialog = ensureNostrPublishDialog;
2596  window.__wizardryEnsureManagedMarkdownParser = ensureManagedMarkdownParser;
2597  window.__wizardryRenderManagedMarkdownInline = renderManagedMarkdownInline;
2598  window.__wizardryRenderManagedMarkdownInlineLinkFallback = renderManagedMarkdownInlineLinkFallback;
2599  window.__wizardryRenderManagedMarkdownBlock = renderManagedMarkdownBlock;
2600  window.__wizardryManagedSlugFromPath = slugFromPath;
2601  window.__wizardryRenderManagedNostrBootstrapSources = renderManagedNostrBootstrapSources;
2602  window.__wizardryRefreshManagedNostrPage = refreshManagedNostrPage;
2603  window.__wizardryRefreshManagedNostrPageView = refreshManagedNostrPageView;
2604  window.__wizardryCommitManagedPagePayload = commitManagedPagePayload;
2605  window.__wizardryReconcileManagedPageRefreshRender = reconcileManagedPageRefreshRender;
2606  window.__wizardryPostFormJson = postFormJson;
2607
2608  window.__wizardrySetPageTitleConfig = function (options) {
2609    var opts = options && typeof options === 'object' ? options : {};
2610    var overrides = {};
2611    if (Object.prototype.hasOwnProperty.call(opts, 'siteTitle')) {
2612      var normalizedSiteTitle = normalizeSiteTitle(opts.siteTitle);
2613      overrides.siteTitle = normalizedSiteTitle;
2614      try {
2615        localStorage.setItem(SITE_TITLE_CACHE_KEY, normalizedSiteTitle);
2616      } catch (_err) {
2617        // Ignore storage failures.
2618      }
2619    }
2620    if (Object.prototype.hasOwnProperty.call(opts, 'appendSiteTitle')) {
2621      var enabled = normalizeAppendSiteTitleEnabled(opts.appendSiteTitle);
2622      overrides.appendSiteTitle = enabled;
2623      try {
2624        localStorage.setItem(APPEND_SITE_TITLE_CACHE_KEY, enabled ? '1' : '0');
2625      } catch (_err) {
2626        // Ignore storage failures.
2627      }
2628    }
2629    return applyPageTitle(
2630      Object.prototype.hasOwnProperty.call(opts, 'baseTitle') ? opts.baseTitle : undefined,
2631      overrides
2632    );
2633  };
2634
2635  reconcileThemeLink();
2636  applyPageTitle(document.title);
2637
2638  var canonical = document.createElement('link');
2639  canonical.rel = 'canonical';
2640  canonical.href = window.location.origin + window.location.pathname;
2641  document.head.appendChild(canonical);
2642
2643  var ogUrl = document.createElement('meta');
2644  ogUrl.setAttribute('property', 'og:url');
2645  ogUrl.setAttribute('content', canonical.href);
2646  document.head.appendChild(ogUrl);
2647
2648  document.addEventListener('DOMContentLoaded', function () {
2649    var firstHeading = document.querySelector('h1[id]') || document.querySelector('h1');
2650    if (firstHeading && !firstHeading.id) {
2651      firstHeading.id = 'main-content';
2652    }
2653
2654    try {
2655      var currentUrl = new URL(window.location.href);
2656      var expectedSlug = slugFromPath(currentUrl.pathname || '/');
2657      var rootSlug = routeRootSlugFromDom();
2658      var hasRefreshParam = currentUrl.searchParams.get(ROUTE_REFRESH_PARAM) === '1';
2659      var hasRepairParam = currentUrl.searchParams.get(ROUTE_REPAIR_PARAM) === '1';
2660      if (expectedSlug && rootSlug && !slugsEquivalent(expectedSlug, rootSlug)) {
2661        if (!hasRefreshParam) {
2662          currentUrl.searchParams.set(ROUTE_REFRESH_PARAM, '1');
2663          window.location.replace(currentUrl.toString());
2664          return;
2665        }
2666        scheduleRouteLoadFailure();
2667        return;
2668      }
2669      if ((hasRefreshParam || hasRepairParam) && window.history && typeof window.history.replaceState === 'function') {
2670        clearManagedRouteParams(currentUrl);
2671      }
2672    } catch (_routeErr) {
2673      // Ignore URL parsing/runtime failures.
2674    }
2675  });
2676
2677  window.addEventListener('blog-page-initial-content-ready', function () {
2678    cancelRouteLoadFailure();
2679  });
2680})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.