PageSourceSearch

https://andersaamodt.com/checkout

html andersaamodt.com collected 2026-10-08 10:31:18 UTC 39,818 bytes, 998 lines download raw bytes

1<!DOCTYPE html>
2<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
3<head>
4  <meta charset="utf-8" />
5  <meta name="generator" content="pandoc" />
6  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
7  <meta name="author" content="author" />
8  <title>Checkout</title>
9  <style>
10    code{white-space: pre-wrap;}
11    span.smallcaps{font-variant: small-caps;}
12    span.underline{text-decoration: underline;}
13    div.column{display: inline-block; vertical-align: top; width: 50%;}
14    div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
15    ul.task-list{list-style: none;}
16    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
17  </style>
18  <link rel="stylesheet" href="/static/style.css?v=1376469157" />
19  
19<script defer src="/static/js/htmx.min.js?v=1376469157"></script>
19
20  
20<script defer src="/static/js/idiomorph-ext.min.js?v=1376469157"></script>
20
21  
21<script>
22  (function () {
23    try {
24      var host = window.location.hostname || '';
25      var path = window.location.pathname || '';
26      if (path === '/artificer' || path.indexOf('/artificer/') === 0) {
27        document.documentElement.classList.add('artificer-web-route');
28      }
29    } catch (_err) {
30      // Ignore early route detection failures.
31    }
32  })();
33  </script>
33
34  <style id="private-app-route-guard">
35  html.artificer-web-route,
36  html.artificer-web-route body {
37    background: #111418 !important;
38  }
39
40  html.artificer-web-route nav.site-nav,
41  html.artificer-web-route footer.site-footer,
42  html.artificer-web-route #title-block-header {
43    display: none !important;
44  }
45
46  html.artificer-web-route body,
47  html.artificer-web-route main,
48  html.artificer-web-route .page,
49  html.artificer-web-route .content {
50    margin: 0 !important;
51    max-width: none !important;
52    padding: 0 !important;
53  }
54
55  </style>
56  
56<script src="/static/site-bootstrap.js?v=1376469157"></script>
56
57  
57<script>
58  (function () {
59    window.__wizardryThemeStylesheetVersion = '20260622-lapidarist-restore1';
60    var theme = 'lapidarist';
61    try {
62      var bootstrap = window.__wizardrySiteBootstrap || {};
63      var config = bootstrap && bootstrap.config && typeof bootstrap.config === 'object' ? bootstrap.config : {};
64      var hasConfiguredTheme = Object.prototype.hasOwnProperty.call(config, 'theme');
65      var cachedTheme = hasConfiguredTheme ? '' : (localStorage.getItem('wizardry_blog_theme_v1') || '');
66      var nextTheme = String(hasConfiguredTheme ? config.theme : cachedTheme).trim();
67      var routeSlug = String(window.location.pathname || '').replace(/^\/+/, '').split('/')[0].replace(/\.html?$/i, '');
68      var publicationThemes = config.publication_themes && typeof config.publication_themes === 'object' ? config.publication_themes : {};
69      if (routeSlug && publicationThemes[routeSlug]) {
70        nextTheme = String(publicationThemes[routeSlug]).trim();
71      }
72      if (nextTheme) {
73        theme = nextTheme;
74      }
75    } catch (_err) {
76      // Ignore storage failures.
77    }
78    var href = '/static/themes/' + encodeURIComponent(theme) + '.css?v=' + encodeURIComponent(window.__wizardryThemeStylesheetVersion);
79    var markup = '<link id="theme-stylesheet" rel="stylesheet" href="' + href + '" data-theme-href="' + href + '">';
80    if (document.readyState === 'loading' && typeof document.write === 'function') {
81      document.write(markup);
82      return;
83    }
84    var link = document.createElement('link');
85    link.id = 'theme-stylesheet';
86    link.rel = 'stylesheet';
87    link.href = href;
88    link.setAttribute('data-theme-href', href);
89    (document.head || document.documentElement).appendChild(link);
90  })();
91  </script>
91
92  <noscript><link id="theme-stylesheet" rel="stylesheet" href="/static/themes/lapidarist.css?v=1376469157" data-theme-href="/static/themes/lapidarist.css?v=1376469157" /></noscript>
93  <style id="blog-tag-recovery-style">
94  html body .blog-post-item .tag,
95  html body .blog-post-item .tag:hover,
96  html body .blog-post-item .tag:focus-visible,
97  html body .blog-post-item .blog-type-pill,
98  html body .blog-post-item .blog-type-pill:hover,
99  html body .blog-post-item .blog-type-pill:focus-visible,
100  html body .blog-post-item .blog-year-pill,
101  html body .blog-post-item .blog-year-pill:hover,
102  html body .blog-post-item .blog-year-pill:focus-visible {
103    --lapidarist-control-shadow: none;
104    --action-soft-shadow: none;
105    --action-soft-hover-shadow: none;
106    box-shadow: none !important;
107    -webkit-box-shadow: none !important;
108    filter: none !important;
109    -webkit-filter: none !important;
110    text-shadow: none !important;
111  }
112
113  html body .blog-post-item :is(a, button).blog-type-pill,
114  html body .blog-post-item :is(a, button).blog-type-pill:hover,
115  html body .blog-post-item :is(a, button).blog-type-pill:focus-visible,
116  html body .post-single-item :is(a, button).blog-type-pill,
117  html body .post-single-item :is(a, button).blog-type-pill:hover,
118  html body .post-single-item :is(a, button).blog-type-pill:focus-visible {
119    border-color: var(--post-tag-type-border) !important;
120    background: var(--post-tag-type-bg) !important;
121    background-color: var(--post-tag-type-bg) !important;
122    color: var(--post-tag-type-text) !important;
123    -webkit-text-fill-color: var(--post-tag-type-text) !important;
124  }
125
126  html body .blog-post-item :is(a, button).blog-year-pill,
127  html body .blog-post-item :is(a, button).blog-year-pill:hover,
128  html body .blog-post-item :is(a, button).blog-year-pill:focus-visible,
129  html body .post-single-item :is(a, button).blog-year-pill,
130  html body .post-single-item :is(a, button).blog-year-pill:hover,
131  html body .post-single-item :is(a, button).blog-year-pill:focus-visible {
132    border-color: var(--post-tag-year-border) !important;
133    background: var(--post-tag-year-bg) !important;
134    background-color: var(--post-tag-year-bg) !important;
135    color: var(--post-tag-year-text) !important;
136    -webkit-text-fill-color: var(--post-tag-year-text) !important;
137  }
138
139  </style>
140  <!-- Page bundles in the body call these shared helpers during initialization. -->
141  
141<script src="/static/page-head.js?v=1376469157"></script>
141
142  
142<script defer src="/static/zap-ui.js?v=1376469157"></script>
142
143  
143<script defer src="/static/post-context.js?v=1376469157"></script>
143
144  <link id="rss-alternate" rel="alternate" type="application/rss+xml" title="RSS Feed" href="/rss.xml" />
145  <link id="atom-alternate" rel="alternate" type="application/atom+xml" title="Atom Feed" href="/atom.xml" />
146  
146<script>
147  (function () {
148    var config = (window.__wizardrySiteBootstrap || {}).config || {};
149    var slug = String(window.location.pathname || '').replace(/^\/+/, '').split('/')[0].replace(/\.html?$/i, '');
150    if (!slug || !Array.isArray(config.publication_slugs) || config.publication_slugs.indexOf(slug) < 0) return;
151    var rss = document.getElementById('rss-alternate');
152    var atom = document.getElementById('atom-alternate');
153    if (rss) rss.href = '/' + slug + '/rss.xml';
154    if (atom) atom.href = '/' + slug + '/atom.xml';
155  })();
156  </script>
156
157  <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0" />
158  <meta http-equiv="Pragma" content="no-cache" />
159  <meta http-equiv="Expires" content="0" />
160  <meta name="description" content="Nostr-enabled blog template" />
161  <meta property="og:site_name" content="gazeta" />
162  <meta property="og:type" content="website" />
163  <meta name="twitter:card" content="summary_large_image" />
164</head>
165<body>
166<script type="module">
167(function () {
168  var docEl = document.documentElement;
169  var navReady = false;
170  var pageReady = false;
171  var revealed = false;
172
173  function hasDynamicPageRoot() {
174    return !!(
175      document.getElementById('blog-page-root') ||
176      document.getElementById('nip23-page-root') ||
177      document.getElementById('list-page-root') ||
178      document.getElementById('public-ranking-root') ||
179      document.getElementById('overworld-page-root') ||
180      document.getElementById('contact-page-root') ||
181      document.getElementById('archive-page-root') ||
182      document.getElementById('tags-page-root') ||
183      document.getElementById('search-page-root') ||
184      document.getElementById('admin-panel')
185    );
186  }
187
188  function reveal() {
189    if (revealed) {
190      return;
191    }
192    revealed = true;
193    if (docEl) {
194      docEl.classList.remove('app-hydrating');
195    }
196  }
197
198  function maybeReveal() {
199    if (navReady && pageReady) {
200      reveal();
201    }
202  }
203
204  window.__wizardryHydration = {
205    markNavReady: function () {
206      navReady = true;
207      maybeReveal();
208    },
209    markPageReady: function () {
210      pageReady = true;
211      maybeReveal();
212    },
213    forceReveal: reveal
214  };
215
216  setTimeout(function () {
217    reveal();
218  }, 6000);
219})();
220</script>
220
221<a class="skip-link" href="#main-content">Skip to content</a>
222<script>
223(function () {
224  var docEl = document.documentElement;
225  if (docEl && docEl.classList.contains('app-hydrating')) {
226    docEl.classList.add('nav-overflow-booting');
227  }
228})();
229</script>
229
230<nav class="site-nav">
231<a id="nav-site-signature" class="nav-site-signature" href="/">Site</a>
232<div class="nav-center">
233<a href="/" data-page="index" data-nav-rank="1">Writing</a>
234<a href="/blog" data-page="blog" data-nav-rank="2">Blog</a>
235<a href="/oeuvre" data-page="oeuvre" data-nav-rank="3">Oeuvre</a>
236<a href="/projects" data-page="projects" data-nav-rank="4">Projects</a>
237<a href="/reading-list" data-page="reading-list" data-nav-rank="5">Reading list</a>
238<a href="/contact" data-page="contact" data-nav-rank="6">Contact</a>
239<a href="/overworld" data-page="overworld" data-nav-rank="7">Overworld</a>
240<div class="nav-overflow-menu" id="nav-overflow-menu" hidden>
241  <button class="nav-menu-btn nav-overflow-btn" id="nav-overflow-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="More pages">
242    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
243      <path d="M3 4.25H13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
244      <path d="M3 8H13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
245      <path d="M3 11.75H13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
246    </svg>
247    <span class="nav-overflow-count" id="nav-overflow-count" hidden>0</span>
248  </button>
249  <div class="nav-menu-panel nav-overflow-panel" id="nav-overflow-panel" role="menu" hidden></div>
250</div>
251</div>
252<div class="nav-right">
253<form class="nav-search" method="get" action="/search">
254<input type="text" name="q" placeholder="Search..." />
255<button type="submit" aria-label="Search">
256<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
257<circle cx="7" cy="7" r="5.5" stroke="currentColor" stroke-width="1.9"/>
258<path d="M11 11L14.5 14.5" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/>
259</svg>
260</button>
261</form>
262<div class="nav-compose-tools" id="nav-compose-tools" style="display:none;">
263<a href="/admin#compose" class="nav-compose nav-compose-icon" aria-label="Compose post" title="Compose post">
264<!-- Icon is replaced by nav-auth.js -->
265<svg width="21" height="21" viewBox="0 0 24 24" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
266<path fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" d="M4 20h4l10-10-4-4L4 16v4zM13 7l4 4"/>
267</svg>
268</a>
269</div>
270<button id="nav-cart-toggle" class="nav-cart-toggle" type="button" aria-label="Open cart" aria-expanded="false" hidden>
271<svg width="19" height="19" viewBox="0 0 24 24" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
272<path d="M3 4H5L7 16H18L21 7H6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
273<circle cx="9" cy="20" r="1.7" fill="currentColor"/>
274<circle cx="17" cy="20" r="1.7" fill="currentColor"/>
275</svg>
276<span id="nav-cart-count" class="nav-cart-count" hidden>0</span>
277</button>
278<a id="nav-user-name" class="nav-username" href="/admin#account" style="display:none;"></a>
279<div class="nav-user-menu" id="nav-user-menu" style="display:none;">
280  <button class="nav-menu-btn" id="nav-menu-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="User menu"><svg class="overflow-menu-icon-svg" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="5.5" r="1.9" fill="currentColor"/><circle cx="12" cy="12" r="1.9" fill="currentColor"/><circle cx="12" cy="18.5" r="1.9" fill="currentColor"/></svg></button>
281  <div class="nav-menu-panel" id="nav-menu-panel" role="menu" hidden>
282    <a id="nav-menu-primary-link" class="nav-menu-item" href="/admin" role="menuitem">Admin</a>
283    <div class="nav-menu-logout-row" id="nav-menu-logout-row">
284      <button id="nav-menu-logout" class="nav-menu-item nav-menu-item-danger" type="button" role="menuitem">Logout</button>
285      <button id="nav-menu-logout-more" class="nav-menu-logout-more" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="More logout actions" title="More logout actions" style="display:none;"><svg class="overflow-menu-icon-svg" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewB
285ox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="5.5" r="1.9" fill="currentColor"/><circle cx="12" cy="12" r="1.9" fill="currentColor"/><circle cx="12" cy="18.5" r="1.9" fill="currentColor"/></svg></button>
286      <div class="nav-menu-logout-submenu" id="nav-menu-logout-submenu" role="menu" hidden>
287        <button id="nav-menu-logout-everywhere" class="nav-menu-item" type="button" role="menuitem" style="display:none;">Log out other sessions</button>
288      </div>
289    </div>
290  </div>
291</div>
292<div class="nav-login-split" id="nav-login-split" style="display:none;">
293  <button class="btn-login btn-login-main" id="login-btn" type="button">Login</button>
294  <button class="btn-login btn-login-caret" id="login-more-btn" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="More login options">▼</button>
295  <div class="nav-login-menu" id="nav-login-menu" role="menu" hidden>
296    <button id="login-menu-register" class="nav-menu-item" type="button" role="menuitem">Use browser signer...</button>
297    <button id="login-menu-phone" class="nav-menu-item" type="button" role="menuitem">Use phone signer (QR)</button>
298    <button id="login-menu-manual" class="nav-menu-item" type="button" role="menuitem">Advanced...</button>
299    <button id="login-menu-learn" class="nav-menu-item" type="button" role="menuitem">Learn about Nostr sign-in</button>
300  </div>
301</div>
302</div>
303</nav>
304<script>
305(function () {
306  function seedInitialOverflowMenu() {
307    var docEl = document.documentElement;
308    if (!docEl || !docEl.classList.contains('app-hydrating')) {
309      return;
310    }
311    try {
312      seedInitialOverflowMenuNow();
313    } finally {
314      docEl.classList.remove('nav-overflow-booting');
315    }
316  }
317
318  function seedInitialOverflowMenuNow() {
319    var navCenter = document.querySelector('nav.site-nav .nav-center');
320    var navRight = document.querySelector('nav.site-nav .nav-right');
321    var menu = document.getElementById('nav-overflow-menu');
322    var button = document.getElementById('nav-overflow-btn');
323    var count = document.getElementById('nav-overflow-count');
324    var panel = document.getElementById('nav-overflow-panel');
325    if (!navCenter || !menu || !button || !count || !panel) {
326      return;
327    }
328
329    function esc(text) {
330      return String(text || '')
331        .replace(/&/g, '&amp;')
332        .replace(/</g, '&lt;')
333        .replace(/>/g, '&gt;')
334        .replace(/"/g, '&quot;')
335        .replace(/'/g, '&#39;');
336    }
337
338    function normalizeNavPath(path) {
339      var p = String(path || '').trim();
340      if (!p) {
341        return '/';
342      }
343      if (p.indexOf('http://') === 0 || p.indexOf('https://') === 0) {
344        try {
345          p = new URL(p, window.location.href).pathname || '/';
346        } catch (_urlErr) {
347          p = '/';
348        }
349      }
350      p = p.split('?', 1)[0].replace(/\/+$/, '') || '/';
351      if (p.indexOf('/pages/') === 0) {
352        p = '/' + p.slice('/pages/'.length).replace(/\.html?$/i, '');
353      }
354      return p || '/';
355    }
356
357    function initialNavbarPages() {
358      var bootstrap = window.__wizardrySiteBootstrap;
359      if (bootstrap && Array.isArray(bootstrap.navbar_pages) && bootstrap.navbar_pages.length) {
360        return bootstrap.navbar_pages;
361      }
362      try {
363        var cached = JSON.parse(localStorage.getItem('cached_navbar_pages_v1') || '[]');
364        if (Array.isArray(cached) && cached.length) {
365          return cached;
366        }
367      } catch (_cacheErr) {
368        // Ignore invalid cached navbar rows.
369      }
370      return null;
371    }
372
373    function renderInitialNavbarPages() {
374      var pages = initialNavbarPages();
375      if (!pages || !pages.length) {
376        return;
377      }
378      var current = normalizeNavPath(window.location.pathname);
379      var seen = {};
380      var html = '';
381      pages.forEach(function (page, index) {
382        var slug = String(page && page.slug || '').trim();
383        var title = String(page && page.title || '').trim();
384        var path = String(page && page.path || '').trim();
385        if (!slug || !path || seen[slug]) {
386          return;
387        }
388        seen[slug] = true;
389        var active = normalizeNavPath(path) === current;
390        html += '<a href="' + esc(path) + '" data-page="' + esc(slug) + '" data-nav-rank="' + String(index + 1) + '"' + (active ? ' class="active" aria-current="page"' : '') + '>' + esc(title || slug) + '</a>';
391      });
392      if (!html) {
393        return;
394      }
395      navCenter.innerHTML = html;
396      navCenter.appendChild(menu);
397    }
398
399    renderInitialNavbarPages();
400
401    var links = Array.prototype.slice.call(navCenter.querySelectorAll('a[data-page][href]'));
402    if (!links.length) {
403      return;
404    }
405
406    function rectVisible(rect) {
407      return !!rect && rect.width > 0 && rect.height > 0;
408    }
409
410    function rectsVerticallyOverlap(a, b) {
411      return !!(a && b && a.bottom > b.top && b.bottom > a.top);
412    }
413
414    function rightmostVisibleLinkRect() {
415      for (var idx = links.length - 1; idx >= 0; idx -= 1) {
416        var link = links[idx];
417        if (link.classList.contains('is-nav-overflow-hidden')) {
418          continue;
419        }
420        var rect = link.getBoundingClientRect();
421        if (rectVisible(rect)) {
422          return rect;
423        }
424      }
425      return null;
426    }
427
428    function navCollisionLeft() {
429      if (!navRight) {
430        return null;
431      }
432      var search = navRight.querySelector('.nav-search');
433      var target = search && !search.hidden ? search : navRight;
434      var rect = target.getBoundingClientRect();
435      if (!rectVisible(rect)) {
436        return null;
437      }
438      return rect.left;
439    }
440
441    function hasRightSideCollision() {
442      var linkRect = rightmostVisibleLinkRect();
443      var collisionLeft = navCollisionLeft();
444      if (!linkRect || collisionLeft === null) {
445        return false;
446      }
447      var centerRect = navCenter.getBoundingClientRect();
448      var rightRect = navRight ? navRight.getBoundingClientRect() : null;
449      if (!rectsVerticallyOverlap(centerRect, rightRect)) {
450        return false;
451      }
452      return linkRect.right > (collisionLeft - 8);
453    }
454
455    function hasNavPressure() {
456      return navCenter.scrollWidth > (navCenter.clientWidth + 1) || hasRightSideCollision();
457    }
458
459    links.forEach(function (link) {
460      link.classList.remove('is-nav-overflow-hidden');
461    });
462    menu.hidden = true;
463    panel.innerHTML = '';
464
465    var useMobileOverflowTier = !!(window.matchMedia && window.matchMedia('(max-width: 780px)').matches);
466    if (useMobileOverflowTier) {
467      links.forEach(function (link) {
468        var rank = Number(link.getAttribute('data-nav-rank') || 0);
469        if (rank >= 6) {
470          link.classList.add('is-nav-overflow-hidden');
471        }
472      });
473    }
474
475    var activeLink = links.find(function (link) {
476      return link.classList.contains('active') || link.getAttribute('aria-current') === 'page';
477    }) || null;
478    if (hasNavPressure()) {
479      menu.hidden = false;
480      var guard = 0;
481      while (hasNavPressure() && guard < links.length) {
482        var hide = null;
483        for (var i = links.length - 1; i >= 0; i -= 1) {
484          if (links[i].classList.contains('is-nav-overflow-hidden')) {
485            continue;
486          }
487          if (activeLink && links[i] === activeLink) {
488            continue;
489          }
490          hide = links[i];
491          break;
492        }
493        if (!hide && activeLink && !activeLink.classList.contains('is-nav-overflow-hidden')) {
494          hide = activeLink;
495        }
496        if (!hide) {
497          break;
498        }
499        hide.classList.add('is-nav-overflow-hidden');
500        guard += 1;
501      }
502    }
503
504    var hiddenLinks = links.filter(function (link) {
505      return link.classList.contains('is-nav-overflow-hidden');
506    });
507    if (!hiddenLinks.length) {
508      count.textContent = '0';
509      count.hidden = true;
510      button.setAttribute('aria-label', 'More pages');
511      menu.hidden = true;
512      return;
513    }
514
515    panel.innerHTML = '';
516    hiddenLinks.forEach(function (link) {
517      var item = document.createElement('a');
518      item.className = 'nav-menu-item';
519      item.setAttribute('role', 'menuitem');
520      item.href = link.getAttribute('href') || '/';
521      item.textContent = String(link.textContent || '').trim() || 'Page';
522      panel.appendChild(item);
523    });
524    count.textContent = String(hiddenLinks.length);
525    count.hidden = false;
526    button.setAttribute('aria-label', 'More pages (' + String(hiddenLinks.length) + ' hidden)');
527    menu.hidden = false;
528  }
529
530  seedInitialOverflowMenu();
531})();
532</script>
vendor: 1 bytes, line 532
532
533<script type="module">
534(function () {
535  function setupExpandableSearch() {
536    var forms = document.querySelectorAll('form.nav-search');
537    for (var i = 0; i < forms.length; i += 1) {
538      (function (form) {
539        if (!form || form.getAttribute('data-expandable-search-ready') === 'true') {
540          return;
541        }
542        form.setAttribute('data-expandable-search-ready', 'true');
543        var input = form.querySelector('input[type="text"]');
544        var button = form.querySelector('button[type="submit"], button:not([type])');
545        if (!input || !button) {
546          return;
547        }
548
549        function hasValue() {
550          return String(input.value || '').trim().length > 0;
551        }
552
553        function setExpanded(expanded) {
554          var nav = form.closest ? form.closest('nav.site-nav') : null;
555          var nextExpanded = !!expanded || hasValue();
556          form.classList.toggle('is-search-expanded', !!expanded);
557          form.classList.toggle('has-search-value', hasValue());
558          if (nav) {
559            nav.classList.toggle('has-expanded-search', nextExpanded);
560          }
561          button.setAttribute('aria-expanded', expanded ? 'true' : 'false');
562        }
563
564        function expand() {
565          setExpanded(true);
566        }
567
568        function collapseIfEmpty() {
569          var active = document.activeElement;
570          var hasFormFocus = !!(active && (active === form || form.contains(active)));
571          if (!hasValue() && !hasFormFocus) {
572            setExpanded(false);
573          } else {
574            setExpanded(true);
575          }
576        }
577
578        setExpanded(hasValue());
579        input.addEventListener('focus', expand);
580        input.addEventListener('input', function () {
581          setExpanded(true);
582        });
583        button.addEventListener('click', function (event) {
584          if (!form.classList.contains('is-search-expanded') && !hasValue()) {
585            event.preventDefault();
586            expand();
587            input.focus();
588          }
589        });
590        form.addEventListener('submit', function (event) {
591          if (!hasValue()) {
592            event.preventDefault();
593            expand();
594            input.focus();
595          }
596        });
597        document.addEventListener('pointerdown', function (event) {
598          if (!form.contains(event.target) && !hasValue()) {
599            setExpanded(false);
600          }
601        });
602      })(forms[i]);
603    }
604  }
605
606  if (document.readyState === 'loading') {
607    document.addEventListener('DOMContentLoaded', setupExpandableSearch, { once: true });
608  } else {
609    setupExpandableSearch();
610  }
611})();
612
613(function () {
614  function dedupeTopLevelNav() {
615    try {
616      var navs = document.querySelectorAll('nav.site-nav');
617      if (navs && navs.length > 1) {
618        for (var i = 1; i < navs.length; i += 1) {
619          var node = navs[i];
620          if (node && node.parentNode) {
621            node.parentNode.removeChild(node);
622          }
623        }
624      }
625      var skips = document.querySelectorAll('.skip-link');
626      if (skips && skips.length > 1) {
627        for (var j = 1; j < skips.length; j += 1) {
628          var skip = skips[j];
629          if (skip && skip.parentNode) {
630            skip.parentNode.removeChild(skip);
631          }
632        }
633      }
634    } catch (_dedupeErr) {
635      // Ignore non-fatal nav dedupe issues.
636    }
637  }
638
639  dedupeTopLevelNav();
640  if (document.readyState === 'loading') {
641    document.addEventListener('DOMContentLoaded', dedupeTopLevelNav, { once: true });
642  } else {
643    setTimeout(dedupeTopLevelNav, 0);
644  }
645
646  try {
647    var SITE_TITLE_CACHE_KEY = 'wizardry_blog_site_title_v1';
648    var siteSignature = document.getElementById('nav-site-signature');
649    function normalizeSiteTitle(value) {
650      var text = String(value || '').replace(/\s+/g, ' ').trim();
651      return text || 'Site';
652    }
653    function applySiteTitleSignature(value) {
654      if (!siteSignature) {
655        return;
656      }
657      var title = normalizeSiteTitle(value);
658      siteSignature.textContent = title;
659      siteSignature.setAttribute('title', title);
660    }
661    function syncSiteTitleDestination() {
662      if (!siteSignature || !siteSignature.setAttribute) {
663        return;
664      }
665      var firstNavLink = document.querySelector('.nav-center a[data-page][href]');
666      var href = firstNavLink ? String(firstNavLink.getAttribute('href') || '').trim() : '';
667      siteSignature.setAttribute('href', href || '/');
668    }
669    try {
670      applySiteTitleSignature(localStorage.getItem(SITE_TITLE_CACHE_KEY) || '');
671    } catch (_siteTitleErr) {
672      applySiteTitleSignature('Site');
673    }
674    syncSiteTitleDestination();
675
676    var token = String(localStorage.getItem('session_token') || '').trim();
677    var hasToken = !!token && token !== 'null' && token !== 'undefined';
678    var cachedPlayerName = String(localStorage.getItem('last_auth_player_name') || '').trim();
679    var loginSplit = document.getElementById('nav-login-split');
680    var userMenu = document.getElementById('nav-user-menu');
681    var userName = document.getElementById('nav-user-name');
682    var composeTools = document.getElementById('nav-compose-tools');
683    var cachedIsAdmin = String(localStorage.getItem('last_auth_is_admin') || '') === '1';
684
685    if (loginSplit) {
686      loginSplit.style.display = 'none';
687    }
688    if (userMenu) {
689      userMenu.style.display = 'none';
690    }
691    if (userName) {
692      userName.style.display = 'none';
693      userName.textContent = '';
694      userName.setAttribute('href', '/admin#account');
695    }
696
697    if (hasToken) {
698      if (composeTools) {
699        composeTools.style.display = cachedIsAdmin ? 'inline-flex' : 'none';
700      }
701      if (userMenu) {
702        userMenu.style.display = 'inline-flex';
703      }
704      if (userName) {
705        userName.style.display = 'inline-block';
706        userName.textContent = cachedPlayerName || 'signed-in';
707        userName.setAttribute('aria-label', 'Open account settings');
708        userName.setAttribute('href', '/admin#account');
709      }
710    } else if (loginSplit) {
711      loginSplit.style.display = 'inline-flex';
712    }
713  } catch (_err) {
714    // Ignore storage failures and let nav-auth.js reconcile state.
715  }
716
717  try {
718    var navCenter = document.querySelector('.nav-center');
719    var cachedRaw = localStorage.getItem('cached_navbar_pages_v1');
720    function normalizeNavPath(path) {
721      var p = String(path || '').trim();
722      var search = '';
723      if (!p) {
724        return '/';
725      }
726      if (p.indexOf('http://') === 0 || p.indexOf('https://') === 0) {
727        try {
728          var parsed = new URL(p, window.location.href);
729          p = parsed.pathname || '/';
730          search = parsed.search || '';
731        } catch (_urlErr) {
732          p = '/';
733          search = '';
734        }
735      }
736      if (!search && p.indexOf('?') >= 0) {
737        var split = p.split('?', 2);
738        p = split[0] || '/';
739        search = split[1] ? ('?' + split[1]) : '';
740      }
741      p = p.replace(/\/+$/, '') || '/';
742      if (p === '/pages/index' || p === '/pages/index.html') {
743        try {
744          var params = new URLSearchParams(search || '');
745          var slug = String(params.get('page_slug') || params.get('slug') || '').trim().toLowerCase();
746          slug = slug.replace(/[^a-z0-9-]+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, '');
747          if (slug && slug !== 'index') {
748            return '/' + slug;
749          }
750        } catch (_paramErr) {
751          // Ignore malformed page query strings.
752        }
753        return '/';
754      }
755      if (p.indexOf('/pages/') === 0) {
756        p = '/' + p.slice('/pages/'.length);
757        p = p.replace(/\.html?$/i, '');
758      }
759      return p || '/';
760    }
761    function highlightCurrentNavNow() {
762      if (!navCenter) {
763        return;
764      }
765      var current = normalizeNavPath(window.location.href);
766      if (current.indexOf('/posts/') === 0 || current === '/cgi/blog-open-post' || current.indexOf('/cgi/blog-open-post/') === 0) {
767        current = '/';
768      }
769      var links = navCenter.querySelectorAll('a[data-page]');
770      var selected = null;
771      links.forEach(function (link) {
772        var active = !selected && normalizeNavPath(link.getAttribute('href') || '') === current;
773        if (active) {
774          selected = link;
775        }
776        link.classList.toggle('active', active);
777        if (active) {
778          link.setAttribute('aria-current', 'page');
779          link.removeAttribute('aria-disabled');
780          link.removeAttribute('tabindex');
781        } else {
782          link.removeAttribute('aria-current');
783          link.removeAttribute('aria-disabled');
784          link.removeAttribute('tabindex');
785        }
786      });
787    }
788    function collapseOverflowingNavLinksNow() {
789      if (!navCenter) {
790        return;
791      }
792      var links = Array.prototype.slice.call(navCenter.querySelectorAll('a[data-page]'));
793      if (links.length < 2) {
794        return;
795      }
796      links.forEach(function (link) {
797        link.classList.remove('is-nav-overflow-hidden');
798      });
799      var activeLink = links.find(function (link) {
800        return link.classList.contains('active');
801      }) || null;
802      var guard = 0;
803      while (navCenter.scrollWidth > (navCenter.clientWidth + 1) && guard < links.length) {
804        var hide = null;
805        for (var i = links.length - 1; i >= 0; i -= 1) {
806          if (links[i].classList.contains('is-nav-overflow-hidden')) {
807            continue;
808          }
809          if (activeLink && links[i] === activeLink) {
810            continue;
811          }
812          hide = links[i];
813          break;
814        }
815        if (!hide && activeLink && !activeLink.classList.contains('is-nav-overflow-hidden')) {
816          hide = activeLink;
817        }
818        if (!hide) {
819          break;
820        }
821        hide.classList.add('is-nav-overflow-hidden');
822        guard += 1;
823      }
824    }
825    function syncInitialOverflowPanelNow() {
826      var overflowMenu = document.getElementById('nav-overflow-menu');
827      var overflowButton = document.getElementById('nav-overflow-btn');
828      var overflowCount = document.getElementById('nav-overflow-count');
829      var overflowPanel = document.getElementById('nav-overflow-panel');
830      if (!overflowMenu || !overflowButton || !overflowCount || !overflowPanel) {
831        return;
832      }
833      var hiddenLinks = Array.prototype.slice.call(navCenter.querySelectorAll('a[data-page].is-nav-overflow-hidden'));
834      overflowPanel.innerHTML = '';
835      hiddenLinks.forEach(function (link) {
836        var item = document.createElement('a');
837        item.className = 'nav-menu-item';
838        item.setAttribute('role', 'menuitem');
839        item.href = link.getAttribute('href') || '/';
840        item.textContent = String(link.textContent || '').trim() || 'Page';
841        overflowPanel.appendChild(item);
842      });
843      if (!hiddenLinks.length) {
844        overflowCount.textContent = '0';
845        overflowCount.hidden = true;
846        overflowButton.setAttribute('aria-label', 'More pages');
847        overflowMenu.hidden = true;
848        return;
849      }
850      overflowCount.textContent = String(hiddenLinks.length);
851      overflowCount.hidden = false;
852      overflowButton.setAttribute('aria-label', 'More pages (' + String(hiddenLinks.length) + ' hidden)');
853      overflowMenu.hidden = false;
854    }
855    if (navCenter && cachedRaw) {
856      var cachedPages = JSON.parse(cachedRaw);
857      if (!Array.isArray(cachedPages)) {
858        cachedPages = [];
859      }
860      var basePages = [
861        { slug: 'index', title: 'Writing', path: '/' }
862      ];
863      var seen = {};
864      var html = '';
865      function esc(text) {
866        return String(text || '')
867          .replace(/&/g, '&amp;')
868          .replace(/</g, '&lt;')
869          .replace(/>/g, '&gt;')
870          .replace(/"/g, '&quot;')
871          .replace(/'/g, '&#39;');
872      }
873      basePages.forEach(function (page) {
874        seen[page.slug] = true;
875        html += '<a href="' + esc(page.path) + '" data-page="' + esc(page.slug) + '">' + esc(page.title) + '</a>';
876      });
877      cachedPages.forEach(function (page) {
878        var slug = String(page && page.slug || '').trim();
879        var title = String(page && page.title || '').trim();
880        var path = String(page && page.path || '').trim();
881        if (!slug || !path || seen[slug]) {
882          return;
883        }
884        seen[slug] = true;
885        html += '<a href="' + esc(path) + '" data-page="' + esc(slug) + '">' + esc(title || slug) + '</a>';
886      });
887      if (html) {
888        var overflowMenu = document.getElementById('nav-overflow-menu');
889        navCenter.innerHTML = html;
890        if (overflowMenu) {
891          navCenter.appendChild(overflowMenu);
892        }
893        syncSiteTitleDestination();
894      }
895    }
896    highlightCurrentNavNow();
897    collapseOverflowingNavLinksNow();
898    syncInitialOverflowPanelNow();
899  } catch (_err2) {
900    // Ignore cache parse failures and let runtime fetch reconcile state.
901  }
902
903  document.addEventListener('DOMContentLoaded', function () {
904    var hasDynamicNostrPage = !!(
905      document.getElementById('blog-page-root') ||
906      document.getElementById('nip23-page-root') ||
907      document.getElementById('list-page-root') ||
908      document.getElementById('public-ranking-root') ||
909      document.getElementById('overworld-page-root') ||
910      document.getElementById('contact-page-root') ||
911      document.getElementById('archive-page-root') ||
912      document.getElementById('tags-page-root') ||
913      document.getElementById('search-page-root') ||
914      document.getElementById('admin-panel')
915    );
916    if (hasDynamicNostrPage) {
917      return;
918    }
919    var gate = window.__wizardryHydration;
920    if (gate && typeof gate.markPageReady === 'function') {
921      gate.markPageReady();
922    }
923  });
924})();
925</script>
925
926
927<div id="nav-top-toast-host" class="nav-top-toast-host" aria-live="polite" aria-atomic="true"></div>
928<aside id="nav-cart-drawer" class="nav-cart-drawer" hidden>
929  <div class="nav-cart-drawer-head">
930    <h2>Shopping Cart</h2>
931    <button id="nav-cart-close" type="button" aria-label="Close cart">&times;</button>
932  </div>
933  <p id="nav-cart-empty" class="nav-cart-empty">Your cart is empty.</p>
934  <ul id="nav-cart-items" class="nav-cart-items"></ul>
935  <div class="nav-cart-drawer-footer">
936    <div class="nav-cart-subtotal-row"><span>Subtotal</span><strong id="nav-cart-subtotal">$0.00</strong></div>
937    <div class="nav-cart-drawer-links">
938      <a href="/cart" class="nav-cart-link-button">View Cart</a>
939      <a href="/checkout" class="nav-cart-link-button nav-cart-link-button-primary">Checkout</a>
940    </div>
941  </div>
942</aside>
943
944<script defer src="/static/vendor/citrine-nostr-web.js?v=1376469157"></script>
vendor: 1 bytes, line 944
944
945<script defer src="/static/nav-auth.js?v=1376469157"></script>
vendor: 1 bytes, line 945
945
946<script defer src="/static/shop-cart.js?v=1376469157"></script>
vendor: 1 bytes, line 946
946
947<script async src="https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.js"></script>
vendor: 1 bytes, line 947
947
948<script async src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
948
949<header id="title-block-header">
950<h1 class="title">Checkout</h1>
951<p class="author">author</p>
952</header>
953<section id="checkout-page-root" class="checkout-shell" data-page-slug="checkout" data-page-type="checkout">
954<div class="checkout-head">
955<h1>
956Checkout
957</h1>
958<p>
959Choose BTCPay or credit card, then complete payment in-panel.
960</p>
961</div>
962<div id="checkout-page-content" class="checkout-page-content">
963
964</div>
965</section>
966<script src="/static/checkout-page.js?v=1376469157"></script>
966
967<footer class="site-footer">
968  <nav id="footer-pages" class="footer-pages" aria-label="Footer pages" hidden></nav>
969  <div class="footer-feeds" aria-label="Syndication feeds">
970    <a href="/rss.xml" class="footer-feed-link" aria-label="RSS feed" title="RSS feed">
971      <svg width="15" height="15" viewBox="0 0 24 24" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
972        <circle cx="6" cy="18" r="2.2" fill="currentColor"/>
973        <path d="M4 10a10 10 0 0 1 10 10" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round"/>
974        <path d="M4 4a16 16 0 0 1 16 16" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round"/>
975      </svg>
976      <span>RSS</span>
977    </a>
978    <a href="/atom.xml" class="footer-feed-link" aria-label="Atom feed" title="Atom feed">
979      <svg width="15" height="15" viewBox="0 0 24 24" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
980        <circle cx="12" cy="12" r="2.1" fill="currentColor"/>
981        <ellipse cx="12" cy="12" rx="8.6" ry="3.6" fill="none" stroke="currentColor" stroke-width="1.6"/>
982        <ellipse cx="12" cy="12" rx="8.6" ry="3.6" transform="rotate(60 12 12)" fill="none" stroke="currentColor" stroke-width="1.6"/>
983        <ellipse cx="12" cy="12" rx="8.6" ry="3.6" transform="rotate(120 12 12)" fill="none" stroke="currentColor" stroke-width="1.6"/>
984      </svg>
985      <span>Atom</span>
986    </a>
987    <span class="footer-version" aria-label="Site version">v0.7.60</span>
988    <a href="https://github.com/andersaamodt/gazeta" class="footer-feed-link" aria-label="GitHub repository" title="GitHub repository" rel="noopener noreferrer">
989      <svg width="15" height="15" viewBox="0 0 24 24" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
990        <path fill="currentColor" d="M12 1C5.93 1 1 5.93 1 12c0 4.86 3.15 8.98 7.52 10.44.55.1.75-.24.75-.53 0-.26-.01-1.13-.02-2.05-3.06.66-3.71-1.3-3.71-1.3-.5-1.27-1.22-1.61-1.22-1.61-.99-.68.08-.66.08-.66 1.1.08 1.68 1.13 1.68 1.13.98 1.67 2.56 1.19 3.19.91.1-.71.38-1.19.7-1.47-2.44-.28-5.01-1.22-5.01-5.43 0-1.2.43-2.18 1.13-2.94-.11-.28-.49-1.4.11-2.91 0 0 .92-.29 3.02 1.13.88-.24 1.82-.37 2.75-.37.93 0 1.87.12 2.75.37 2.1-1.42 3.02-1.13 3.02-1.13.6 1.51.22 2.63.11 2.91.7.77 1.13 1.74 1.13 2.94 0 4.22-2.57 5.15-5.02 5.42.39.34.74 1.01.74 2.04 0 1.47-.01 2.66-.01 3.02 0 .29.2.64.76.53A11.01 11.01 0 0 0 23 12c0-6.07-4.93-11-11-11Z"/>
991      </svg>
992      <span>GitHub</span>
993    </a>
994  </div>
995</footer>
996<script defer src="/static/footer-pages.js?v=1376469157"></script>
996
997</body>
998</html>

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.