{
  "version": 3,
  "sources": ["/cdn/shop/t/21/assets/black-hole-customizer.js?vfresh=0.8078437407145143"],
  "sourcesContent": ["/* Black Hole Registry \u2014 customizer console. Vanilla port of the design handoff (no React/support.js).\n   Reads a JSON config injected by the Liquid section (copy, occasions, tones, art, packages, add-ons,\n   asset URLs, variant IDs) and renders the 6-row wizard + rail. Adds the main variant + each selected\n   add-on as separate /cart/add.js line items sharing a _bundle_id. */\n(function () {\n  var mount = document.getElementById('bhr-customizer');\n  if (!mount) return;\n  var CFG;\n  try { CFG = JSON.parse(document.getElementById('bhr-customizer-config').textContent); }\n  catch (e) { console.error('[bhr] bad config', e); return; }\n\n  // ART starts EMPTY. It used to start as six hardcoded entries, which meant the static art was\n  // not a fallback at all \u2014 it was the initial state of every page load, painted by renderAll()\n  // before loadGallery() had returned. So 'only shown when Cloudflare is down' was untrue by\n  // construction. Now first paint is a skeleton, and art only ever appears from the live gallery\n  // or, when that cannot be reached, from the curated published set.\n  // MODE, SIGNS, CATEGORIES AND FLAGS (spec 025). The section decides the mode from the store's flag\n  // document and the entry occasion's `standalone` rule; the script only reads it. Absent means the\n  // ordinary console, so a store without the data renders exactly as it did before the feature.\n  var MODE = (CFG.mode === 'hole-o-scopes') ? 'hole-o-scopes' : 'black-holes';\n  var FLAGS = CFG.flags || {};\n  var SIGNS = CFG.signs || [];\n  var CATS = CFG.categories || [];\n  // A STANDALONE OCCASION EXISTS ONLY WHILE ITS FLAG IS ON (2026-09-27, replacing spec 025 FR-001a's\n  // \"off = nothing changes\", which left the pre-025 Horoscope chip and sign step live on prod for a\n  // feature that was not released). The section already leaves it out of CFG.occasions while the flag\n  // is off; this is the same rule read again here so a config that still carries one cannot show it.\n  // While the flag is on it is offered, and only through its own door: in the ordinary console the\n  // chip navigates to the occasion's own page (`url`, written by the section) instead of selecting\n  // it here; on that page the mode is hole-o-scopes and the locked occasion resolves as before.\n  function offeredHere(o) {\n    return !o.standalone || !!FLAGS.holeOScopes;\n  }\n  var OCC = (CFG.occasions || []).filter(offeredHere), TONES = CFG.tones, ART = [], PKGS = CFG.packages,\n      ADDONS = CFG.addons, EXTRAS = CFG.extras || {}, C = CFG.copy || {};\n  // PER-SENTENCE SIZE AND COLOUR (spec 031). Every sentence the store writes can carry its own\n  // style \u2014 `{ \"<fieldKey>\": { \"size\": px, \"color\": \"#rrggbb\" } }` in a `styles` field on the\n  // occasion, tone, sign or category it belongs to, or on its copy group (CFG.stylesByGroup) \u2014 set in\n  // curator beside the words. The operator, 2026-09-27: \"text is far too small and a light grey color\n  // on black ... I need to be able to set font size, color, and text next to each entry\". `ov()`\n  // turns one into an inline fragment appended AFTER the site's own declarations, so it wins by\n  // cascade order, and a missing or malformed style changes nothing. Group keys are camelCased the\n  // way `copy` names its strings (curator's camelKey does the same): `panel_empty_body` styles\n  // `C.panelEmptyBody`. Both modes paint through the same sites, so Hole-O-scopes is covered too.\n  function camelKey(k) { return String(k).replace(/_([a-z0-9])/g, function (_m, c) { return c.toUpperCase(); }); }\n  function styleOf(map, key) {\n    var st = map && key ? map[key] : null;\n    if (!st || typeof st !== 'object') return null;\n    var out = {}, n = Number(st.size);\n    if (Number.isInteger(n) && n >= 8 && n <= 72) out.size = n;\n    if (typeof st.color === 'string' && /^#[0-9a-fA-F]{6}$/.test(st.color)) out.color = st.color;\n    return (out.size || out.color) ? out : null;\n  }\n  function ov(st) {\n    if (!st) return '';\n    return (st.size ? ';font-size:' + st.size + 'px' : '') + (st.color ? ';color:' + st.color : '');\n  }\n  var STYLES = (function () {\n    var flat = {}, groups = CFG.stylesByGroup || {}, clashed = [];\n    Object.keys(groups).forEach(function (g) {\n      var m = groups[g];\n      if (!m || typeof m !== 'object') return;\n      Object.keys(m).forEach(function (k) {\n        var ck = camelKey(k), st = styleOf(m, k);\n        if (!st) return;\n        if (flat[ck]) { clashed.push(g + '.' + k); return; }   // the first group keeps the key; said once\n        flat[ck] = st;\n      });\n    });\n    if (clashed.length) console.warn('[bhr] style clash', clashed);   // first group kept; said once, not per render\n    return flat;\n  })();\n  // THE SITE RULE (spec 031 slice 2; the operator, 2026-09-27: \"text is just tiny in many places ...\n  // I want to adjust throughout the customizer. Any text, any field ... this is a site rule\"). Every\n  // size and every grey the console paints is adjustable from curator: the `customizer_type` group is\n  // one scale and one palette for the whole console, in both modes, and per-sentence `styles` sit on\n  // top of it. `px(n)` is the ONLY way an inline size is written in this file, `MUTED`/`INK` the only\n  // greys, `LABEL`/`HEADING` the two named sizes; a literal that bypasses them fails\n  // tests/storefront/customizer-type-rule.test.ts. Absent group, absent field: the defaults below,\n  // which are also what the section serialises when the store has no group, so old and new agree.\n  var T = (function () {\n    var t = CFG.type || {};\n    function num(v, lo, hi, dflt) { var n = Number(v); return (Number.isFinite(n) && n >= lo && n <= hi) ? n : dflt; }\n    function hex(v, dflt) { return (typeof v === 'string' && /^#[0-9a-fA-F]{6}$/.test(v)) ? v : dflt; }\n    return {\n      baseSize: num(t.baseSize, 8, 72, num(C.panelBodySize, 8, 72, 15)),\n      headingSize: num(t.headingSize, 8, 72, num(C.panelTitleSize, 8, 72, 19)),\n      labelSize: num(t.labelSize, 8, 72, 13),\n      ink: hex(t.ink, '#f2f2f4'),\n      mutedInk: hex(t.mutedInk, '#c9c9d1'),\n      panelIconSize: num(t.panelIconSize, 16, 256, num(C.panelIconSize, 16, 256, 64)),\n      panelImageScale: num(t.panelImageScale, 10, 100, 100),\n      panelFillHeight: t.panelFillHeight === true || t.panelFillHeight === 'true'\n    };\n  })();\n  var SCALE = T.baseSize / 15;\n  /** An inline size in px, scaled by the console's base size (15 is the unscaled design). */\n  function px(n) { return Math.round(n * SCALE); }\n  var INK = T.ink, MUTED = T.mutedInk, LABEL = T.labelSize, HEADING = T.headingSize;\n  function occStyles() { var o = findOcc(); return o ? o.styles : null; }\n  // Add-ons are per-occasion: each occasion's Shopify collection supplies its add-ons (config, not code).\n  // Fall back to the universal add-ons (CFG.addons) for any occasion whose collection has none.\n  var ADDONS_BY_OCC = CFG.addonsByOccasion || {};\n  // Curated fallback, published to shop metafields by curator (ADR-0020). Never browsed: these\n  // are only ever shown when the gallery pull has failed.\n  /** Operator copy. CLEARING the field clears the text on the page, and there is nothing under it.\n   *\n   *  `C.<name> || 'literal'` cannot express that. '' is falsy in JavaScript, so a setting the operator\n   *  deliberately emptied silently rendered the hardcoded copy instead \u2014 the field saved, the page did\n   *  not change, and nothing said why. Reported 2026-08-25 against \"Product note\"; it was true of\n   *  sixteen settings.\n   *\n   *  THE LITERAL SECOND ARGUMENT IS GONE (2026-08-30). It was dead in every one of 123 call sites:\n   *  the section assigns all 135 copy values unconditionally and serialises them, so `C.<name>` was\n   *  never absent and the fallback never fired. What kept it honest was nothing \u2014 it was one key name\n   *  away from silently shipping the theme's words over the operator's. `mockupBg` had made exactly\n   *  that mistake and nobody could see it, because the stale literal matched the setting's value.\n   *\n   *  So the guarantee moved to where it can fail loudly: tests/storefront/customizer-copy-reaches-the-\n   *  browser.test.ts asserts that every key this file reads is a key the section emits. A key added\n   *  here and forgotten there now fails the build instead of quietly rendering the wrong sentence.\n   *\n   *  Absence still cannot reach the page as the word \"undefined\": it coerces to ''.\n   *\n   *  NOT for colours or sizes: '' is not a valid CSS value, so those keep `||` on purpose. */\n  function copy(v) { return (v === null || v === undefined) ? '' : v; }\n\n  /** Fill `{who}`, `{occasion}` and friends in a sentence the operator owns.\n   *\n   *  A token exists only where the sentence is BUILT AROUND something the shopper chose, so the\n   *  operator cannot reword it by appending: \"A black hole, registered for Ada this birthday.\" has\n   *  the name in the middle. Where a value can simply be appended it is, because a token an operator\n   *  has to remember to keep is a way to break the page from a text box (the re-draw count is\n   *  appended for exactly that reason).\n   *\n   *  An unknown token is left as it was typed rather than blanked, so a typo reads as a typo. */\n  function fill(s, vars) {\n    return String(s == null ? '' : s).replace(/\\{(\\w+)\\}/g, function (m, k) {\n      return Object.prototype.hasOwnProperty.call(vars, k) ? String(vars[k]) : m;\n    });\n  }\n\n  /** The chip row under a package \u2014 \"CARD + CERTIFICATE  FREE SHIPPING  PRINT ON DEMAND\".\n   *\n   *  Operator-editable as ONE comma-separated setting rather than three fixed fields, so a package\n   *  can carry two chips or four without a schema change. It was three literals in the section file\n   *  until 2026-08-25, which made \"Print on demand\" a code change and a deploy.\n   *\n   *  An EMPTY setting removes the row rather than rendering an empty strip \u2014 same rule as every\n   *  other copy setting: '' is an instruction. `bullets` is still honoured so a stored template that\n   *  predates `bulletsRaw` keeps working. */\n  function chipList(p) {\n    if (p.bulletsRaw !== null && p.bulletsRaw !== undefined) {\n      return String(p.bulletsRaw).split(',').map(function (b) { return b.trim(); })\n        .filter(function (b) { return b.length; });\n    }\n    return p.bullets || [];\n  }\n\n  function chipRow(p) {\n    var list = chipList(p);\n    if (!list.length) return '';\n    return '<span style=\"display:flex;flex-wrap:wrap;gap:6px;margin-top:2px\">'\n      + list.map(function (b) {\n          return '<span style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(10) + 'px;letter-spacing:0.04em;'\n            + 'text-transform:uppercase;color:' + MUTED + ';border:1px solid #2b2b32;border-radius:999px;'\n            + 'padding:4px 9px\">' + esc(b) + '</span>';\n        }).join('') + '</span>';\n  }\n\n\n  var BACKUP_ART = CFG.backupArt || [], BACKUP_TEXT = CFG.backupText || [];\n  // 'loading' | 'live' | 'backup' | 'empty' \u2014 what the carousel is currently showing, so the\n  // shopper is told which, instead of a silent swap.\n  var artSource = 'loading';\n  // Price styling is configurable in the theme editor. Every price goes through this, so a change in\n  // the editor moves all of them together \u2014 previously each site hardcoded its own size and colour.\n  function priceStyle(sizePx, weight) {\n    return 'font-family:' + (C.priceFont || \"'Space Mono', monospace\")\n      + ';font-size:' + (sizePx || C.priceSize || 19) + 'px'\n      + ';color:' + (C.priceColor || '#e07b1f')\n      + ';font-weight:' + (weight || 700)\n      + ';letter-spacing:-0.01em;line-height:1';\n  }\n\n  function addonsFor(occ) { var l = occ && ADDONS_BY_OCC[occ.id]; return (l && l.length) ? l : ADDONS; }\n\n  // Every add-on carries a `sizes` array \u2014 four for a puzzle, one for a one-size product \u2014 so price,\n  // variant, mockup and box all resolve through here rather than off the add-on itself. Nothing\n  // downstream needs to know whether a product has sizes at all.\n  //\n  // The older config shape put price/variantId/mockup/box directly on the add-on. Tolerate it, because\n  // the theme and the Shopify data deploy separately and a stale cache of either should degrade to a\n  // working single-size add-on rather than an exception.\n  function sizesOf(a) {\n    if (a.sizes && a.sizes.length) return a.sizes;\n    return [{ label: '', variantId: a.variantId, sku: a.sku || '', price: a.price,\n              available: a.available !== false, mockup: a.mockup || '', box: a.box || '' }];\n  }\n  function sizeIdx(a) {\n    var n = sizesOf(a).length;\n    var i = state.addonSize[a.id];\n    return Math.min(i == null ? 0 : i, n - 1);\n  }\n  function sizeOf(a) { return sizesOf(a)[sizeIdx(a)]; }\n\n  // Each size was photographed from several angles \u2014 flat, on a wall, in a hand \u2014 and every one of them\n  // is calibrated, so the panel can show the product from more than one viewpoint. That is the only way a\n  // still tile conveys scale: a 252-piece puzzle and a 2000-piece one are identical pictures until you\n  // see one of them next to a hand.\n  // Signed mockups for the selected black hole, fetched once and remembered on the art record.\n  var _mockupFetches = {};\n  function ensureMockups(art) {\n    if (!art || art.mockups || !(art.mockupSkus && art.mockupSkus.length)) return;\n    if (_mockupFetches[art.id]) return;\n    _mockupFetches[art.id] = 1;\n    fetch(GALLERY_PATH + '/mockups?image=' + encodeURIComponent(art.id), { credentials: 'same-origin' })\n      .then(function (r) { return r.ok ? r.json() : null; })\n      .then(function (d) {\n        if (!d || !d.mockups) return;\n        art.mockups = d.mockups;\n        renderAll();                       // the panel was showing the CSS fallback until now\n      })\n      .catch(function () { /* the add-ons step falls back to compositing; not worth surfacing */ });\n  }\n\n  function viewsOf(a) {\n    var sz = sizeOf(a);\n    // Pre-rendered mockups win. They are photographs of this exact black hole on this exact product,\n    // warped with real perspective and passing behind anything in front of the print \u2014 none of which\n    // the browser can do by stacking an overlay over the art. A `src` with no `box` tells the stage to\n    // show the picture as-is rather than compositing.\n    var art = ART[state.art];\n    var pre = art && art.mockups && sz.sku && art.mockups[sz.sku];\n    if (pre && pre.length) return pre.map(function (u) { return { src: u, box: '', w: 0, h: 0 }; });\n    // Array.isArray, not truthiness: a config that carries the string \"[]\" (an absent metafield rendered\n    // through `default`) is truthy AND has .length, so a plain check let a string reach .map and take the\n    // whole render down. One malformed field should cost its own mockups, not the page.\n    if (Array.isArray(sz.views) && sz.views.length) return sz.views;\n    return sz.mockup ? [{ src: sz.mockup, box: sz.box, w: 0, h: 0 }] : [];\n  }\n  // View index is keyed by add-on AND size: switching size changes which photographs exist, so carrying\n  // \"view 4\" across to a size with two views would silently land on the wrong picture.\n  function viewKey(a) { return a.id + '@' + sizeIdx(a); }\n  // How much of the frame the print occupies, from the measured box.\n  function viewFill(v) {\n    if (!v || !v.box) return 1;\n    var w = /width:([\\d.]+)%/.exec(v.box), h = /height:([\\d.]+)%/.exec(v.box);\n    return (w && h) ? (parseFloat(w[1]) * parseFloat(h[1]) / 10000) : 1;\n  }\n  // Which view to show before anyone touches the panel. Views are ordered biggest-print-first, so a\n  // naive index 0 opens every product on a frame-filling shot of the artwork \u2014 three panels that look\n  // identical and say nothing about what the product IS. Preferring a view where the print takes a\n  // moderate share of the frame picks the one WITH CONTEXT: the hand holding the puzzle, the print on a\n  // wall, the deck behind the card. The frame-filling shots stay in the slideshow, just not first.\n  function defaultViewIdx(a) {\n    var vw = viewsOf(a);\n    if (vw.length < 2) return 0;\n    var best = 0, bestD = Infinity;\n    for (var i = 0; i < vw.length; i++) {\n      var d = Math.abs(viewFill(vw[i]) - 0.45);\n      if (d < bestD) { bestD = d; best = i; }\n    }\n    return best;\n  }\n  function viewIdx(a) {\n    var n = viewsOf(a).length;\n    if (!n) return 0;\n    var i = state.addonView[viewKey(a)];\n    return Math.min(i == null ? defaultViewIdx(a) : i, n - 1);\n  }\n  function viewOf(a) { return viewsOf(a)[viewIdx(a)] || null; }\n  function findAddon(id) {\n    var l = addonsFor(findOcc());\n    for (var i = 0; i < l.length; i++) if (l[i].id === id) return l[i];\n    return null;\n  }\n\n  // Round chevron, same treatment as the occasion marquee and the art carousel.\n  function navBtn(act, side, glyph, sizePx, extra) {\n    sizePx = sizePx || 42;\n    return '<button data-act=\"' + act + '\" ' + (extra || '') + ' aria-label=\"' + (side === 'left' ? 'Previous' : 'Next') + '\"'\n      + ' style=\"position:absolute;' + side + ':6px;top:50%;transform:translateY(-50%);z-index:3;width:' + sizePx + 'px;height:' + sizePx + 'px;'\n      + 'padding:0;border-radius:50%;border:1px solid rgba(255,255,255,0.18);background:rgba(10,10,13,0.72);color:' + INK + ';'\n      + 'display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:' + Math.round(sizePx * 0.57) + 'px;line-height:1;'\n      + '-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)\">' + glyph + '</button>';\n  }\n\n  // The art sits at a percentage of the OVERLAY, not of the tile \u2014 so the element the percentages apply\n  // to must have the overlay's own aspect ratio. Letterboxing that frame inside a fixed-aspect stage\n  // keeps every panel the same height while a portrait deck of cards and a landscape metal print still\n  // land their art exactly where it was measured.\n  function mockupStage(a, artSrc, stageAspect, opts) {\n    opts = opts || {};\n    var view = viewOf(a), vw = viewsOf(a);\n    if (!view) return '<span style=\"display:block;width:100%;aspect-ratio:' + stageAspect + ';background:#ececed;border-radius:8px\"></span>';\n    // No box means this view is already a finished photograph \u2014 show it, do not composite.\n    if (!view.box) {\n      var navA = vw.length < 2 || opts.noNav ? '' :\n        navBtn('addonViewPrev', 'left', '&#8249;', opts.navPx || 26, 'data-id=\"' + a.id + '\"')\n        + navBtn('addonViewNext', 'right', '&#8250;', opts.navPx || 26, 'data-id=\"' + a.id + '\"');\n      var dotsA = vw.length < 2 || opts.noNav ? '' :\n        '<span style=\"position:absolute;left:0;right:0;bottom:7px;display:flex;justify-content:center;gap:5px;z-index:3\">'\n        + vw.map(function (_, i) {\n            return '<span data-act=\"addonView\" data-id=\"' + a.id + '\" data-i=\"' + i + '\" role=\"button\" tabindex=\"0\"'\n              + ' style=\"width:' + (i === viewIdx(a) ? 16 : 6) + 'px;height:6px;border-radius:999px;cursor:pointer;'\n              + 'background:' + (i === viewIdx(a) ? '#e07b1f' : 'rgba(255,255,255,0.55)') + ';transition:all .2s ease\"></span>';\n          }).join('') + '</span>';\n      return '<span style=\"position:relative;display:flex;align-items:center;justify-content:center;width:100%;'\n        + 'aspect-ratio:' + stageAspect + ';background:#ececed;border-radius:8px;overflow:hidden'\n        + (opts.maxH ? ';max-height:' + opts.maxH : '') + '\">'\n        + '<img src=\"' + view.src + '\" alt=\"\" style=\"max-width:100%;max-height:100%;width:auto;height:auto;display:block\">'\n        + navA + dotsA + '</span>';\n    }\n    // The art is positioned in PERCENTAGES OF THE FRAME, so the frame must carry the overlay's own\n    // aspect or every measured percentage resolves against the wrong shape \u2014 the art slides off the\n    // print, and on the portrait card deck a landscape rectangle lands across it.\n    //\n    // GUESSING that aspect was the bug. `views` carries the overlay's pixel dimensions, but the legacy\n    // single-mockup fallback supplies w:0,h:0, and the old code quietly defaulted those to 4/3. A\n    // fallback that renders wrong is not a fallback.\n    //\n    // So when w/h are absent the frame is left unshaped and marked data-fit, and the aspect is taken\n    // from the overlay's OWN naturalWidth/naturalHeight the moment it loads (see the data-fit listener\n    // near the bottom of this file). Measured beats declared: it is also self-correcting if the stored\n    // w/h are stale.\n    var sp = String(stageAspect).split('/');\n    var sa = sp.length === 2 ? (parseFloat(sp[0]) / parseFloat(sp[1])) : 4 / 3;\n    var known = !!(view.w && view.h);\n    var fa = known ? (view.w / view.h) : 0;\n    // Bind whichever axis actually constrains and let the other derive from the ratio: `width:100% +\n    // aspect-ratio + max-height` does NOT preserve the ratio (the browser keeps width and merely clamps\n    // height), which squashes the frame and drags the art off the print.\n    var frameStyle = known\n      ? 'aspect-ratio:' + view.w + '/' + view.h + ';' + (fa >= sa ? 'width:100%;height:auto' : 'height:100%;width:auto')\n      : 'width:100%;height:auto';\n    var dots = vw.length < 2 || opts.noNav ? '' :\n      '<span style=\"position:absolute;left:0;right:0;bottom:7px;display:flex;justify-content:center;gap:5px;z-index:3\">'\n      + vw.map(function (_, i) {\n          return '<span data-act=\"addonView\" data-id=\"' + a.id + '\" data-i=\"' + i + '\" role=\"button\" tabindex=\"0\"'\n            + ' style=\"width:' + (i === viewIdx(a) ? 16 : 6) + 'px;height:6px;border-radius:999px;cursor:pointer;'\n            + 'background:' + (i === viewIdx(a) ? '#e07b1f' : 'rgba(255,255,255,0.34)') + ';transition:all .2s ease\"></span>';\n        }).join('') + '</span>';\n    var arrows = vw.length < 2 || opts.noNav ? '' :\n      navBtn('addonViewPrev', 'left', '&#8249;', opts.navPx || 26, 'data-id=\"' + a.id + '\"')\n      + navBtn('addonViewNext', 'right', '&#8250;', opts.navPx || 26, 'data-id=\"' + a.id + '\"');\n    return '<span style=\"position:relative;display:flex;align-items:center;justify-content:center;width:100%;'\n      + 'aspect-ratio:' + stageAspect + ';background:#ececed;border-radius:8px;overflow:hidden'\n      + (opts.maxH ? ';max-height:' + opts.maxH : '') + '\">'\n      + '<span style=\"position:relative;display:block;' + frameStyle + '\" data-sa=\"' + sa + '\">'\n      + '<img src=\"' + artSrc + '\" alt=\"\" style=\"position:absolute;object-fit:cover;' + view.box + (a.filter ? ';filter:' + a.filter : '') + '\">'\n      // object-fit:fill, not contain: the frame is exactly the overlay's aspect, so there is nothing to\n      // letterbox, and `contain` would only reintroduce sub-pixel drift between the two layers.\n      + '<img src=\"' + view.src + '\" alt=\"\"' + (known ? '' : ' data-fit=\"1\"')\n      + ' style=\"position:absolute;inset:0;width:100%;height:100%;object-fit:fill;pointer-events:none\">'\n      + '</span>' + arrows + dots + '</span>';\n  }\n\n  // Some add-ons are produced at a different facility from the card/box and arrive in their own parcel.\n  // Say so on the card itself: finding out at checkout \u2014 or worse, when only half the order turns up \u2014\n  // is the kind of surprise that generates a support email and a refund request.\n  function shipsNote(a) {\n    if (!a.shipsSeparately) return '';\n    return '<span title=\"' + esc(copy(C.shipsSeparatelyNote)) + '\" style=\"display:inline-flex;align-items:center;gap:5px;font-size:' + px(10) + 'px;letter-spacing:0.06em;text-transform:uppercase;font-family:\\'Space Mono\\',monospace;color:' + MUTED + ';background:#17171c;border:1px solid #2b2b32;border-radius:999px;padding:3px 8px;align-self:flex-start' + ov(STYLES.shipsSeparatelyLabel) + '\">'\n      + '<svg width=\"10\" height=\"10\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"' + MUTED + '\" stroke-width=\"1.5\" aria-hidden=\"true\"><path d=\"M1 4.5h9v7H1z\"/><path d=\"M10 7h3l2 2.2v2.3h-5z\"/><circle cx=\"4\" cy=\"12.5\" r=\"1.4\"/><circle cx=\"11.7\" cy=\"12.5\" r=\"1.4\"/></svg>'\n      + esc(copy(C.shipsSeparatelyLabel)) + '</span>';\n  }\n  var money = function (n) { return '$' + Number(n).toFixed(2); };\n  var mobile = function () { return window.matchMedia('(max-width:749px)').matches; };\n  var enc = function (s) { return String(s == null ? '' : s); };\n  var esc = function (s) { return enc(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\"/g, '&quot;'); };\n\n  // The default occasion is simply the FIRST in the list, so the shop metafield custom.occasions\n  // controls both order AND default with one lever \u2014 reordering in the admin needs no deploy.\n  var DEFAULT_OCC = (OCC[0] && OCC[0].id) || 'justbecause';\n  var state = { occ: CFG.entryOccasion && CFG.entryOccasion !== 'none' ? CFG.entryOccasion : DEFAULT_OCC,\n    extra: {}, category: (CATS[0] && CATS[0].key) || '', acrosticShown: false, tone: 'cheeky', art: 1, car: 0, pkg: 'basic', size: null, addons: [], addonSize: {}, addonView: {}, addonCar: 0, alb: null, name: '', rel: '', from: '', regDate: '', msg: '', lb: null, slide: 0, bhName: '', cardTitle: '',\n    panel: null, schrod: false, draw: 0, redraws: 0, opened: false,\n    // The curated pair currently on the card, and which bucket it was drawn for.\n    drawn: null, drawKey: '', drawState: 'idle', drawnSeen: [],\n    // The cat ration (spec 025): the service's last `cats` block (undefined until it has spoken, null\n    // when it says nothing is counting, an object with `left` when it is), and the cat-cha in progress.\n    cats: undefined, catcha: null };\n  // panel = which card face the viewer is showing; schrod = \"let us write it\" vs self-written.\n  // draw = which message we drew for them; redraws = how many they have spent asking for another.\n  //\n  // schrod DEFAULTS OFF, for now. Having us write the inside IS the product \u2014 the Registry doing the\n  // paperwork is the joke people are buying \u2014 and it was the default for exactly that reason. But the\n  // default is a promise the corpus has to keep: a shopper who lands on it and gets a message that does\n  // not suit their occasion judges the product by that line, and there is no second impression. Until\n  // there is enough reviewed copy behind every occasion-and-tone bucket to be confident of what the\n  // draw returns, \"I'll write it myself\" is the honest opening position.\n  //\n  // TURN THIS BACK ON once the pool is deep enough. It is one boolean and the button order below, and\n  // the whole feature is already built behind it \u2014 leaving it off permanently would be quietly\n  // shipping a card company with no writers.\n  //\n  // opened = has the shopper broken the seal. False until they click, because the copy inside is the\n  // surprise and both inside panels show a sealed envelope until then.\n  var MSG_MAX = (CFG.copy && CFG.copy.messageMax) || 300;\n  var REROLL = (CFG.copy && CFG.copy.reroll) || {};\n  /**\n   * THERE IS NO AUDIENCE. Until 2026-09-26 this console asked \"Who is it for\" on the occasions that\n   * had a kids pool, carried the answer as `_audience` on the cart line, sent it with every draw, and\n   * hid the Romantic and Too Far chips for a child. The operator removed the question after user\n   * testing with the six tone chips live (spec 030 Amendment A): \"Too Far covers the adult/child\n   * issues on the site. It will be up to the user to determine if there are issues.\" The chip is the\n   * choice. Nothing here reads, sends or stores an audience; the draw serves one pool per occasion\n   * and tone.\n   */\n  var locked = !!(CFG.entryOccasion && CFG.entryOccasion !== 'none');\n\n  function findOcc() { for (var i = 0; i < OCC.length; i++) if (OCC[i].id === state.occ) return OCC[i]; return null; }\n  function findTone() { for (var i = 0; i < TONES.length; i++) if (TONES[i].id === state.tone) return TONES[i]; return TONES[0]; }\n\n  /**\n   * The tone chips THIS occasion offers.\n   *\n   * Not every register suits every occasion \u2014 there is no professional divorce card \u2014 and the chip row\n   * used to be the same eight for all of them. A shopper who picked one of the combinations we never\n   * write got the \"no message written yet\" fallback and no way to tell that from an outage. The\n   * allow-list is config: `tones` on the occasion metaobject, mirrored from EVENT_TONES in the\n   * curator's text-axes.ts so the chips and the corpus cannot disagree.\n   *\n   * A null or empty list means UNRESTRICTED, which is what horoscope wants (its copy is keyed by sign)\n   * and what every occasion falls back to before the metafield is deployed. Unknown handles are dropped\n   * rather than trusted, so a typo in the metaobject cannot put a dead chip on the page.\n   */\n  // No tone literal lives here any more. `ADULT_ONLY_TONES` (the chips hidden for a child) went with\n  // the audience question (Amendment A); every tone this console knows comes from the store, and\n  // tests/storefront/theme-tone-constants.test.ts fails the moment a tone literal reappears (DEV-10).\n  function tonesFor(occ) {\n    var allowed = occ && occ.tones;\n    // An EXPLICIT empty list means no tone step at all (spec 025, research R6): the occasion's copy is\n    // not keyed by tone, so a chip row would be six buttons that do nothing. Absent (null) still means\n    // unrestricted, which is what keeps every occasion that has never been given a list as it was.\n    // TONES is the store's shop-level `custom.tones` list \u2014 since spec 030 the six PARENT tones; the\n    // registers beneath them (casual, raunchy ...) are never chips and never appear here.\n    if (allowed && allowed.length === 0) return [];\n    var out = [];\n    for (var i = 0; i < TONES.length; i++) {\n      var t = TONES[i];\n      if (allowed && allowed.length && allowed.indexOf(t.id) === -1) continue;\n      out.push(t);\n    }\n    return out.length ? out : TONES;\n  }\n\n  /** Keep state.tone inside the chosen occasion's list. Without this, switching from Birthday to\n   *  Divorce leaves `romantic` selected \u2014 no chip looks active, and the message is drawn from a bucket\n   *  the new occasion does not have. */\n  function clampTone() {\n    var allowed = tonesFor(findOcc());\n    // No tone step: leave the tone where it is. The draw for such an occasion ignores it.\n    if (!allowed.length) return false;\n    for (var i = 0; i < allowed.length; i++) if (allowed[i].id === state.tone) return false;\n    state.tone = allowed[0].id;\n    return true;\n  }\n  function findPkg() { for (var i = 0; i < PKGS.length; i++) if (PKGS[i].id === state.pkg) return PKGS[i]; return PKGS[0]; }\n\n  // Live gallery: the \"Choose Your Singularity\" art comes from the Shopify App Proxy (shopify-gallery-worker),\n  // which returns a per-occasion weighted mix of available black holes with signed thumbnail URLs. If the\n  // proxy isn't reachable (not yet configured, offline, empty), we fall back to CFG.backupArt \u2014 the\n  // curated set curator publishes to a shop metafield (ADR-0020) \u2014 so the customizer never breaks.\n  // Config-driven: the proxy path is a section setting.\n  var GALLERY_PATH = CFG.galleryPath || '/apps/gallery';\n  var BHR_SID = (function () {\n    try {\n      var s = localStorage.getItem('bhr_sid');\n      if (!s) { s = 's' + Math.random().toString(36).slice(2) + Date.now().toString(36); localStorage.setItem('bhr_sid', s); }\n      return s;\n    } catch (e) { return 's' + Math.random().toString(36).slice(2); }\n  })();\n  var _galleryReq = 0;\n  // A published backup entry, in the same shape mapLive produces. `id` is the REAL cloudflare_id \u2014\n  // that is the whole reason an outage sale is an ordinary sale. No mockups: those are signed on\n  // demand from a worker that, by definition, cannot be reached right now.\n  function mapBackup(e) {\n    var tail = String(e.code || '').replace(/^BHR-/, '');\n    return { id: e.id, code: e.code, name: e.name || ('Singularity ' + tail),\n             src: e.src, full: e.src, mockupSkus: [], mockups: null,\n             // Baked in by curator's backup publish (spec 026); older sets have none and show a sample.\n             coordinates: e.coordinates || null };\n  }\n  function mapLive(img) {\n    var tail = String(img.code || '').replace(/^BHR-/, '');\n    return { id: img.id, code: img.code, name: 'Singularity ' + tail,\n             src: img.url, full: img.full || img.url,\n             // Which SKUs have mockups. The signed URLs themselves are fetched lazily for the selected\n             // image only \u2014 signing all twelve images' worth on every gallery pull discarded ~12x the\n             // work and pushed the request past the image-worker's 100-id batch cap.\n             mockupSkus: img.mockupSkus || [], mockups: null,\n             // Where this black hole is \u2014 the image's own metadata (spec 026), printed in the\n             // certificate box. Null until the pool is backfilled; the plate then shows a sample.\n             coordinates: img.coordinates || null };\n  }\n  // The gallery is deeper than one page \u2014 when the shopper reaches the end we pull the next batch,\n  // excluding what they've already seen, and append it. `_galleryEnd` stops us asking once it's exhausted.\n  // How many ids may ride in the `exclude` query string. Shopify's App Proxy answers an over-long URL\n  // with a 500 \u2014 and it answers in HTML, which fetch().catch() swallows, so the shopper is left on the\n  // STATIC fallback art with nothing shown and nothing logged.\n  //\n  // Measured against the dev store: 90 ids (3,545 B) returns 200, 100 ids (3,932 B) returns 500. The\n  // ceiling is ~4 KB once Shopify appends shop/path_prefix/timestamp/signature.\n  //\n  // Both callers used 150, which is ABOVE that ceiling. So the gallery worked on a fresh browser and\n  // then stopped for good once enough ids had accumulated in localStorage \u2014 degrading as you browse and\n  // then sticking, which reads as \"the gallery broke\" long after the session that actually broke it.\n  // Clearing site data appeared to fix it, which sent the blame somewhere else again.\n  //\n  // 60 leaves ~1.5 KB of headroom for the occasion and session params. The list only keeps repeats out\n  // of the next page, so dropping the oldest ids costs a little freshness and nothing else.\n  var URL_EXCLUDE_MAX = 60;\n  var _loadingMore = false, _galleryEnd = false;\n  function loadMore(cb) {\n    if (_loadingMore || _galleryEnd || !GALLERY_PATH) { if (cb) cb(); return; }\n    _loadingMore = true;\n    var seen = ART.map(function (a) { return a.id; }).filter(Boolean).slice(-URL_EXCLUDE_MAX);\n    var qs = '?session=' + encodeURIComponent(BHR_SID)\n      + (state.occ && state.occ !== 'none' ? '&occasion=' + encodeURIComponent(state.occ) : '')\n      + (seen.length ? '&exclude=' + encodeURIComponent(seen.join(',')) : '');\n    fetch(GALLERY_PATH + qs, { headers: { Accept: 'application/json' }, credentials: 'same-origin' })\n      .then(function (r) { return r.ok ? r.json() : null; })\n      .then(function (d) {\n        _loadingMore = false;\n        var fresh = (d && d.images ? d.images : []).filter(function (im) { return seen.indexOf(im.id) === -1; });\n        if (!fresh.length) { _galleryEnd = true; if (cb) cb(); return; }\n        rememberSeen(fresh.map(function (im) { return im.id; }));\n        ART = ART.concat(fresh.map(mapLive));\n        renderAll();\n        if (cb) cb();\n      })\n      .catch(function () { _loadingMore = false; if (cb) cb(); });\n  }\n\n  // What this session has already been shown. loadMore() excludes what is on screen, but loadGallery()\n  // excluded nothing \u2014 so an occasion change or a reload drew from the whole pool again and could hand\n  // back images just seen. With a 220-image pool that reads as \"it keeps repeating\" even though each\n  // draw is uniformly random (60 draws returning 52 distinct is exactly what uniform predicts).\n  // Remembering recent picks makes the session sample WITHOUT replacement, which is what \"show me\n  // another\" is expected to mean.\n  var SEEN_MAX = 150;\n  function seenIds() {\n    try { return JSON.parse(localStorage.getItem('bhr_seen') || '[]'); } catch (e) { return []; }\n  }\n  function rememberSeen(ids) {\n    if (!ids || !ids.length) return;\n    try {\n      var all = seenIds().concat(ids).filter(Boolean), uniq = [];\n      for (var i = all.length - 1; i >= 0 && uniq.length < SEEN_MAX; i--)\n        if (uniq.indexOf(all[i]) === -1) uniq.push(all[i]);\n      uniq.reverse();\n      localStorage.setItem('bhr_seen', JSON.stringify(uniq));\n    } catch (e) { /* private mode: degrade to plain random rather than fail the pull */ }\n  }\n\n  function loadGallery(occId) {\n    if (!GALLERY_PATH) return;\n    var mine = ++_galleryReq;\n    _galleryEnd = false;\n    var skip = seenIds().slice(-URL_EXCLUDE_MAX);\n    function url(ex) {\n      return GALLERY_PATH + '?session=' + encodeURIComponent(BHR_SID)\n        + (occId && occId !== 'none' ? '&occasion=' + encodeURIComponent(occId) : '')\n        + (ex.length ? '&exclude=' + encodeURIComponent(ex.join(',')) : '');\n    }\n    function get(ex) {\n      return fetch(url(ex), { headers: { Accept: 'application/json' }, credentials: 'same-origin' })\n        .then(function (r) { return r.ok ? r.json() : null; });\n    }\n    function apply(d) {\n      if (mine !== _galleryReq || !d || !d.images || !d.images.length) return false;  // supersession\n      rememberSeen(d.images.map(function (im) { return im.id; }));\n      ART = d.images.map(mapLive);\n      artSource = 'live';\n      state.art = 0; state.car = 0; state.lb = null;\n      renderAll();\n      return true;\n    }\n    // Cloudflare is unreachable, or answered with nothing. Show the curated published set, which\n    // Shopify is still serving. Every entry carries a real cloudflare_id, so buying one here is an\n    // ordinary sale of a genuinely unique image \u2014 not the invented-code order this used to produce.\n    function useBackup() {\n      if (mine !== _galleryReq) return;\n      if (!BACKUP_ART.length) { artSource = 'empty'; renderAll(); return; }\n      ART = BACKUP_ART.map(mapBackup);\n      artSource = 'backup';\n      state.art = 0; state.car = 0; state.lb = null;\n      renderAll();\n    }\n\n    get(skip)\n      .then(function (d) {\n        if (apply(d) || mine !== _galleryReq) return;\n        // The exclude list is an optimisation, never a reason to fall back. If the pull failed or came\n        // back empty, ask again for the WHOLE pool \u2014 a shopper seeing a repeat is a far smaller failure\n        // than a shopper never seeing the real gallery at all.\n        if (!skip.length) { useBackup(); return; }\n        return get([]).then(function (d2) { if (!apply(d2)) useBackup(); });\n      })\n      .catch(useBackup);\n  }\n\n  function vals() {\n    // ART[s.art] was read unguarded. One undefined art object throws wherever v.art.src is read,\n    // which kills renderLeft() and leaves the ENTIRE section blank \u2014 a short or reordered gallery must\n    // degrade to the first image, never to nothing.\n    var m = mobile(), s = state, occ = findOcc(), tone = findTone(), pkg = findPkg();\n    var art = ART[s.art] || ART[0] || { code: '', name: '', src: '' };\n    ensureMockups(art);\n    var sizes = pkg.sizes || null;\n    var size = sizes ? Math.min(s.size == null ? (pkg.defaultSize || 0) : s.size, sizes.length - 1) : 0;\n    var pkgPrice = sizes ? sizes[size].price : pkg.price;\n    var pkgVariantId = sizes ? sizes[size].variantId : pkg.variantId;\n    // The sku, not just the variant id: the mockup proxy keys scenes by SKU, and a 5x7 card should\n    // show the 5x7 mockup rather than whichever scene happens to be first.\n    var pkgSku = (sizes ? sizes[size].sku : pkg.sku) || '';\n    var addons = addonsFor(occ);\n    var chosen = addons.filter(function (a) { return s.addons.indexOf(a.id) > -1; });\n    var ex = occ ? EXTRAS[occ.id] : null;\n    var who = s.name || 'their name';\n    // The full preview is what the shopper is BUYING, so every slide that can be real must be real.\n    //\n    // It used to be four static theme PNGs plus two text placeholders \u2014 a sample certificate reading\n    // GARGANTUA, signed by someone else, with a registry number nobody ordered. The accurate renderers\n    // already existed (certPlateHTML / insideTwoHTML composite the customer's own values onto the\n    // measured plates, and mockupStage does add-ons); the slideshow simply predated them and nothing\n    // ever pointed it at them.\n    //\n    // Slides carry a DESCRIPTOR, not HTML: this runs inside vals(), so `v` does not exist yet and\n    // certPlateHTML(v) cannot be called here. renderRail() has `v` and renders `face`/`addon` there.\n    // A greeting card is presented the way it is handled: OUTSIDE (front + back) and OPEN (the two\n    // inside faces), not four disconnected faces. Each face is a full 3/2 card, so a spread is two at\n    // 50% with a fold line between them.\n    var slides = pkg.id === 'basic' ? [\n      { label: copy(C.slideOutside), key: 'slideOutside', face: 'outside' },\n      { label: state.schrod ? copy(C.slideOpenWritten)\n                            : copy(C.slideOpenOwn), key: state.schrod ? 'slideOpenWritten' : 'slideOpenOwn', face: 'open' }\n    ] : [\n      { label: copy(C.slideBox), key: 'slideBox', img: pkg.img, imgStyle: '' },\n      { label: copy(C.slideCert), key: 'slideCert', face: 'cert' },\n      { label: copy(C.slidePrint), key: 'slidePrint', img: art.src, imgStyle: '' }\n      // No \"Pin + deed\" slide. There is no photography for the pin or the deed, so it rendered as an\n      // empty panel with a line of text \u2014 a blank page in a preview whose whole job is showing the\n      // shopper what they get. Add it back when there is a photograph to put in it.\n    ];\n    // Every add-on they actually chose, mocked up on their own art \u2014 \"all add ons added\" is the point\n    // of a full preview, and these were absent entirely.\n    for (var ci = 0; ci < chosen.length; ci++) {\n      var csz = sizeOf(chosen[ci]);\n      slides.push({ label: chosen[ci].name + (csz && csz.label ? ' \u2014 ' + csz.label : ''), addon: chosen[ci].id });\n    }\n    var slide = Math.min(s.slide, slides.length - 1);\n    var exBits = ex ? ex.fields.map(function (f) {\n      var v = s.extra[f.key] || (f.options ? f.options[0] : '');\n      if (!v) return null;\n      if (f.key === 'age') return 'Turning ' + v;\n      if (f.key === 'annNo') return v + ' years';\n      return v;\n    }).filter(Boolean) : [];\n    var total = pkgPrice + chosen.reduce(function (n, a) { return n + sizeOf(a).price; }, 0);\n    var maxStart = Math.max(0, ART.length - (m ? 1 : 3));\n    var car = Math.min(s.car, maxStart);\n    return { m: m, s: s, occ: occ, tone: tone, art: art, pkg: pkg, chosen: chosen, ex: ex, addons: addons,\n      slides: slides, slide: slide, exBits: exBits, total: total, maxStart: maxStart, car: car,\n      sizes: sizes, size: size, pkgPrice: pkgPrice, pkgVariantId: pkgVariantId, pkgSku: pkgSku };\n  }\n\n  /* ---------- render helpers ---------- */\n  // The selected-state treatment: a spinning photon ring plus a pulsing glow. Defined once because the\n  // occasion grid and the option pickers are meant to feel identical \u2014 two copies would drift the first\n  // time either was touched. `sub` is an optional helper line under the label.\n  function pickerButton(attrs, label, sub, icon, on, sizePx, st) {\n    var ring = on ? 'background:radial-gradient(circle,rgba(224,123,31,0.18),rgba(224,123,31,0) 68%)' : '';\n    var photon = on ? '<span style=\"position:absolute;inset:-6px;border-radius:50%;background:conic-gradient(from 0deg,rgba(224,123,31,0) 0deg,rgba(224,123,31,0) 190deg,#e07b1f 300deg,#ffd7a5 344deg,rgba(224,123,31,0) 360deg);-webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 3px));mask:radial-gradient(farthest-side,transparent calc(100% - 3px),#000 calc(100% - 3px));animation:photonSpin 2.8s linear infinite\"></span><span style=\"position:absolute;inset:-10px;border-radius:50%;background:radial-gradient(circle,rgba(224,123,31,0.34),rgba(224,123,31,0) 70%);animation:photonGlow 2.8s ease-in-out infinite\"></span>' : '';\n    return '<button ' + attrs + ' style=\"min-width:0;background:none;border:none;padding:2px 0;cursor:pointer;display:flex;flex-direction:column;align-items:center;gap:7px;color:inherit\">'\n      + '<span style=\"position:relative;width:' + (sizePx + 2) + 'px;height:' + (sizePx + 2) + 'px;display:flex;align-items:center;justify-content:center\">' + photon\n      + '<span style=\"position:relative;width:' + sizePx + 'px;height:' + sizePx + 'px;border-radius:50%;display:flex;align-items:center;justify-content:center;box-sizing:border-box;transition:all .18s ease;' + ring + '\">'\n      + '<img src=\"' + icon + '\" alt=\"\" style=\"width:' + sizePx + 'px;height:' + sizePx + 'px;object-fit:contain;display:block;opacity:' + (on ? '1' : '0.62') + '\"></span></span>'\n      + '<span style=\"display:flex;flex-direction:column;gap:2px\">'\n      + '<span style=\"font-size:' + LABEL + 'px;line-height:1.2;text-align:center;color:' + (on ? INK : MUTED) + ov(st) + '\">' + esc(label) + '</span>'\n      + (sub ? '<span style=\"font-size:' + px(9.5) + 'px;line-height:1.25;text-align:center;color:' + (on ? '#b9924f' : MUTED) + '\">' + esc(sub) + '</span>' : '')\n      + '</span></button>';\n  }\n\n  // A field whose options carry `from` (MM-DD) is a calendar: pre-select the window covering today.\n  // Someone shopping a horoscope card almost certainly wants the current sign \u2014 and if the next window\n  // opens within LOOKAHEAD days, that one instead, because cards are bought ahead of the date.\n  var OPTION_LOOKAHEAD_DAYS = 10;\n  function defaultByDate(meta, options, now) {\n    now = now || new Date();\n    var DAY = 86400000, starts = [];\n    for (var i = 0; i < options.length; i++) {\n      var m = meta[options[i]];\n      if (!m || !m.from) return '';                     // not a calendar field \u2014 no opinion\n      var p = m.from.split('-'), mo = +p[0] - 1, d = +p[1];\n      // Windows can straddle the new year (Capricorn opens in December, closes in January), so the\n      // window covering today may have opened LAST year. Consider the neighbouring years too.\n      for (var dy = -1; dy <= 1; dy++) starts.push({ id: options[i], t: new Date(now.getFullYear() + dy, mo, d) });\n    }\n    starts.sort(function (a, b) { return a.t - b.t; });\n    var cur = null, next = null;\n    for (var j = 0; j < starts.length; j++) {\n      if (starts[j].t <= now) cur = starts[j];\n      else { next = starts[j]; break; }\n    }\n    if (!cur) return next ? next.id : '';\n    if (next && (next.t - now) <= OPTION_LOOKAHEAD_DAYS * DAY) return next.id;\n    return cur.id;\n  }\n\n  /**\n   * `?sign=leo` (spec 025): the sign marquee on the Hole-O-scopes page links back here with a sign,\n   * and that sign wins over today's. Matched against the field's own options, case-insensitively, so\n   * a handle in the URL becomes the option's spelling; anything else is ignored.\n   */\n  function requestedSign(options) {\n    var m = /[?&]sign=([^&#]+)/.exec(window.location.search || '');\n    if (!m) return '';\n    var want = decodeURIComponent(m[1]).replace(/\\+/g, ' ').toLowerCase();\n    for (var i = 0; i < options.length; i++) if (String(options[i]).toLowerCase() === want) return options[i];\n    return '';\n  }\n\n  // Runs when the occasion changes (which clears state.extra) and once at start-up. Never overwrites a\n  // choice the shopper has already made.\n  function seedExtraDefaults() {\n    var ex = EXTRAS[state.occ], meta = CFG.optionMeta || {};\n    if (!ex || !ex.fields) return;\n    for (var i = 0; i < ex.fields.length; i++) {\n      var f = ex.fields[i];\n      if (state.extra[f.key] || !f.options || !meta[f.key]) continue;\n      var d = (MODE === 'hole-o-scopes' && requestedSign(f.options)) || defaultByDate(meta[f.key], f.options);\n      if (d) state.extra[f.key] = d;\n    }\n  }\n\n  // An occasion with no icon metafield falls back to a theme asset that may not exist yet, and a new\n  // event would then render as a broken image. Swap in its initial instead: undecorated, not broken.\n  // Capture phase because `error` does not bubble.\n  document.addEventListener('error', function (e) {\n    var img = e.target;\n    if (!img || img.tagName !== 'IMG' || !img.closest) return;\n    var btn = img.closest('[data-act=\"occ\"],[data-act=\"extraPick\"]');\n    if (!btn) return;\n    img.style.display = 'none';\n    var host = img.parentNode;\n    if (host.querySelector('.bhr-icon-fallback')) return;\n    var span = document.createElement('span');\n    span.className = 'bhr-icon-fallback';\n    span.textContent = (btn.textContent || '?').trim().charAt(0).toUpperCase();\n    host.appendChild(span);\n  }, true);\n\n  // ---- Hole-O-scopes (spec 025) --------------------------------------------------------------\n  // One engine, a second mode. Everything below renders only when the section decided the mode is\n  // hole-o-scopes (the flag is on and the entry occasion is standalone); in the ordinary mode none\n  // of it is reached, which is what lets the code ship with the flag off.\n  var HOLEO = MODE === 'hole-o-scopes';\n  var ACRO = CFG.acrostic || {};\n  /**\n   * Nebula's capitals are the display face, and its lowercase a, v, i and y are the readable forms of\n   * those four (the rest of its lowercase reads as capitals). Operator, 2026-09-03: \"lower case A and\n   * V and I and Y in DIVA\". Applied wherever Nebula sets sign text; never to the bold (Nunito) style.\n   */\n  function nebulaCase(s) {\n    return String(s || '').toUpperCase().replace(/[AVIY]/g, function (c) { return c.toLowerCase(); });\n  }\n  /**\n   * The largest size, in px, at which `text` set in `family` (with `tracking` em of letter-spacing)\n   * fits `maxPx` wide, walked down from `startPx` to `minPx`. SAGITTARIUS in Nebula at 30px ran\n   * out of its 200px column and over the next one (operator, 2026-09-03); LEO should stay at 30.\n   * Measured on a canvas, so it follows the face the browser actually has.\n   */\n  /**\n   * After a render, the name is fitted to the column it is actually in: the column is 200px on a\n   * wide card and narrower on a narrow one (operator, 2026-09-03: the name must start no further\n   * left than the description under it, and sit centred from there). The canvas guess above the\n   * render avoids a visible jump; this is the measurement that is true.\n   */\n  function fitHeroName(root) {\n    // The card stacks (icon and name, then the attributes, then the description) when it is too\n    // narrow for two columns: the attributes ran off the card at about 430px (operator's screen,\n    // 2026-09-03). Measured on the card itself rather than the viewport, because the card's width\n    // is the customizer's layout's to decide.\n    var cards = (root || document).querySelectorAll('.bhr-sign-explainer');\n    for (var c = 0; c < cards.length; c++) {\n      if (cards[c].clientWidth) cards[c].classList.toggle('is-narrow', cards[c].clientWidth < 560);\n    }\n    var els = (root || document).querySelectorAll('.bhr-sign-hero-name');\n    for (var i = 0; i < els.length; i++) {\n      var el = els[i], col = el.parentElement;\n      if (!col) continue;\n      var max = col.clientWidth;\n      if (!max) continue;\n      fitPx._colW = max;\n      var cur = parseFloat(el.style.fontSize) || 30;\n      el.style.fontSize = cur + 'px';\n      var guard = 0;\n      while (el.scrollWidth > max && cur > 16 && guard++ < 20) { cur -= 1; el.style.fontSize = cur + 'px'; }\n    }\n  }\n  function fitPx(text, family, maxPx, startPx, minPx, tracking) {\n    var cv = fitPx._cv || (fitPx._cv = document.createElement('canvas'));\n    var ctx = cv.getContext && cv.getContext('2d');\n    if (!ctx) return startPx;\n    for (var cur = startPx; cur > minPx; cur -= 1) {\n      ctx.font = cur + 'px ' + family;\n      var w = ctx.measureText(text).width + (tracking || 0) * cur * Math.max(0, text.length - 1);\n      if (w <= maxPx) return cur;\n    }\n    return minPx;\n  }\n  function findSign(name) {\n    for (var i = 0; i < SIGNS.length; i++) if (SIGNS[i].name === name) return SIGNS[i];\n    return null;\n  }\n  /** The chosen category's KEY, always one the store offers; the label is presentation. */\n  function currentCategory() {\n    if (!CATS.length) return '';\n    for (var i = 0; i < CATS.length; i++) if (CATS[i].key === state.category) return state.category;\n    return CATS[0].key;\n  }\n  function categoryLabel(key) {\n    for (var i = 0; i < CATS.length; i++) if (CATS[i].key === key) return CATS[i].label;\n    return key;\n  }\n  /**\n   * The sign explainer: dates, element, ruler, and the four traits stacked so their initials read\n   * down. The word is exposed once, after the list, for assistive technology; sighted readers tap\n   * \"Read down.\" to have it said. Every string here is store data or curator copy; the only\n   * markup decision is the emphasis, which the theme editor sets (a size and a style, not words).\n   */\n  function signExplainer(sign) {\n    if (!sign) return '';\n    var traits = (sign.traits || []).filter(Boolean);\n    var word = sign.word || traits.map(function (t) { return t.charAt(0); }).join('').toUpperCase();\n    var nebula = (ACRO.emphasis || 'display') !== 'bold';\n    var rows = traits.map(function (t) {\n      return '<li><span class=\"bhr-acrostic-initial\" aria-hidden=\"true\">' + esc(nebula ? nebulaCase(t.charAt(0)) : t.charAt(0)) + '</span>'\n        + '<span class=\"bhr-acrostic-rest\" aria-hidden=\"true\">' + esc(t.slice(1)) + '</span>'\n        + '<span class=\"bhr-visually-hidden\">' + esc(t) + '</span></li>';\n    }).join('');\n    var facts = [[copy(C.holeoDatesLabel), sign.dates, 'holeoDatesLabel', 'dates'], [copy(C.holeoElementLabel), sign.element, 'holeoElementLabel', 'element'], [copy(C.holeoRulerLabel), sign.ruler, 'holeoRulerLabel', 'ruler']]\n      .filter(function (f) { return f[1]; })\n      .map(function (f) { return '<div class=\"bhr-sign-fact\"><span class=\"bhr-sign-fact-k\" style=\"' + ov(STYLES[f[2]]) + '\">' + esc(f[0]) + '</span><span class=\"bhr-sign-fact-v\" style=\"' + ov(styleOf(sign.styles, f[3])) + '\">' + esc(f[1]) + '</span></div>'; })\n      .join('');\n    var spelled = (copy(C.holeoWordPrefix) + ' ' + word).trim();\n    // Every format knob is a theme-editor setting carried in CFG.acrostic; the words are the sign's.\n    var vars = '--bhr-acrostic-size:' + (Number(ACRO.size) || 40) + 'px'\n      + ';--bhr-acrostic-scale:' + ((Number(ACRO.traitScale) || 48) / 100)\n      + ';--bhr-acrostic-gap:' + (ACRO.gap == null ? 2 : (Number(ACRO.gap) || 0)) + 'px'\n      + (ACRO.initialColor ? ';--bhr-acrostic-initial:' + esc(String(ACRO.initialColor)) : '')\n      + (ACRO.traitColor ? ';--bhr-acrostic-trait:' + esc(String(ACRO.traitColor)) : '');\n    // Operator, 2026-09-03: no \"Read down.\" hint by default, and the acrostic centred in its column.\n    var reveal = ACRO.reveal || 'never';\n    var tail = reveal === 'always'\n      ? '<span class=\"bhr-acrostic-spelled\" aria-hidden=\"true\" style=\"' + ov(STYLES.holeoWordPrefix) + '\">' + esc(spelled) + '</span>'\n      : reveal === 'never' ? ''\n      : '<button type=\"button\" data-act=\"acrostic\" class=\"bhr-acrostic-reveal' + (state.acrosticShown ? ' is-shown' : '') + '\" aria-pressed=\"' + (state.acrosticShown ? 'true' : 'false') + '\" style=\"' + ov(state.acrosticShown ? STYLES.holeoWordPrefix : STYLES.holeoReadDown) + '\">'\n        + esc(state.acrosticShown ? spelled : copy(C.holeoReadDown)) + '</button>';\n    // The card (operator, 2026-09-03): the sign large on the left, its name under it and the facts\n    // under that; the attributes on the right under a small heading; the sign's own paragraph, written\n    // in curator or the admin, across the bottom when there is one.\n    var about = String(sign.about || '').trim();\n    return '<div class=\"bhr-sign-explainer\" style=\"' + vars + '\" data-emphasis=\"' + esc(ACRO.emphasis || 'display') + '\" data-case=\"' + esc(ACRO['case'] || 'written') + '\" data-align=\"' + esc(ACRO.align || 'center') + '\">'\n      + '<div class=\"bhr-sign-hero\">'\n      + (sign.icon ? '<img class=\"bhr-sign-hero-icon\" src=\"' + esc(sign.icon) + '\" alt=\"\" width=\"150\" height=\"150\" loading=\"lazy\">' : '')\n      + '<div class=\"bhr-sign-hero-name\" style=\"font-size:' + fitPx(nebulaCase(sign.name), \"'Nebula', 'Space Mono', monospace\", (fitPx._colW || 200) - 4, 30, 16, 0.06) + 'px' + ov(styleOf(sign.styles, 'name')) + '\">' + esc(nebulaCase(sign.name)) + '</div>'\n      + (facts ? '<div class=\"bhr-sign-facts\">' + facts + '</div>' : '')\n      + '</div>'\n      + '<div class=\"bhr-sign-attrs\">'\n      + '<div class=\"bhr-sign-explainer-title\" style=\"' + ov(STYLES.holeoExplainerTitle) + '\">' + esc(copy(C.holeoExplainerTitle)) + '</div>'\n      + '<ol class=\"bhr-acrostic\" aria-label=\"' + esc(sign.name) + '\">' + rows + '</ol>'\n      + '<span class=\"bhr-visually-hidden\">' + esc(spelled) + '</span>'\n      + tail\n      + '</div>'\n      + (about ? '<div class=\"bhr-sign-about\" style=\"' + ov(styleOf(sign.styles, 'about')) + '\">' + esc(about) + '</div>' : '')\n      + '</div>';\n  }\n  function categoryPicker() {\n    if (!CATS.length) return '';\n    var cur = currentCategory();\n    return '<div class=\"bhr-category-picker\" role=\"group\">' + CATS.map(function (c) {\n      var on = c.key === cur;\n      return '<button type=\"button\" data-act=\"category\" data-id=\"' + esc(c.key) + '\" aria-pressed=\"' + (on ? 'true' : 'false') + '\" class=\"bhr-category' + (on ? ' is-on' : '') + '\">'\n        + '<span class=\"bhr-category-label\" style=\"' + ov(styleOf(c.styles, 'label')) + '\">' + esc(c.label) + '</span>'\n        + (c.blurb ? '<span class=\"bhr-category-blurb\" style=\"' + ov(styleOf(c.styles, 'blurb')) + '\">' + esc(c.blurb) + '</span>' : '') + '</button>';\n    }).join('') + '</div>';\n  }\n\n  function occGrid(v) {\n    return OCC.map(function (o) {\n      return pickerButton('data-act=\"occ\" data-id=\"' + o.id + '\"', o.name, '', o.icon, state.occ === o.id, 70, styleOf(o.styles, 'name'));\n    }).join('');\n  }\n  // The panel is the event's own: its icon beside its own name, a divider, then the description the\n  // operator wrote for it. Nothing a shopper reads is written here \u2014 the event owns its copy and the\n  // empty state's copy is a setting \u2014 which is what makes this panel translatable at all (A10).\n  // Sizes are settings too, so tuning the panel needs no deploy.\n  function pitchPanel(v) {\n    var occ = v.occ, head, body;\n    // The type group knobs (spec 031 slice 2): T already folded in the theme-editor settings as fallbacks.\n    var ico = T.panelIconSize, tsz = HEADING, bsz = T.baseSize;\n    if (occ) {\n      // Dimensions are declared so changing occasion cannot shift the layout. The icon is the same\n      // one the selector buttons use; an event with none simply renders its name alone.\n      var ic = occ.icon\n        ? '<img src=\"' + esc(occ.icon) + '\" alt=\"\" width=\"' + ico + '\" height=\"' + ico + '\" style=\"display:block;width:' + ico + 'px;height:' + ico + 'px;object-fit:contain;flex:0 0 auto\">'\n        : '';\n      head = '<div style=\"display:flex;align-items:center;justify-content:center;gap:14px;min-width:0;text-align:center\">' + ic\n           + '<div style=\"font-size:' + tsz + 'px;font-weight:500;line-height:1.25' + ov(styleOf(occ.styles, 'name')) + '\">' + esc(occ.name) + '</div></div>';\n      body = occ.pitch || '';\n    } else {\n      head = '<div style=\"text-align:center\"><div style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(10.5) + 'px;letter-spacing:0.18em;text-transform:uppercase;color:#e07b1f' + ov(STYLES.panelEmptyHeading) + '\">' + esc(C.panelEmptyHeading) + '</div>'\n           + '<div style=\"font-size:' + tsz + 'px;font-weight:500;line-height:1.25;margin-top:6px' + ov(STYLES.panelEmptyTitle) + '\">' + esc(C.panelEmptyTitle) + '</div></div>';\n      body = enc(C.panelEmptyBody);\n    }\n    // Optional supporting artwork. Absent is indistinguishable from the feature not existing.\n    var art = (occ && occ.panelImage)\n      ? '<img src=\"' + esc(occ.panelImage) + '\" alt=\"\" width=\"600\" height=\"240\" style=\"display:block;width:' + T.panelImageScale + '%;max-width:100%;margin:0 auto;height:auto;aspect-ratio:5/2;object-fit:cover;border-radius:8px\">'\n      : '';\n    // No body means no divider: a rule with nothing beneath it is worse than no rule.\n    // Hug the content unless the operator asks the panel to fill the grid height: a tall empty box\n    // beside four rows of icons read as \"a tremendous amount of whitespace\" (operator, 2026-09-27).\n    var fill = T.panelFillHeight;\n    return '<div style=\"flex:1 1 auto;min-width:0;display:flex;flex-direction:column;justify-content:' + (fill ? 'center' : 'flex-start') + ';' + (fill ? '' : 'align-self:flex-start;') + 'gap:10px;background:#101013;border:1px solid #232329;border-radius:12px;padding:18px\">'\n      + head\n      + (body ? '<div style=\"height:1px;background:#232329;margin:4px 0 2px 0\"></div>' : '')\n      + (body ? '<div style=\"font-size:' + bsz + 'px;color:' + MUTED + ';line-height:1.65' + ov(occ ? styleOf(occ.styles, 'pitch') : STYLES.panelEmptyBody) + '\">' + body + '</div>' : '')\n      + art + '</div>';\n  }\n  // One occasion-extra field for the detail sub-step. A required-but-empty field gets an orange border + '*'.\n  function extraField(f) {\n    var val = state.extra[f.key] || '';\n    var req = !!f.required, empty = req && !val, bd = empty ? '#e07b1f' : '#2b2b32';\n    var ctrl;\n    // A dropdown hides twelve choices behind a click. When the section supplies artwork for a field's\n    // values, show them all instead \u2014 same selection treatment as the occasions, and the helper line\n    // carries the date range so nobody has to know their recipient's sign to buy for them.\n    var meta = (CFG.optionMeta || {})[f.key];\n    if (f.options && meta) {\n      ctrl = '<div class=\"bhr-opt-picker\">' + f.options.map(function (op) {\n        var m = meta[op] || {};\n        return pickerButton('data-act=\"extraPick\" data-key=\"' + f.key + '\" data-id=\"' + esc(op) + '\"',\n                            op, m.note || '', m.icon || '', val === op, 52);\n      }).join('') + '</div>';\n    } else if (f.options) {\n      ctrl = '<select data-act=\"extra\" data-key=\"' + f.key + '\" style=\"background:#0b0b0d;border:1px solid ' + bd + ';border-radius:8px;padding:11px 32px 11px 12px;color:' + INK + ';font-size:' + px(14) + 'px;outline:none;appearance:none;' + errBox(f.key) + '\">'\n        + '<option value=\"\">' + (req ? 'Choose\u2026' : '\u2014') + '</option>'\n        + f.options.map(function (op) { return '<option ' + (op === val ? 'selected' : '') + '>' + esc(op) + '</option>'; }).join('') + '</select>';\n    } else {\n      ctrl = '<input type=\"' + (f.type || 'text') + '\" value=\"' + esc(val) + '\" data-act=\"extra\" data-key=\"' + f.key + '\" placeholder=\"' + esc(f.hint || '') + '\" style=\"background:#0b0b0d;border:1px solid ' + bd + ';border-radius:8px;padding:11px 12px;color:' + INK + ';font-size:' + px(14) + 'px;outline:none;' + errBox(f.key) + '\">';\n    }\n    // A flagged field prints as the registration date, so the label says so \u2014 otherwise the shopper\n    // types a date into an event detail and has no idea it reached the certificate.\n    var regNote = f.registers ? '<span style=\"font-size:' + px(11) + 'px;color:' + MUTED + '' + ov(STYLES.detailsRegisters) + '\">'\n      + esc(copy(C.detailsRegisters)) + '</span>' : '';\n    return '<label style=\"display:flex;flex-direction:column;gap:5px\"><span style=\"font-size:' + LABEL + 'px;color:' + MUTED + '' + ov(styleOf(occStyles(), 'detail_fields')) + '\">' + esc(f.label) + (req ? ' <span style=\"color:#e07b1f\">*</span>' : ' <span style=\"color:' + MUTED + ';font-size:' + px(10.5) + 'px\">(optional)</span>') + '</span>' + ctrl + errNote(f.key, fill(copy(C.fieldRequired), { field: f.label || 'this event' })) + '' + regNote + '</label>';\n  }\n  // Step numbers, shared: renderLeft labels the sections with these and the click handler needs to name\n  // one to advance past it. Numbering is not contiguous in the DOM \u2014 occasion and tone share a section.\n  var STEP_N = { p: '01', a: '02', at: '03', b: '04', c: '05', d: '06' };\n\n  function step(n, title, note, body, extraStyle) {\n    var tk = Array.isArray(title) ? title[1] : null, nk = Array.isArray(note) ? note[1] : null;\n    if (Array.isArray(title)) title = title[0];\n    if (Array.isArray(note)) note = note[0];\n    return '<section id=\"bhr-step-' + n + '\" style=\"background:#141417;border:1px solid #232329;border-radius:14px;padding:18px 20px 20px 20px;' + (extraStyle || '') + '\">'\n      + '<div style=\"display:flex;align-items:baseline;gap:12px;margin-bottom:14px\"><span style=\"' + priceStyle(Math.round((C.priceSize || 19) * 0.8)) + ';letter-spacing:0.18em\">' + n + '</span>'\n      + '<span style=\"font-size:' + HEADING + 'px;font-weight:700' + ov(tk ? STYLES[tk] : null) + '\">' + esc(title) + '</span><span style=\"font-size:' + px(12) + 'px;color:' + MUTED + ';margin-left:auto' + ov(nk ? STYLES[nk] : null) + '\">' + esc(note) + '</span></div>' + body + '</section>';\n  }\n\n  // ---- The card panels (personalize step) ----\n  // The two INSIDE faces, which are the only ones the shopper changes: the certificate, and the message.\n  // The front is the chosen black hole and is already the subject of the carousel above; the back is our\n  // static branding. Neither is repeated here. The message is written on-card, unless the shopper picks\n  // \"Schrodinger's Card/Box\", in which case we write it in a tone.\n  // MEASURED, not guessed: the widest printed occasion line (\"Happy valentine's Day!\") fills 78% of\n  // the title strip, and all three card sizes independently work out to ~28 characters at full width.\n  // 25 leaves room for wide glyphs at every size, so a title that fits 4x6 also fits 5x7 and A5 \u2014\n  // which matters because the shopper can change card size after typing.\n  var TITLE_MAX = 25;\n\n  // THE MESSAGE FIELD IS contenteditable, so its value is HTML, and a paste brings whatever markup came\n  // with it \u2014 including <img src=x onerror=...>. That value is seeded back into the editor, mirrored into\n  // the card preview via innerHTML, and sent to the cart as the _message_html line-item property, so an\n  // unsanitised paste survives every re-render and is persisted onto the order.\n  //\n  // Parsing is done with DOMParser, NOT `div.innerHTML = html`: a DOMParser document is inert, while a\n  // detached div still constructs elements and lets an <img> begin loading, which is enough to fire\n  // onerror. Only the inline tags the card can actually render survive, and each survivor is rebuilt as a\n  // FRESH element so no attribute \u2014 style, onclick, srcset \u2014 can come through with it.\n  var MSG_TAGS = { B: 1, STRONG: 1, I: 1, EM: 1, U: 1, BR: 1 };\n  // Dropped WITH their contents. Every other unknown tag keeps its text \u2014 <div>hello</div> should still\n  // say hello \u2014 but the inside of a <script> or <style> is code, and keeping it prints \"alert(1)\" on\n  // someone's certificate. Harmless, and absurd.\n  var MSG_DROP = { SCRIPT: 1, STYLE: 1, TEMPLATE: 1, NOSCRIPT: 1 };\n  function parseInert(html) {\n    return new DOMParser().parseFromString('<body>' + (html || '') + '</body>', 'text/html').body;\n  }\n  // A block element is a LINE BREAK the shopper typed. contenteditable wraps every line after the\n  // first in a <div> (Chrome) or <p>, and unwrapping those without a separator fused the lines \u2014\n  // \"\u2026did you pay?Just like\u2026\" reached the printed card that way on order #BHR1016. The boundary is\n  // kept as an explicit <br> so the preview, the cart property and the renderer all see the same break.\n  var MSG_BLOCK = { DIV: 1, P: 1 };\n  function cleanMsg(html) {\n    var out = document.createElement('div');\n    function brk(to) {\n      if (to.lastChild && to.lastChild.nodeName !== 'BR') to.appendChild(document.createElement('br'));\n    }\n    (function walk(from, to) {\n      for (var n = from.firstChild; n; n = n.nextSibling) {\n        if (n.nodeType === 3) { to.appendChild(document.createTextNode(n.nodeValue)); continue; }\n        if (n.nodeType !== 1) continue;\n        if (MSG_DROP[n.nodeName]) continue;\n        if (MSG_TAGS[n.nodeName]) {\n          var el = document.createElement(n.nodeName.toLowerCase());\n          to.appendChild(el); walk(n, el);\n        } else {\n          if (MSG_BLOCK[n.nodeName]) brk(to);\n          walk(n, to);            // drop the tag, keep the words inside it\n          if (MSG_BLOCK[n.nodeName] && n.nextSibling) brk(to);\n        }\n      }\n    })(parseInert(html), out);\n    return out.innerHTML;\n  }\n  // Cleans first rather than trusting the caller: today it is only ever handed an already-clean\n  // state.msg, but that is call-order luck, and this value becomes the cart's Message property.\n  // Serialized by hand because textContent DROPS <br> without a newline \u2014 the renderer splits the\n  // message on '\\n' (render_inside2.py), so the break must survive as a character here.\n  /**\n   * Occasions whose inside message is ALWAYS Registry-written. A horoscope card IS the reading: the\n   * drawn title names the sign and the copy is drawn for it, so letting the shopper replace the inside\n   * would ship a horoscope card containing no horoscope.\n   *\n   * `C.schrodOnly`, NOT `CFG.schrodOnly`: the section emits it inside `copy`, so read off CFG it was\n   * undefined at every render and the literal below always won \u2014 ticking \"registry writes only\" on a\n   * second occasion in curator did nothing at all. Invisible until now only because horoscope is the\n   * one occasion that has the flag, so the stale literal happened to be the right answer.\n   *\n   * ABSENT and EMPTY are different, exactly as they are for copy. Absent means the store predates the\n   * flag, and horoscope is the historic default. Empty means every box was deliberately unticked, and\n   * `|| 'horoscope'` would have overruled the operator and locked the writer on horoscope anyway.\n   */\n  function writerLocked() {\n    if (!state.occ) return false;\n    var ids = String(C.schrodOnly == null ? 'horoscope' : C.schrodOnly).toLowerCase().split(',');\n    for (var i = 0; i < ids.length; i++) if (ids[i].trim() === String(state.occ).toLowerCase()) return true;\n    return false;\n  }\n  function msgText(html) {\n    var text = '';\n    (function walk(n) {\n      for (var c = n.firstChild; c; c = c.nextSibling) {\n        if (c.nodeType === 3) text += c.nodeValue;\n        else if (c.nodeName === 'BR') text += '\\n';\n        else walk(c);\n      }\n    })(parseInert(cleanMsg(html)));\n    return text.replace(/\\u00a0/g, ' ').trim();\n  }\n  function msgLen(html) { return msgText(html).length; }\n  function hasHtml(html) { return /<(b|strong|i|em|u|br)\\b/i.test(html || ''); }\n  // Placeholder auto-copy for Schrodinger's Card until the certificate/greeting LLM is wired in.\n  // The \"we write it\" preview. Two things were wrong with the one-liner this replaces.\n  //\n  //   1. It contained a literal em-dash. NEVER an em-dash in generated copy: it is the strongest\n  //      \"written by a machine\" tell in English prose, and the rule is absolute (ADR-0005). It is\n  //      enforced by strip_dashes() server-side, but this string never went near that function.\n  //   2. It read only tone.line and occ.name, so choosing a different STAR SIGN changed the plate and\n  //      left the words identical. The sign lives in state.extra, exactly where i2Plate() looks for it.\n  function selectedOptionLabel() {\n    var meta = CFG.optionMeta || {};\n    for (var key in meta) {\n      var sel = state.extra[key];\n      if (sel && meta[key][sel]) return sel;\n    }\n    return '';\n  }\n\n  /**\n   * The shapes a drawn message can take.\n   *\n   * STILL THE PLACEHOLDER. The real inside copy is curated in curator (/curate/text), reviewed per\n   * bucket, and meant to be DRAWN from that pool at order time \\u2014 a title and a message picked\n   * independently within one occasion-and-tone bucket. That pool has no route out to the storefront\n   * yet: the theme can only reach the /apps/gallery App Proxy, and nothing there serves text. So these\n   * are still assembled from the tone line and the shopper's own selections.\n   *\n   * What they now do is VARY, which the single hard-coded sentence could not. That matters because the\n   * re-draw button below is worthless against a function that returns the same string every time, and\n   * a button that visibly does nothing is worse than no button.\n   *\n   * When the pool endpoint lands, drawMessage() is the ONE function to change \\u2014 replace the local\n   * variant with a bucket-scoped fetch and everything else here already works.\n   */\n  function copyShapes(who, occ, opt) {\n    var v = { who: who, occasion: occ, detail: opt };\n    return opt ? [\n      fill(copy(C.messageDetail1), v),\n      fill(copy(C.messageDetail2), v),\n      fill(copy(C.messageDetail3), v),\n      fill(copy(C.messageDetail4), v)\n    ] : [\n      fill(copy(C.messagePlain1), v),\n      fill(copy(C.messagePlain2), v),\n      fill(copy(C.messagePlain3), v),\n      fill(copy(C.messagePlain4), v)\n    ];\n  }\n\n  /* ---------- the curated pool ----------------------------------------------------------------\n   *\n   * The copy on the card comes from text-worker now, through the App Proxy: human-reviewed pairs out\n   * of curator_db, not the template below. Shopify signs `/apps/gallery/*` on the way through, which\n   * is what makes the endpoint reachable from a storefront and from nowhere else.\n   *\n   * ASYNC INTO A SYNCHRONOUS RENDER. drawnPair() is called while building the certificate and the\n   * inside-2 panel, so it cannot await anything. The fetch therefore fills `state.drawn` and asks for\n   * a repaint; drawnPair() only ever reads what is already there. That is also why a draw is triggered\n   * by the things that CHANGE THE BUCKET rather than by rendering \u2014 rendering happens on every\n   * keystroke, and a fetch per keystroke would be a self-inflicted rate limit.\n   */\n  var _drawSeq = 0;\n  function drawKey() {\n    // In Hole-O-scopes mode the bucket is sign \u00D7 category (spec 025 FR-012), so both are in the key\n    // and changing either re-draws. In the ordinary mode the key is what it always was.\n    return [state.occ, state.tone, HOLEO ? horoscopeSign() + '|' + currentCategory() : ''].join('|');\n  }\n  /** The chosen zodiac sign, detected the way i2Plate() detects it: the selected extra whose\n   *  option meta carries a horoscope plate. '' on every non-horoscope occasion. */\n  function horoscopeSign() {\n    var meta = CFG.optionMeta || {};\n    for (var key in meta) {\n      var sel = state.extra[key];\n      if (sel && meta[key][sel] && String(meta[key][sel].plate || '').indexOf('horoscope-') > -1) return sel;\n    }\n    return '';\n  }\n  function fetchDrawn(opts) {\n    opts = opts || {};\n    if (!state.schrod || !GALLERY_PATH) return;\n    var key = drawKey();\n    var exclude = opts.reroll ? (state.drawnSeen || []).slice(-10) : [];\n    var seq = ++_drawSeq;\n    state.drawState = 'loading';\n    // TWO PATHS, per the copy model: a horoscope is keyed by SIGN (surface=horoscope, no tone);\n    // everything else by occasion \u00D7 tone. This used to hardcode card_message for every occasion,\n    // so the entire sign-keyed horoscope pool \u2014 including hand-authored readings \u2014 was unreachable\n    // from the storefront: cards sold, pool never served, and nothing said so.\n    var sign = horoscopeSign();\n    var qs = (sign\n        ? '?surface=horoscope&sign=' + encodeURIComponent(sign)\n          + (HOLEO && currentCategory() ? '&category=' + encodeURIComponent(currentCategory()) : '')\n        : '?surface=card_message'\n          + (state.occ && state.occ !== 'none' ? '&event=' + encodeURIComponent(state.occ) : '')\n          + '&tone=' + encodeURIComponent(state.tone || 'cheeky'))\n      + '&session=' + encodeURIComponent(BHR_SID)\n      + (exclude.length ? '&exclude=' + encodeURIComponent(exclude.join(',')) : '');\n    // A re-draw costs a cat, and the grant (this one, or one a reload left behind) buys the next\n    // supply. The service decides whether it is valid yet; this side never consults a clock.\n    var grant = opts.grant || (opts.reroll ? storedGrant() : '');\n    if (opts.reroll) qs += '&reroll=1';\n    if (grant) qs += '&grant=' + encodeURIComponent(grant);\n    fetch(GALLERY_PATH + '/message' + qs, { headers: { Accept: 'application/json' }, credentials: 'same-origin' })\n      .then(function (r) { return r.ok ? r.json() : null; })\n      .then(function (d) {\n        // Out-of-order responses are the classic bug here: change occasion twice quickly and the FIRST\n        // response can land last, putting a divorce message on a birthday card. Only the newest\n        // request may write.\n        if (seq !== _drawSeq) return;\n        if (!d) { state.drawState = 'error'; renderAll(); return; }\n        if ('cats' in d) state.cats = d.cats;\n        // Out of cats: the card keeps the message it has while the cats are rounded up.\n        if (!d.pair && d.cats && d.cats.catcha) { startCatcha(d.cats); renderAll(); return; }\n        if (!d.pair && d.cats && d.cats.wait_seconds > 0) { startLives(d.cats); renderAll(); return; }\n        if (!d.pair) { state.drawn = null; state.drawState = 'empty'; renderAll(); return; }\n        if (grant) stopCatcha();\n        state.drawn = d.pair;\n        state.drawKey = key;\n        // The worker names a pair by an opaque token, not a row id (017 FR-021); `id` is what a worker\n        // without its token secret still sends. Either goes straight back in `exclude`.\n        state.drawnSeen = (state.drawnSeen || []).concat([d.pair.token || d.pair.id]).slice(-10);\n        state.drawState = 'ok';\n        renderAll();\n      })\n      .catch(function () { if (seq === _drawSeq) { state.drawState = 'error'; renderAll(); } });\n  }\n\n  /** Draw again if the bucket has moved since the copy on screen was fetched. */\n  function ensureDrawn() {\n    if (!state.schrod) return;\n    if (state.drawState === 'loading') return;\n    if (state.drawn && state.drawKey === drawKey()) return;\n    fetchDrawn();\n  }\n\n  /**\n   * Say when the copy on the card is not the real thing.\n   *\n   * The fallback is SILENT for adults by design, and that silence cost an afternoon: an empty bucket\n   * and a broken deploy look identical from the storefront, so \"the text did not update\" was\n   * indistinguishable from \"this occasion has no copy yet\". A template that looks like a product is\n   * worse than one that admits what it is.\n   *\n   * Shown to whoever is looking \u2014 there is no operator-only view of a storefront \u2014 so it is written to\n   * be true rather than internal, and it is honest about the one thing a shopper would care about:\n   * this is not the message they will receive.\n   */\n  function sourceNote() {\n    if (!state.schrod) return '';\n    var s2 = state.drawState;\n    if (s2 === 'ok') return '';\n    var text, colour, key = null;\n    if (s2 === 'loading') { text = 'Drawing a message\\u2026'; colour = MUTED; }\n    else if (s2 === 'empty') {\n      // The Hole-O-scopes page has no tone to pick and nothing to write, so its note is its own.\n      text = copy(HOLEO ? C.holeoEmptyNote : C.drawEmptyNote); key = HOLEO ? 'holeoEmptyNote' : 'drawEmptyNote';\n      colour = '#e07b1f';\n    } else if (s2 === 'error') {\n      text = copy(C.drawErrorNote); key = 'drawErrorNote';\n      colour = '#c0392b';\n    } else return '';\n    return '<div style=\"font-size:' + px(11.5) + 'px;color:' + colour + ';line-height:1.45' + ov(key ? STYLES[key] : null) + '\">' + text + '</div>';\n  }\n\n  /**\n   * The TITLE half of a drawn pair \\u2014 the name this black hole is registered under, printed on the\n   * facing certificate (Inside 1).\n   *\n   * Curated copy is a PAIR: curator generates and reviews a title beside its message, because they are\n   * read together on facing panels. Only the message half was ever wired up here, so Inside 1's name\n   * field sat empty unless the shopper typed one, and the \"we write it\" mode wrote half a card.\n   *\n   * Placeholder, like the messages: two to five words, evocative rather than jokey, which is the spec\n   * the curated titles are written to.\n   */\n  function titleShapes(opt) {\n    var v = { detail: opt };\n    return opt ? [\n      fill(copy(C.titleDetail1), v),\n      fill(copy(C.titleDetail2), v),\n      fill(copy(C.titleDetail3), v),\n      fill(copy(C.titleDetail4), v),\n    ] : [\n      copy(C.titlePlain1),\n      copy(C.titlePlain2),\n      copy(C.titlePlain3),\n      copy(C.titlePlain4),\n    ];\n  }\n\n  /** Pick from a variant list by the current draw, wrapping rather than running off the end. */\n  function pick(list) {\n    return list[((state.draw % list.length) + list.length) % list.length];\n  }\n\n  /**\n   * The drawn pair: what fills BOTH inside faces.\n   *\n   * One function returning `{title, message}` because that is the shape the curated pool serves \\u2014 a\n   * title and a message drawn independently within one occasion-and-tone bucket. Everything downstream\n   * already reads it in that shape, so swapping this body for a fetch is the whole change when the\n   * endpoint exists. Nothing else here needs to know where the words came from.\n   */\n  /**\n   * The curated backup line for this bucket, or null.\n   *\n   * Matches the live draw's bucket: surface, occasion and tone. There is no audience in the bucket\n   * any more (Amendment A); a row published before that carries an `audience` key the filter simply\n   * does not read.\n   *\n   * Falls back from the exact bucket to a looser one, because a curated line written for the wrong\n   * occasion still beats generated filler.\n   */\n  function backupLine(v) {\n    if (!BACKUP_TEXT.length) return null;\n    var ev = v.occ ? v.occ.id : null;\n    var tn = v.tone ? v.tone.id : null;\n    var mine = BACKUP_TEXT.filter(function (e) {\n      return e.surface === 'card_message';\n    });\n    if (!mine.length) return null;\n    var exact = mine.filter(function (e) { return e.event === ev && e.tone === tn; });\n    var byEvent = mine.filter(function (e) { return e.event === ev; });\n    var pool = exact.length ? exact : (byEvent.length ? byEvent : mine);\n    return pool[Math.floor(Math.random() * pool.length)];\n  }\n\n  function drawnPair(v) {\n    // The curated pair, when we have one. This is the product; everything below it is a stopgap.\n    if (state.drawn) {\n      // `id` here is the pair's REFERENCE for the order, not a number: the token text-worker minted\n      // (017 FR-021), or the raw row id from a worker that has no token secret yet. It lands in\n      // `_text_id` unchanged and order-worker forwards whichever it is; nothing else reads it.\n      return { id: state.drawn.token || state.drawn.id, title: state.drawn.title || '', message: esc(state.drawn.message) };\n    }\n    // CURATED BACKUP COPY, before any template. Published to a shop metafield by curator and matched\n    // on the same bucket the live draw uses, so what a shopper sees when text-worker is unreachable is\n    // reviewed writing rather than assembled filler. The template below survives only for the case\n    // where nothing has been curated for this bucket yet.\n    var b = backupLine(v);\n    if (b) return { id: null, title: b.title || '', message: esc(b.message) };\n\n    var who = state.name || 'you';\n    var occ = v.occ ? v.occ.name.toLowerCase() : 'the occasion';\n    var opt = selectedOptionLabel();\n    var lead = (v.tone.line || '').replace(/[\\u2014\\u2013\\u2015\\u2012]/g, ',').replace(/\\s*,\\s*/g, ', ').trim();\n    if (lead && !/[.!?]$/.test(lead)) lead += '.';\n    // A horoscope card names the sign; everything else names the occasion.\n    var tail = pick(copyShapes(who, occ, opt));\n    return { id: null, title: pick(titleShapes(opt)), message: esc((lead ? lead + ' ' : '') + tail) };\n  }\n\n  function generatedCopy(v) { return drawnPair(v).message; }\n\n  /** How many re-draws are left, or null when they are unlimited. */\n  function redrawsLeft() {\n    // Hole-O-scopes: the SERVICE counts the cats (spec 025 FR-029); once it has spoken, its count is\n    // the one shown, so the page never promises a cat the service will not give. A null block means\n    // nothing is counting (the ration is unarmed): no count, rather than one that never moves.\n    // Both customizers (operator, 2026-09-03): the ration is the service's wherever it speaks.\n    if (state.cats === null) return null;\n    if (state.cats && typeof state.cats.left === 'number') return state.cats.left;\n    var lim = +REROLL.limit || 0;\n    return lim > 0 ? Math.max(0, lim - state.redraws) : null;\n  }\n\n  /**\n   * Draw another message.\n   *\n   * The LIMIT chooses the joke. A finite supply of cats is what makes spending one funny, so a limit\n   * gets \"Sacrifice Another Cat\" and runs out; no limit gets \"Try Another Universe!\" and never does.\n   * Both strings are section settings, because which one lands is a question about the shop's voice\n   * rather than about this code.\n   */\n  function drawMessage() {\n    var left = redrawsLeft();\n    if (left !== null && left <= 0) {\n      // Zero is not the end of the joke once the service is counting: the press goes to it, and\n      // it answers with a cat-cha (fetchDrawn handles it) or, after nine lives, a countdown. A\n      // service that has not spoken (an older worker) leaves the local count as the end.\n      if (state.cats) { state.draw += 1; return true; }\n      return false;\n    }\n    state.draw += 1;\n    state.redraws += 1;\n    return true;\n  }\n\n  function rerollControl() {\n    if (REROLL.enabled === false) return '';\n    if (state.drawState === 'catcha' && state.catcha) return catchaPanel();\n    if (state.drawState === 'lives' && state.catcha) return livesPanel();\n    var left = redrawsLeft();\n    if (left !== null && left <= 0 && !state.cats) {\n      return '<div style=\"font-size:' + LABEL + 'px;color:' + MUTED + '\">'\n        + esc(copy(REROLL.exhausted)) + '</div>';\n    }\n    var label = left === null\n      // Nothing counting on the Hole-O-scopes page keeps the cat's label, just without a number.\n      ? (state.cats === null ? copy(REROLL.labelLimited) : copy(REROLL.labelUnlimited))\n      // The count is appended rather than written into the label so the shop can rephrase the button\n      // without having to remember to keep a placeholder in it.\n      : copy(REROLL.labelLimited) + ' (' + left + ' left)';\n    return '<button data-act=\"reroll\" type=\"button\" style=\"cursor:pointer;align-self:center;'\n      + 'background:#17120c;border:1px solid #e07b1f;border-radius:8px;padding:9px 14px;'\n      + 'font-size:' + px(12.5) + 'px;font-weight:500;color:#e07b1f\">' + esc(label) + '</button>';\n  }\n  // --- The cat-cha (spec 025 US8) -------------------------------------------------------------------\n  // The service rations re-draws and, at zero cats, answers with a grant that becomes valid a few\n  // seconds later ON ITS CLOCK. This side shows the wait, rotates the lines, and sends the grant back\n  // when the service's `seconds` have been counted down here \u2014 never earlier by a device clock, and\n  // if the count here runs fast the service simply says how many seconds remain and the wait resumes.\n  var _catchaTimer = null;\n\n  /** The rounding-up lines, one per '|' in the copy field. */\n  function catchaLines() {\n    return String(copy(C.holeoCatchaLines) || '').split('|')\n      .map(function (s) { return s.trim(); }).filter(Boolean);\n  }\n  function catchaLine(idx) {\n    var L = catchaLines();\n    return L.length ? L[((idx % L.length) + L.length) % L.length] : '';\n  }\n  var CATCHA_SCENES = ['table', 'box', 'count', 'feed', 'stare', 'murder', 'lives'];\n  /**\n   * A line and its scene (operator, 2026-09-03: \"several different animations to match the text\").\n   * A line may name its scene up front (\"table: Rounding up cats\u2026\"); one that does not is matched on\n   * its words; one that matches nothing takes a scene by its position so the set still varies.\n   */\n  function parseCatchaLine(raw, idx) {\n    var m = /^\\s*([a-z]+)\\s*:\\s*(.+)$/i.exec(raw || '');\n    if (m && CATCHA_SCENES.indexOf(m[1].toLowerCase()) > -1) return { scene: m[1].toLowerCase(), text: m[2].trim() };\n    var t = String(raw || '');\n    var scene = /table|knock/i.test(t) ? 'table'\n      : /box|lid|observe|garden/i.test(t) ? 'box'\n      : /lives|alive|paperwork/i.test(t) ? 'lives'\n      : /count/i.test(t) ? 'count'\n      : /feed|ate |bowl|unimpressed/i.test(t) ? 'feed'\n      : /seen things|negotiat|stare/i.test(t) ? 'stare'\n      : /murder|knife|stab|tendenc/i.test(t) ? 'murder'\n      // by position, over the scenes that carry a line (the ninth life is the countdown's alone)\n      : CATCHA_SCENES[((idx || 0) % 6 + 6) % 6];\n    return { scene: scene, text: t.trim() };\n  }\n  /** 6 \u2192 \"6s\"; 65 \u2192 \"1m 05s\". */\n  function formatWait(sec) {\n    sec = Math.max(0, Math.round(+sec || 0));\n    var m = Math.floor(sec / 60), s = sec % 60;\n    return m ? m + 'm ' + (s < 10 ? '0' : '') + s + 's' : s + 's';\n  }\n  /** One small scene per line, in the store's line style. */\n  function catSvg(scene) {\n    var head = '<path d=\"M50 26 q0 -10 8 -10 q8 0 8 10 q0 6 -8 6 q-8 0 -8 -6z\"/><path d=\"M51 19 l1 -6 4 5 M65 19 l-1 -6 -4 5\"/>';\n    if (scene === 'table') {\n      // A cat sits, looks straight at you, reaches out one paw and pushes the mug off the edge. Slowly.\n      return '<svg viewBox=\"0 0 80 56\" aria-hidden=\"true\" focusable=\"false\">'\n        + '<path d=\"M4 40 h72\" class=\"bhr-line\"/><path d=\"M14 40 v12 M66 40 v12\" class=\"bhr-line\"/>'\n        + '<g class=\"bhr-cat bhr-cat-sit\"><path d=\"M44 40 q-2 -16 12 -16 q12 0 12 16z\"/>' + head\n        + '<g class=\"bhr-cat-eyes\"><circle cx=\"55\" cy=\"22\" r=\"1.3\"/><circle cx=\"61\" cy=\"22\" r=\"1.3\"/></g>'\n        + '<path d=\"M58 25.5 q1 1.5 2 0\" fill=\"none\"/><path class=\"bhr-cat-tail\" d=\"M68 40 q8 -4 6 -12\" fill=\"none\"/></g>'\n        + '<g class=\"bhr-paw\"><path d=\"M46 33 h-10\" fill=\"none\"/><circle cx=\"36\" cy=\"33\" r=\"2\"/></g>'\n        + '<g class=\"bhr-mug\"><rect x=\"22\" y=\"30\" width=\"9\" height=\"10\" rx=\"1.5\"/><path d=\"M31 33 q4 0 4 3 q0 3 -4 3\" fill=\"none\"/></g>'\n        + '<g class=\"bhr-crash\"><path d=\"M10 50 l-3 3 M16 52 l0 4 M22 50 l3 3\" fill=\"none\"/></g></svg>';\n    }\n    if (scene === 'lives') {\n      // The ninth life: a halo that will not sit still, and nine dots that count.\n      var dots = '';\n      for (var i = 0; i < 9; i++) dots += '<circle class=\"bhr-life\" cx=\"' + (12 + i * 7) + '\" cy=\"50\" r=\"2\"/>';\n      return '<svg viewBox=\"0 0 80 56\" aria-hidden=\"true\" focusable=\"false\"><g class=\"bhr-cat\" transform=\"translate(-16 6)\">'\n        + '<path d=\"M44 40 q-2 -16 12 -16 q12 0 12 16z\"/>' + head + '<circle cx=\"55\" cy=\"22\" r=\"1.3\"/><circle cx=\"61\" cy=\"22\" r=\"1.3\"/>'\n        + '<path class=\"bhr-cat-tail\" d=\"M68 40 q8 -4 6 -12\" fill=\"none\"/></g>'\n        + '<ellipse class=\"bhr-halo\" cx=\"42\" cy=\"8\" rx=\"9\" ry=\"2.4\" fill=\"none\"/>' + dots + '</svg>';\n    }\n    if (scene === 'count') {\n      // Three cats in a row, nodding in turn as they are counted. The last one is counting back.\n      var cats = '';\n      for (var k = 0; k < 3; k++) {\n        var x = 8 + k * 24;\n        cats += '<g class=\"bhr-count-cat\" style=\"animation-delay:' + (k * 0.5) + 's\">'\n          + '<path d=\"M' + x + ' 46 q-2 -14 10 -14 q12 0 10 14z\"/>'\n          + '<path d=\"M' + (x + 3) + ' 30 q0 -9 7 -9 q7 0 7 9 q0 5 -7 5 q-7 0 -7 -5z\"/>'\n          + '<path d=\"M' + (x + 4) + ' 24 l1 -5 3 4 M' + (x + 16) + ' 24 l-1 -5 -3 4\"/>'\n          + '<circle cx=\"' + (x + 7.5) + '\" cy=\"27\" r=\"1.1\"/><circle cx=\"' + (x + 12.5) + '\" cy=\"27\" r=\"1.1\"/></g>';\n      }\n      return '<svg viewBox=\"0 0 80 56\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M4 46 h72\" class=\"bhr-line\"/>' + cats\n        + '<g class=\"bhr-count-badge\"><circle cx=\"70\" cy=\"12\" r=\"7\"/><text x=\"70\" y=\"15.5\" text-anchor=\"middle\" font-size=\"9\" font-family=\"Space Mono, monospace\">3</text></g></svg>';\n    }\n    if (scene === 'feed') {\n      // A bowl, a cat over it, and no enthusiasm whatsoever.\n      return '<svg viewBox=\"0 0 80 56\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M4 50 h72\" class=\"bhr-line\"/>'\n        + '<g class=\"bhr-cat bhr-feed-cat\" transform=\"translate(-6 8)\"><path d=\"M44 40 q-2 -16 12 -16 q12 0 12 16z\"/>' + head\n        + '<circle cx=\"55\" cy=\"22\" r=\"1.3\"/><circle cx=\"61\" cy=\"22\" r=\"1.3\"/><path d=\"M56 26 h4\" fill=\"none\"/>'\n        + '<path class=\"bhr-cat-tail\" d=\"M68 40 q8 -4 6 -12\" fill=\"none\"/></g>'\n        + '<g class=\"bhr-bowl\"><path d=\"M12 42 q10 10 20 0\" fill=\"none\"/><path class=\"bhr-food\" d=\"M15 42 q7 -6 14 0\" fill=\"none\"/></g></svg>';\n    }\n    if (scene === 'murder') {\n      // A cat with a knife. It is not doing anything with it. Yet. (Operator, 2026-09-03.)\n      return '<svg viewBox=\"0 0 80 56\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M4 50 h72\" class=\"bhr-line\"/>'\n        + '<g class=\"bhr-cat bhr-murder-cat\"><path d=\"M26 50 q-2 -18 12 -18 q14 0 12 18z\"/>'\n        + '<path d=\"M30 32 q0 -11 8 -11 q8 0 8 11 q0 6 -8 6 q-8 0 -8 -6z\"/>'\n        + '<path d=\"M31 24 l1 -6 4 5 M45 24 l-1 -6 -4 5\"/>'\n        + '<path d=\"M33 25.5 l4 1.5 M43 25.5 l-4 1.5\" fill=\"none\"/><path d=\"M34 29 h3 M39 29 h3\" fill=\"none\"/><path d=\"M37 32 h2\" fill=\"none\"/>'\n        + '<path class=\"bhr-cat-tail\" d=\"M50 48 q10 -3 8 -12\" fill=\"none\"/></g>'\n        + '<g class=\"bhr-knife-arm\"><path d=\"M46 40 l9 -7\" fill=\"none\"/><circle cx=\"55\" cy=\"33\" r=\"2\"/>'\n        + '<path d=\"M56 32 l4 -3\" fill=\"none\"/><path class=\"bhr-blade\" d=\"M60 29 l13 -9 l-3 7 l-9 5z\"/>'\n        + '<path class=\"bhr-glint\" d=\"M69 20 v-3 M67.5 21.5 l-2 -2 M70.5 21.5 l2 -2\" fill=\"none\"/></g></svg>';\n    }\n    if (scene === 'stare') {\n      // A cat that has seen things. The pupils say so.\n      // A close-up: the head fills the frame, and the shoulders run off the bottom of it.\n      return '<svg viewBox=\"0 0 80 56\" aria-hidden=\"true\" focusable=\"false\"><g class=\"bhr-cat\" transform=\"translate(-72 -18) scale(1.95)\">'\n        + '<path d=\"M44 40 q-2 -16 12 -16 q12 0 12 16z\"/>' + head\n        + '<circle cx=\"55\" cy=\"22\" r=\"2.6\" fill=\"none\"/><circle cx=\"61\" cy=\"22\" r=\"2.6\" fill=\"none\"/>'\n        + '<g class=\"bhr-pupils\"><circle cx=\"55\" cy=\"22\" r=\"0.9\"/><circle cx=\"61\" cy=\"22\" r=\"0.9\"/></g>'\n        + '<path d=\"M57 26 h2\" fill=\"none\"/></g></svg>';\n    }\n    // The box: a cat in it, and a lid that will not settle.\n    return '<svg viewBox=\"0 0 80 56\" aria-hidden=\"true\" focusable=\"false\">'\n      + '<path d=\"M12 26 h56 v26 h-56z\" class=\"bhr-box\"/><g class=\"bhr-cat\"><path d=\"M18 30 q-2 -12 8 -14 l3 -6 3 6 h8 l3 -6 3 6 q10 2 8 14 q-2 10 -18 10 q-16 0 -18 -10z\"/>'\n      + '<circle cx=\"29\" cy=\"24\" r=\"1.4\"/><circle cx=\"41\" cy=\"24\" r=\"1.4\"/><path d=\"M33 29 q2 2 4 0\" fill=\"none\"/>'\n      + '<path class=\"bhr-cat-tail\" d=\"M52 34 q10 -2 8 -10\" fill=\"none\"/></g>'\n      + '<path class=\"bhr-lid\" d=\"M12 26 l4 -10 h48 l4 10\"/></svg>';\n  }\n  function catchaPanel() {\n    var c = state.catcha;\n    var line = parseCatchaLine(catchaLine(c.lineIdx || 0), c.lineIdx || 0);\n    return '<div class=\"bhr-catcha\" role=\"status\" aria-live=\"polite\" data-scene=\"' + esc(line.scene) + '\">' + catSvg(line.scene)\n      + '<div class=\"bhr-catcha-text\"><div class=\"bhr-catcha-heading\" style=\"' + ov(STYLES.holeoCatchaHeading) + '\">' + esc(copy(C.holeoCatchaHeading)) + '</div>'\n      + '<div class=\"bhr-catcha-line\" style=\"' + ov(STYLES.holeoCatchaLines) + '\">' + esc(line.text) + '</div>'\n      + '<div class=\"bhr-catcha-count\">' + esc(formatWait(c.remaining)) + '</div></div></div>';\n  }\n  function livesPanel() {\n    var c = state.catcha;\n    return '<div class=\"bhr-catcha bhr-catcha-lives\" role=\"status\" aria-live=\"polite\" data-scene=\"lives\">' + catSvg('lives')\n      + '<div class=\"bhr-catcha-text\"><div class=\"bhr-catcha-heading\" style=\"' + ov(STYLES.holeoCatchaOutOfLives) + '\">' + esc(copy(C.holeoCatchaOutOfLives)) + '</div>'\n      + '<div class=\"bhr-catcha-line\" style=\"' + ov(STYLES.holeoCatchaCountdown) + '\">' + esc(String(copy(C.holeoCatchaCountdown)).replace('{wait}', formatWait(c.remaining))) + '</div></div></div>';\n  }\n  /** A grant a reload left behind, for this session only. */\n  function storedGrant() {\n    try {\n      var raw = sessionStorage.getItem('bhr-catcha');\n      var v = raw ? JSON.parse(raw) : null;\n      return v && v.sid === BHR_SID && v.grant ? v.grant : '';\n    } catch (e) { return ''; }\n  }\n  function startCatcha(block) {\n    stopCatcha();\n    var cc = block.catcha;\n    // A different opening line and scene each time (operator, 2026-09-03: it started the same way\n    // every time). The line index walks from a random start; the scene is offset from it.\n    var lines = catchaLines();\n    state.catcha = { grant: cc.grant, remaining: +cc.seconds || 0, total: +cc.seconds || 0, ticks: 0,\n      lineIdx: Math.floor(Math.random() * Math.max(1, lines.length)) };\n    state.drawState = 'catcha';\n    try { sessionStorage.setItem('bhr-catcha', JSON.stringify({ sid: BHR_SID, grant: cc.grant })); } catch (e) { /* private mode */ }\n    _catchaTimer = setInterval(function () {\n      var c = state.catcha;\n      if (!c) { stopCatcha(); return; }\n      c.remaining -= 1; c.ticks += 1;\n      // Two scenes per wait (operator, 2026-09-03): the line and its animation change once, halfway.\n      if (c.ticks === Math.max(1, Math.round((c.total || 0) / 2))) c.lineIdx += 1;\n      if (c.remaining <= 0) {\n        clearInterval(_catchaTimer); _catchaTimer = null;\n        state.drawState = 'loading';\n        fetchDrawn({ reroll: true, grant: c.grant });\n      }\n      renderAll();\n    }, 1000);\n  }\n  function startLives(block) {\n    stopCatcha();\n    state.catcha = { remaining: +block.wait_seconds || 0, lineIdx: 0, ticks: 0 };\n    state.drawState = 'lives';\n    _catchaTimer = setInterval(function () {\n      var c = state.catcha;\n      if (!c) { stopCatcha(); return; }\n      c.remaining -= 1;\n      if (c.remaining <= 0) { stopCatcha(); state.catcha = null; state.drawState = 'ok'; }\n      renderAll();\n    }, 1000);\n  }\n  function stopCatcha() {\n    if (_catchaTimer) clearInterval(_catchaTimer);\n    _catchaTimer = null;\n    state.catcha = null;\n    try { sessionStorage.removeItem('bhr-catcha'); } catch (e) { /* private mode */ }\n  }\n\n  // --- Certificate hot areas -----------------------------------------------------------------------\n  // Only a few spots on the certificate are writable; everything else is the printed plate. Geometry is\n  // MEASURED from the magenta placeholders in the 4x6 print file rather than typed, so the type lands\n  // exactly where the design put it and can never drift from the art.\n  //   left/base : % of the print file's width / height\n  //   size      : % of its WIDTH \u2014 i.e. a container query unit, so type tracks the plate at any display\n  //               size with no resize listener\n  //   max       : the field's box, also % of width (the ornamental box interiors, measured)\n  //   asc       : where Nebula's baseline sits below a line-height:1 box top (ascent + half-leading)\n  var CERT = {\n    // The TRIMMED card (6.000 x 4.000 in), because that is what the customer receives \u2014 the print\n    // file's 2 mm bleed is cut off by Printful and showing it here would just be cropped by the stage.\n    w: 1800, h: 1200, asc: 0.8169,\n    fields: [\n      { key: 'regId',  left: 25.528, base: 32.417, size: 1.667, max: 16.8 },\n      { key: 'regOn',  left: 75.917, base: 32.083, size: 1.889, max: 16.0 },\n      { key: 'bhName', left: 50.083, base: 60.667, size: 3.389, max: 57.5, edit: true,\n        ph: copy(C.plateNamePh), face: 'nunito-bold' },\n      { key: 'certTo', left: 49.639, base: 68.333, size: 2.222, max: 46.5, edit: true,\n        ph: copy(C.plateToPh), face: 'nunito' }\n    ]\n  };\n  // Spec 027: the plates and their geometry are GENERATED from the same marker renders the printer's\n  // plates come from (print/assets/printful/tools/derive_cert_web_plates.py -> the bhr-cert-plates\n  // snippet), one per face: the main certificate, and one per Hole-O-scope sign with the sign's card\n  // baked in. The plate follows the chosen sign the way inside 2 does. The typed CERT above is only\n  // the fallback for a store whose section predates the snippet.\n  function certGeom() {\n    var cp = CFG.certPlates;\n    if (!cp || !cp.plates || !cp.plates.main) {\n      return { w: CERT.w, h: CERT.h, plate: (CFG.assets && CFG.assets.certPlate) || '', fields: CERT.fields,\n               asc: function () { return CERT.asc; }, samples: [] };\n    }\n    // The chosen sign comes back in the option's own spelling (\"Leo\"); the plate keys are handles.\n    var sign = String(HOLEO ? horoscopeSign() : '').toLowerCase();\n    var key = sign && cp.plates['horoscope-' + sign] ? 'horoscope-' + sign : 'main';\n    var g = cp.plates[key];\n    var fields = g.fields.map(function (f) {\n      var o = {}; for (var k in f) o[k] = f[k];\n      if (f.key === 'bhName') o.ph = copy(C.plateNamePh);\n      if (f.key === 'certTo') o.ph = copy(C.plateToPh);\n      return o;\n    });\n    return { w: cp.w || 1800, h: cp.h || 1200, plate: g.plate || '', fields: fields, key: key,\n             asc: function (face) { return (cp.faces && cp.faces[face] && cp.faces[face].asc) || CERT.asc; },\n             samples: g.samples || [] };\n  }\n  // Print parity (render_card.py CERT_FIELDS): the two PERSONAL fields print in Nunito Sans \u2014 the\n  // black-hole name bold, the recipient regular \u2014 while the registry number and date stay Nebula.\n  // The preview must render AND measure with the same faces: Nebula is a wide display face, so\n  // fitting Nunito text with Nebula metrics under- or over-shrinks it, and the card lies about itself.\n  var CERT_FACES = {\n    'nunito':      { css: \"font-family:'Nunito Sans',Georgia,sans-serif;font-weight:400;\", canvas: '400 ', family: '\"Nunito Sans\", Georgia, sans-serif' },\n    'nunito-bold': { css: \"font-family:'Nunito Sans',Georgia,sans-serif;font-weight:700;\", canvas: '700 ', family: '\"Nunito Sans\", Georgia, sans-serif' },\n    // The design's registry number, date and coordinates are a serif bold; print uses DejaVu Serif\n    // Bold, the site the nearest face every browser has. An idea of the card, not a proof.\n    'serif-bold':  { css: \"font-family:Georgia,'Times New Roman',serif;font-weight:700;\", canvas: 'bold ', family: 'Georgia, \"Times New Roman\", serif' },\n    // Nebula: the plate's own display face, loaded by the section; the fallback keeps the metrics near.\n    'nebula':      { css: \"font-family:'Nebula','Space Mono',monospace;font-weight:400;\", canvas: '400 ', family: '\"Nebula\", \"Space Mono\", monospace' }\n  };\n  var MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];\n\n  function hashCode(s) { var h = 0; for (var i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0; return h; }\n  function certField(key) { var fs = certGeom().fields; for (var i = 0; i < fs.length; i++) if (fs[i].key === key) return fs[i]; return null; }\n\n  // The registration date defaults to the day they shopped, and since 2026-08-29 a shopper may type\n  // one instead (an anniversary, the day the baby arrived): whichever it is, it is stamped at render,\n  // then frozen onto the line item at add-to-cart so the printed card can never disagree with the preview.\n  function certDate(d) {\n    d = d || new Date();\n    return MONTHS[d.getMonth()] + ' ' + ('0' + d.getDate()).slice(-2) + ' ' + d.getFullYear();\n  }\n  // AN OCCASION'S OWN DATE IS THE REGISTRATION DATE, when it has one and the shopper filled it in.\n  //\n  // A wedding's `annDate`, an anniversary's date, a birth date: the day the certificate should carry\n  // is the day the occasion is about, not the day someone happened to shop. So a detail field on the\n  // occasion may declare `\"registers\": true` and that field becomes the date. It is DATA on the\n  // occasion (Content -> Metaobjects -> Occasion, `detail_fields`), not a list of occasion names in\n  // here \u2014 adding it to another event is an edit, not a deploy. Operator, 2026-08-29.\n  //\n  // Precedence: the occasion's own flagged field, then the general Registration date field, then the\n  // day they shopped. The general field is not rendered at all when the occasion has a flagged one,\n  // because two date inputs on one page is a question about which of them wins.\n  function registrationField(occId) {\n    var ex = EXTRAS[occId || state.occ];\n    if (!ex || !ex.fields) return null;\n    // THE OCCASION'S DATE FIELD IS THE REGISTRATION DATE. No separate flag: this looked for\n    // `registers: true` until 2026-08-30 and NOTHING on either store carried it, so the feature had\n    // never once fired since it shipped. A flag that must be ticked in a second place is a feature\n    // nobody gets. A date field on the occasion IS the date the occasion is about.\n    //\n    // Exactly one, deliberately. Two date fields on one occasion is ambiguous, and picking the first\n    // would make the certificate depend on the order they happen to sit in the metaobject.\n    var dates = ex.fields.filter(function (f) { return f.type === 'date'; });\n    return dates.length === 1 ? dates[0] : null;\n  }\n  function registrationDate() {\n    var f = registrationField(state.occ);\n    return (f && state.extra[f.key]) || state.regDate || '';\n  }\n\n  // A typed date arrives as the input's ISO value (YYYY-MM-DD). It is read as a CALENDAR day, never\n  // through `new Date(iso)`, which parses as UTC midnight and shows the previous day west of Greenwich.\n  // Anything that is not a full date falls back to today, so a half-typed field cannot print garbage.\n  function certDateFor(iso, now) {\n    var m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(iso || '');\n    if (!m) return certDate(now);\n    var d = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n    if (d.getFullYear() !== Number(m[1]) || d.getMonth() !== Number(m[2]) - 1 || d.getDate() !== Number(m[3])) return certDate(now);\n    return certDate(d);\n  }\n\n  function certValues(v, g) {\n    var art = v.art || {};\n    var yr = new Date().getFullYear();\n    // Where the black hole is (spec 026). The registration draws its real coordinates when the order\n    // exists \u2014 a point in a real galaxy, in the sign's constellation for a horoscope \u2014 so the preview\n    // shows a plausible sample from the same catalogue, one of a few, fixed by the image's code so\n    // it does not flicker between renders.\n    // The image carries its own (drawn at curation, spec 026) \u2014 the same values the registration and\n    // the certificate will use. The sample is only for an image the backfill has not reached.\n    var own = art.coordinates && art.coordinates.ra ? art.coordinates : null;\n    var samples = (g || certGeom()).samples || [];\n    var pick = own || (samples.length ? samples[Math.abs(hashCode(String(art.code || ''))) % samples.length] : null);\n    return {\n      coordRa: pick ? pick.ra : '', coordDec: pick ? pick.dec : '',\n      // The image's OWN code tail: BHR-79A8F5 -> BHR-2026-79A8F5. The code is the image's catalog\n      // identity \u2014 unique, stable, and the same mark the shopper saw on the gallery badge \u2014 where the\n      // previous scheme (digits filtered out of the UUID) was minted here in the browser, matched\n      // nothing else in the system, and could collide.\n      regId: art.registryId || ('BHR-' + yr + '-'\n        + (String(art.code || '').replace(/^BHR-/, '').toUpperCase() || '000000')),\n      regOn: certDateFor(registrationDate()),\n      // The drawn TITLE lands here: it is the name this black hole is registered under, and it is the\n      // half of the pair that belongs on Inside 1. A name the shopper typed always wins \u2014 they are\n      // naming their own black hole and we are only filling the blank until they do.\n      //\n      // The LAST fallback is the BHR designation (art.code, \"BHR-113B2C\") \u2014 the catalog convention,\n      // the same mark on the gallery badge \u2014 not the friendly \"Singularity 113B2C\" display label.\n      // An unnamed object carries its designation; that is how catalogs work, and it is the joke.\n      bhName: state.bhName || (state.schrod ? drawnPair(v).title : '') || art.code || art.name || '',\n      certTo: state.name || ''\n    };\n  }\n\n  var _measureCtx;\n  function textW(txt, sizePx, face) {\n    _measureCtx = _measureCtx || document.createElement('canvas').getContext('2d');\n    var f = CERT_FACES[face];\n    _measureCtx.font = f ? (f.canvas + sizePx + 'px ' + f.family) : (sizePx + 'px Nebula, \"Space Mono\", monospace');\n    return _measureCtx.measureText(txt).width;\n  }\n  // Shrink to fit, never grow. This is load-bearing rather than a safety net: BHR-2026-000042 is 15\n  // characters where the placeholder was 11, and overflows its ornamental box by ~16% at design size.\n  function certSize(txt, f) {\n    if (!txt) return f.size;\n    var w = certGeom().w;\n    var natural = textW(txt, f.size / 100 * w, f.face), room = f.max / 100 * w;\n    return natural > room ? f.size * (room / natural) : f.size;\n  }\n\n  function certPlateHTML(v) {\n    var g = certGeom();\n    var plate = g.plate;\n    var vals = certValues(v, g);\n    var spans = g.fields.map(function (f) {\n      var txt = vals[f.key] || '';\n      var size = certSize(txt || (f.edit ? f.ph : ''), f);\n      // Place by BASELINE, not box top. The magenta we measured is all-caps with no descenders, so its\n      // bbox bottom IS the baseline; converting here keeps the spec in the designer's terms.\n      var top = f.base - g.asc(f.face) * size * (g.w / g.h);\n      return '<div class=\"bhr-cert-f' + (f.edit ? ' bhr-cert-edit' : '') + '\"'\n        + (f.edit ? ' contenteditable=\"true\" spellcheck=\"false\" data-act=\"certfield\" data-key=\"' + f.key\n                  + '\" data-ph=\"' + esc(f.ph) + '\" title=\"' + esc(copy(C.plateEditHint)) + '\"' : '')\n        + ' data-cq=\"' + size.toFixed(3) + '\"'\n        + ' style=\"left:' + f.left.toFixed(3) + '%;top:' + top.toFixed(3) + '%;font-size:'\n        + size.toFixed(3) + 'cqw;max-width:' + f.max + '%;'\n        + (CERT_FACES[f.face] ? CERT_FACES[f.face].css : '') + '\">' + esc(txt) + '</div>';\n    }).join('');\n    return '<div class=\"bhr-cert-plate\">'\n      + (plate ? '<img src=\"' + plate + '\" alt=\"Certificate of registration\">' : '')\n      + spans + '</div>';\n  }\n\n  // cqw sizes the certificate against the plate's own width, which is exactly the right relationship \u2014\n  // but it is the single modern feature the type depends on. If anything upstream establishes a different\n  // query container, or the browser lacks support, every field silently collapses to nothing while the\n  // plate behind it still renders. Restating the size in px from the measured width removes that risk;\n  // the cqw value stays as the pre-JS default.\n  function fitCertText(root) {\n    var plates = (root || document).querySelectorAll('.bhr-cert-plate');\n    for (var i = 0; i < plates.length; i++) {\n      var w = plates[i].clientWidth;\n      if (!w) continue;\n      var fs = plates[i].querySelectorAll('.bhr-cert-f');\n      for (var j = 0; j < fs.length; j++) {\n        var cq = parseFloat(fs[j].getAttribute('data-cq'));\n        if (cq) fs[j].style.fontSize = (cq / 100 * w).toFixed(2) + 'px';\n      }\n    }\n  }\n  window.addEventListener('resize', function () { fitCertText(); fitMessageBox(); fitCardTitle(); });\n\n  // Inside 2 \u2014 the message panel. This is the ONLY panel that differs between the two write modes:\n  // the shopper types it, or the tone engine drafts it. Everything else on the card is identical, which\n  // is why the mode toggle lives above the panels rather than inside one.\n  // Inside 2 \u2014 the printed plate, with the message set into the magenta area the template marks out.\n  // Measured from the 12 horoscope templates, which all carry an IDENTICAL box, so one geometry serves\n  // every sign and the plate is simply swapped. % of the plate, so it holds at panel and viewer size.\n  var I2 = { left: 21.556, top: 29.417, w: 57.444, h: 57.250, size: 3.0 };\n\n  // Which plate to show: a chosen option that carries one wins (horoscope -> the sign), otherwise the\n  // per-occasion plate. Generic on purpose \u2014 the other events drop in as config, not code.\n  function i2Plate() {\n    var meta = CFG.optionMeta || {};\n    for (var key in meta) {\n      var sel = state.extra[key];\n      if (sel && meta[key][sel] && meta[key][sel].plate) return meta[key][sel].plate;\n    }\n    return (CFG.inside2 || {})[state.occ] || '';\n  }\n\n  // Some artwork carries a title strip above the rule (Just Because today). Optional: an empty title\n  // leaves the strip blank, which is exactly what the plate already looks like.\n  function i2TitleBox() { return (CFG.inside2Title || {})[state.occ] || null; }\n\n  function insideTwoHTML(v) {\n    var plate = i2Plate();\n    var body = state.schrod ? generatedCopy(v) : (state.msg || '');\n    var box = 'left:' + I2.left + '%;top:' + I2.top + '%;width:' + I2.w + '%;height:' + I2.h + '%';\n    var tb = i2TitleBox(), title = '';\n    if (tb) {\n      var tt = (state.cardTitle || '').trim();\n      title = '<div class=\"bhr-i2-title' + (tt ? '' : ' bhr-i2-empty') + '\" style=\"left:' + tb.left\n        + '%;top:' + tb.top + '%;width:' + tb.w + '%;height:' + tb.h + '%\">' + esc(tt) + '</div>';\n    }\n    if (!plate) {\n      // No plate for this occasion yet \u2014 show the message on blank stock rather than an empty frame.\n      return '<div class=\"bhr-i2-plate\"><div class=\"bhr-i2-blank\"></div>' + title\n        + '<div class=\"bhr-i2-msg' + (body ? '' : ' bhr-i2-empty') + '\" style=\"' + box + '\">' + body + '</div></div>';\n    }\n    return '<div class=\"bhr-i2-plate\"><img src=\"' + plate + '\" alt=\"\">' + title\n      + '<div class=\"bhr-i2-msg' + (body ? '' : ' bhr-i2-empty') + '\" style=\"' + box + '\">' + body + '</div></div>';\n  }\n\n  // The message wraps, so it cannot be placed on a baseline like the certificate's single lines. Start\n  // proportional to the plate and shrink until the wrapped text fits the box the template drew.\n  // One line in the card's display face: fill the strip's height, shrink only if the words are too wide,\n  // so a short title reads as deliberate rather than shrunken.\n  function fitCardTitle(root) {\n    var els = (root || document).querySelectorAll('.bhr-i2-title');\n    for (var i = 0; i < els.length; i++) {\n      var el = els[i];\n      if (!el.parentNode.clientWidth) continue;\n      var boxW = el.clientWidth, size = el.clientHeight * 0.86, guard = 0;\n      el.style.fontSize = size.toFixed(2) + 'px';\n      while (el.scrollWidth > boxW + 1 && size > 4 && guard++ < 60) {\n        size *= 0.95; el.style.fontSize = size.toFixed(2) + 'px';\n      }\n    }\n  }\n\n  function fitMessageBox(root) {\n    var boxes = (root || document).querySelectorAll('.bhr-i2-msg');\n    for (var i = 0; i < boxes.length; i++) {\n      var el = boxes[i], w = el.parentNode.clientWidth;\n      if (!w) continue;\n      var size = I2.size / 100 * w, guard = 0;\n      el.style.fontSize = size.toFixed(2) + 'px';\n      while (el.scrollHeight > el.clientHeight + 1 && size > 5 && guard++ < 40) {\n        size *= 0.94;\n        el.style.fontSize = size.toFixed(2) + 'px';\n      }\n    }\n  }\n\n  // Three panels across, in the order the card is experienced. The BACK is deliberately not shown: it\n  // is fixed branding the shopper cannot change, and a fourth panel would shrink the three that matter.\n  // Each face is the finished 6x4 trim (3/2) so the certificate's hot areas stay in register.\n  // 2x2 rather than one row of panels. A 6x4 card is landscape, so three across on a ~900px stage gave\n  // 292px panels and put the certificate's registry line at 4.2px \u2014 visible, but impossible to type on.\n  // Two columns doubles every panel, and the per-occasion fields fill the cell the fourth face would use.\n  function cardStageHTML(v, detail) {\n    var faces = panelFaces(v).map(function (p, i) {\n      // The zoom button sits in the FIGURE, not the face: renderCardStage replaces face innerHTML, which\n      // would otherwise delete the control on every keystroke.\n      return '<figure class=\"bhr-panel\">'\n        + '<div class=\"bhr-panel-face\" data-act=\"openPanel\" data-id=\"' + i + '\" title=\"Click to enlarge\">'\n        + p[1] + '</div>'\n        + '<button class=\"bhr-panel-zoom\" data-act=\"openPanel\" data-id=\"' + i + '\" aria-label=\"Enlarge\">&#11007;</button>'\n        + '<figcaption>' + p[0] + '</figcaption></figure>';\n    });\n    // Customization on the left spanning the full height, the two inside panels stacked on the right.\n    // Collapses to one column in the same reading order \u2014 customization, then Inside 1, then Inside 2.\n    return '<div class=\"bhr-card-grid\">'\n      + '<div class=\"bhr-card-config\">'\n      + (detail || '<div class=\"bhr-panel-none' + ov(STYLES.detailsNone) + '\">'\n          + esc(copy(C.detailsNone)) + '</div>')\n      + '</div><div class=\"bhr-card-faces\">' + faces.join('') + '</div></div>';\n  }\n\n  // The stage now contains live form fields, so a naive innerHTML swap would wipe what is being typed.\n  // Only the three FACES are re-rendered; the detail cell is left alone.\n  function renderCardStage() {\n    var el = document.getElementById('bhr-card-stage');\n    if (!el) return;\n    var grid = el.querySelector('.bhr-card-grid');\n    // Rebuilding here would call cardStageHTML WITHOUT the detail HTML, silently replacing the recipient\n    // and occasion fields with the empty-state message. The next renderLeft() builds the grid properly.\n    if (!grid) return;\n    var v = vals(), faces = grid.querySelectorAll('.bhr-panel-face'), spec = panelFaces(v);\n    for (var i = 0; i < faces.length && i < spec.length; i++) {\n      faces[i].innerHTML = spec[i][1];\n      var cap = faces[i].parentNode.querySelector('figcaption');\n      if (cap) cap.textContent = spec[i][0];\n    }\n    fitCertText(grid); fitMessageBox(grid); fitCardTitle(grid);\n  }\n\n  function renderLeft() {\n    var v = vals(), s = state;\n    // Keep the occasion step visible with its normal number even when pre-set from a collection \u2014\n    // it just shows as already-selected (with a \"tap to change\" note), never removed.\n    var n = STEP_N;\n    // 01 product\n    var pkgGrid = v.m ? '1fr' : '1fr 1fr';\n    var pkgs = PKGS.map(function (p) {\n      var on = s.pkg === p.id;\n      var pr = p.sizes ? (p.sizes[on ? v.size : (p.defaultSize || 0)].price) : p.price;\n      var priceLabel = (p.sizes && !on) ? ('from ' + money(pr)) : money(pr);\n      return '<button data-act=\"pkg\" data-id=\"' + p.id + '\" style=\"text-align:left;cursor:pointer;background:#101013;border:1px solid ' + (on ? '#e07b1f' : '#2b2b32') + ';border-radius:12px;padding:16px;color:inherit;display:flex;flex-direction:column;gap:8px;transition:all .18s ease;' + (on ? 'background:#17120c' : '') + '\">'\n        + '<span style=\"display:block;border-radius:9px;overflow:hidden;background:#0b0b0d\"><img src=\"' + p.img + '\" alt=\"\" style=\"display:block;width:100%;aspect-ratio:16/9;object-fit:cover;' + (p.imgStyle || '') + '\"></span>'\n        + '<span style=\"display:flex;align-items:center;gap:9px\"><span style=\"width:15px;height:15px;border-radius:50%;border:1px solid ' + (on ? '#e07b1f' : '#4a4a54') + ';display:inline-flex;align-items:center;justify-content:center\"><span style=\"width:7px;height:7px;border-radius:50%;' + (on ? 'background:#e07b1f' : '') + '\"></span></span>'\n        + '<span style=\"font-size:' + px(15) + 'px;font-weight:500\">' + esc(p.name) + '</span><span style=\"margin-left:auto;' + priceStyle(null, 500) + '\">' + priceLabel + '</span></span>'\n        + '<span style=\"font-size:' + px(12.5) + 'px;color:' + MUTED + ';line-height:1.5\">' + esc(p.desc) + '</span>'\n        + chipRow(p) + '</button>';\n    }).join('');\n    // card-size selector (only when the sized package is chosen)\n    var sizeRow = '';\n    if (v.pkg.sizes) {\n      sizeRow = '<div style=\"display:flex;align-items:center;gap:8px;margin-top:12px;flex-wrap:wrap\"><span style=\"font-size:' + px(12) + 'px;color:' + MUTED + '\">Card size</span>'\n        + v.pkg.sizes.map(function (sz, i) { var son = i === v.size; return '<button data-act=\"size\" data-id=\"' + i + '\" style=\"cursor:pointer;font-size:' + px(12.5) + 'px;padding:7px 13px;border-radius:999px;background:' + (son ? '#e07b1f' : '#1b1b20') + ';border:1px solid ' + (son ? '#e07b1f' : '#303037') + ';color:' + (son ? '#0b0b0d' : INK) + ';font-weight:' + (son ? '500' : '400') + '\">' + sz.label + ' \u00B7 ' + money(sz.price) + '</button>'; }).join('')\n        + '<span style=\"font-size:' + px(11) + 'px;color:' + MUTED + ';margin-left:auto\">Free shipping</span></div>';\n    }\n    var s01 = step(n.p, [copy(C.packageTitle), 'packageTitle'], [copy(C.packageNote), 'packageNote'],\n      '<div style=\"display:grid;gap:12px;grid-template-columns:' + pkgGrid + '\">' + pkgs + '</div>' + sizeRow);\n\n    // 02/03 occasion + tone (one section)\n    // minmax(0,1fr) (not 1fr) so wide occasion labels can't expand the columns past the grid's width and\n    // overflow into the pitch panel \u2014 the label wraps inside the fixed cell instead.\n    var occGridStyle = v.m ? 'width:100%;grid-template-columns:repeat(3,minmax(0,1fr))' : 'width:404px;flex:0 0 auto;grid-template-columns:repeat(4,minmax(0,1fr))';\n    var occBody = v.m ? 'flex-direction:column;gap:14px' : 'flex-direction:row;gap:22px';\n    var tones = tonesFor(v.occ).map(function (t) { var on = s.tone === t.id; return '<button data-act=\"tone\" data-id=\"' + t.id + '\" style=\"cursor:pointer;font-size:' + LABEL + 'px;padding:9px 15px;border-radius:999px;background:' + (on ? '#e07b1f' : '#1b1b20') + ';border:1px solid ' + (on ? '#e07b1f' : '#303037') + ';color:' + (on ? '#0b0b0d' : INK) + ';font-weight:' + (on ? '500' : '400') + ';transition:all .16s ease' + ov(styleOf(t.styles, 'name')) + '\">' + esc(t.name) + '</button>'; }).join('');\n    // id=\"bhr-step-02\": this section wears the 02 number but never had the step id, so the DOM\n    // sequence 01\u219203\u219204 skipped it \u2014 the product advance sailed PAST the occasion picker to the\n    // gallery, and the occasion advance targeted a ghost. The advance chain walks these ids.\n    var occSection = '<section id=\"bhr-step-' + n.a + '\" style=\"background:#141417;border:1px solid #232329;border-radius:14px;overflow:hidden\">'\n      + '<div style=\"display:flex;align-items:baseline;gap:12px;padding:18px 20px 0 20px\"><span style=\"' + priceStyle(Math.round((C.priceSize || 19) * 0.8)) + ';letter-spacing:0.18em\">' + n.a + '</span><span style=\"font-size:' + HEADING + 'px;font-weight:700' + ov(STYLES.occasionTitle) + '\">' + esc(copy(C.occasionTitle)) + '</span><span style=\"font-size:' + px(12) + 'px;color:' + MUTED + ';margin-left:auto' + ov(locked ? STYLES.occasionNoteLocked : STYLES.occasionNoteOpen) + '\">' + esc(locked ? copy(C.occasionNoteLocked)\n        : (v.occ ? v.occ.name : copy(C.occasionNoteOpen))) + '</span></div>'\n      + '<div style=\"padding:16px 20px 20px 20px;display:flex;align-items:stretch;' + occBody + '\"><div style=\"display:grid;gap:14px 6px;' + occGridStyle + '\">' + occGrid(v) + '</div>' + pitchPanel(v) + '</div></section>';\n    // 04 personalize \u2014 a split step: on the left, the tone chips + the event's required detail fields\n    // (age/sign\u2026) + the \"who is this for\" recipient fields; on the right, a live mockup of the certificate /\n    // greeting card in the chosen tone, filled in with those entries. One place to make it theirs.\n    if (HOLEO) {\n      // The sign step first, the explainer beside it, the category under both. The sign picker is the\n      // occasion's own detail field (the twelve options come from the occasion; the dressing from the\n      // store's signs), rendered here instead of in the personalize step.\n      var signField = ((v.ex && v.ex.fields) || []).filter(function (f) { return f.options && (CFG.optionMeta || {})[f.key]; })[0];\n      var signName = signField ? state.extra[signField.key] : '';\n      occSection = '<section id=\"bhr-step-' + n.a + '\" style=\"background:#141417;border:1px solid #232329;border-radius:14px;overflow:hidden\">'\n        + '<div style=\"display:flex;align-items:baseline;gap:12px;padding:18px 20px 0 20px\"><span style=\"' + priceStyle(Math.round((C.priceSize || 19) * 0.8)) + ';letter-spacing:0.18em\">' + n.a + '</span><span style=\"font-size:' + HEADING + 'px;font-weight:700' + ov(STYLES.holeoSignTitle) + '\">' + esc(copy(C.holeoSignTitle)) + '</span><span style=\"font-size:' + px(12) + 'px;color:' + MUTED + ';margin-left:auto' + ov(STYLES.holeoSignNote) + '\">' + esc(copy(C.holeoSignNote)) + '</span></div>'\n        + '<div style=\"padding:16px 20px 20px 20px;display:flex;align-items:stretch;' + occBody + '\"><div style=\"' + (v.m ? 'width:100%' : 'width:404px;flex:0 0 auto') + '\">' + (signField ? extraField(signField) : '') + '</div>' + signExplainer(findSign(signName)) + '</div>'\n        + '<div style=\"padding:0 20px 20px 20px\"><div style=\"font-size:' + LABEL + 'px;color:' + MUTED + ';margin-bottom:9px' + ov(STYLES.holeoCategoryTitle) + '\">' + esc(copy(C.holeoCategoryTitle)) + ' <span style=\"color:' + MUTED + '' + ov(STYLES.holeoCategoryNote) + '\">' + esc(copy(C.holeoCategoryNote)) + '</span></div>' + categoryPicker() + '</div>'\n        + '</section>';\n    }\n    var evGroup = '';\n    if (!HOLEO && v.ex && v.ex.fields && v.ex.fields.length) {\n      var evMissing = v.ex.fields.filter(function (f) { return f.required && !state.extra[f.key]; }).length;\n      var evGrid = (v.ex.fields.length > 1 && !v.m) ? '1fr 1fr' : '1fr';\n      evGroup = '<div id=\"bhr-detail\"><div style=\"font-size:' + px(12) + 'px;color:' + (evMissing ? '#e07b1f' : MUTED) + ';margin-bottom:7px;font-weight:' + (evMissing ? '600' : '400') + ov(STYLES.detailsLabel) + '\">' + esc(v.ex.label || copy(C.detailsLabel))\n        + (evMissing ? ' \\u2014 <span style=\"' + ov(STYLES.detailsRequired) + '\">' + esc(copy(C.detailsRequired)) + '</span>' : '') + '</div>'\n        + '<div style=\"display:grid;gap:12px;grid-template-columns:' + evGrid + '\">' + v.ex.fields.map(extraField).join('') + '</div></div>';\n    }\n    var pfg = v.m ? '1fr' : '1fr 1fr';\n    // Order: how the inside gets written -> who it's for -> event details -> (only when we're writing it)\n    // who it's from, the relationship and the tone. Fields we only need in order to WRITE the message stay\n    // hidden when the shopper is writing it themselves.\n    var schrodLabel = v.pkg.id === 'basic' ? 'Schr\\u00f6dinger\\u2019s Card' : 'Schr\\u00f6dinger\\u2019s Box';\n    var active = s.schrod ? 'schrod' : 'self';\n    function writerBtn(kind, label, sub, labelKey, subKey) {\n      var on = kind === active;\n      return '<button data-act=\"writer\" data-id=\"' + kind + '\" style=\"cursor:pointer;text-align:left;flex:1 1 0;min-width:0;background:' + (on ? '#17120c' : '#101013') + ';border:1px solid ' + (on ? '#e07b1f' : '#2b2b32') + ';border-radius:10px;padding:11px 13px;color:inherit;display:flex;flex-direction:column;gap:2px\"><span style=\"font-size:' + px(13) + 'px;font-weight:500;color:' + (on ? '#e07b1f' : INK) + ov(STYLES[labelKey]) + '\">' + label + '</span><span style=\"font-size:' + px(11) + 'px;color:' + MUTED + ov(STYLES[subKey]) + '\">' + sub + '</span></button>';\n    }\n    // A blurb that changes with the choice, so it always explains what just got picked.\n    var writerBlurb = s.schrod\n      ? (copy(C.schrodBlurb))\n      : (copy(C.selfBlurb));\n    // A Registry-written-only occasion (horoscope) offers no choice: the reading IS the product, so\n    // the group shows the one mode there is rather than a disabled button that reads as broken.\n    var writerGroup = writerLocked()\n      ? '<div><div style=\"font-size:' + LABEL + 'px;color:' + MUTED + ';margin-bottom:7px' + ov(STYLES.writerHeading) + '\">' + esc(copy(C.writerHeading)) + '</div>'\n        + '<div style=\"display:flex;gap:8px;flex-wrap:wrap\">'\n        + writerBtn('schrod', schrodLabel, esc(copy(C.writerLockedNote)), 'writerSchrodLabel', 'writerLockedNote') + '</div>'\n        + '<div style=\"margin-top:9px;font-size:' + px(11.5) + 'px;color:' + MUTED + ';line-height:1.55' + ov(STYLES.schrodOnlyBlurb) + '\">'\n        + (copy(C.schrodOnlyBlurb)) + '</div></div>'\n      : '<div><div style=\"font-size:' + LABEL + 'px;color:' + MUTED + ';margin-bottom:7px' + ov(STYLES.writerHeading) + '\">' + esc(copy(C.writerHeading)) + '</div>'\n      + '<div style=\"display:flex;gap:8px;flex-wrap:wrap\">'\n      // The DEFAULT sits first, whichever it currently is \u2014 a selected button in second place reads as\n      // the fallback, and the two have swapped while the copy pool fills up. Keep this order and\n      // `state.schrod` moving together; they are one decision written twice.\n      + writerBtn('self', esc(copy(C.writerSelfLabel)),\n                  esc(copy(C.writerSelfNote)), 'writerSelfLabel', 'writerSelfNote')\n      + writerBtn('schrod', schrodLabel, esc(copy(C.writerSchrodNote)), 'writerSchrodLabel', 'writerSchrodNote') + '</div>'\n      + '<div style=\"margin-top:9px;font-size:' + px(11.5) + 'px;color:' + MUTED + ';line-height:1.55' + ov(s.schrod ? STYLES.schrodBlurb : STYLES.selfBlurb) + '\">' + writerBlurb + '</div></div>';\n\n    // The message is edited here and previewed on the card, rather than typed onto the card itself: the\n    // panel is a third of print size, and the box the template marks out is not a comfortable text field.\n    var titleGroup = (CFG.inside2Title || {})[s.occ]\n      ? '<div>' + field(lbl(copy(C.titleLabel), copy(C.titleHint), 'titleLabel', 'titleHint'), 'cardTitle',\n                        s.cardTitle, copy(C.titlePh), false, TITLE_MAX)\n        + '<div style=\"margin-top:7px;font-size:' + LABEL + 'px;color:' + MUTED + ov(STYLES.titleNote) + '\">'\n        + esc(fill(copy(C.titleNote),\n                   { max: TITLE_MAX })) + '</div></div>'\n      : '';\n    var msgOver = msgLen(s.msg) > MSG_MAX;\n    var messageGroup = s.schrod ? '' :\n      '<div><div style=\"font-size:' + LABEL + 'px;color:' + MUTED + ';margin-bottom:7px' + ov(STYLES.messageHeading) + '\">' + esc(copy(C.messageHeading)) + '</div>'\n      + '<div style=\"border:1px solid ' + (msgOver ? '#c0392b' : '#2b2b32') + ';border-radius:8px;overflow:hidden;background:#0b0b0d\">'\n      + '<div style=\"display:flex;gap:5px;align-items:center;padding:6px 8px;border-bottom:1px solid #1e1e24\">'\n      + '<button data-act=\"fmt\" data-cmd=\"bold\" title=\"Bold\" style=\"width:24px;height:22px;border:1px solid #2b2b32;background:#141417;border-radius:5px;cursor:pointer;font-weight:700;font-size:' + px(11) + 'px;color:' + INK + '\">B</button>'\n      + '<button data-act=\"fmt\" data-cmd=\"italic\" title=\"Italic\" style=\"width:24px;height:22px;border:1px solid #2b2b32;background:#141417;border-radius:5px;cursor:pointer;font-style:italic;font-size:' + px(11) + 'px;color:' + INK + '\">i</button>'\n      + '<span id=\"bhr-msg-count\" style=\"margin-left:auto;font-size:' + px(10) + 'px;color:' + (msgOver ? '#c0392b' : MUTED) + '\">' + msgLen(s.msg) + '/' + MSG_MAX + '</span></div>'\n      + '<div data-act=\"cardmsg\" contenteditable=\"true\" data-ph=\"' + esc(copy(C.messagePh)) + '\" class=\"bhr-cardmsg\" style=\"min-height:104px;max-height:190px;overflow:auto;padding:11px 12px;color:' + INK + ';font-size:' + px(13.5) + 'px;line-height:1.55;outline:none\">' + (s.msg || '') + '</div>'\n      + '</div><div style=\"margin-top:7px;font-size:' + LABEL + 'px;color:' + MUTED + '' + ov(STYLES.messageNote) + '\">'\n      + esc(copy(C.messageNote)) + '</div></div>';\n\n    // The black-hole name gets a REAL field, not only the click-to-edit spot on the plate \u2014 the first\n    // real order shipped \"Singularity 79A8F5\" because nobody discovered the plate was editable. The\n    // input shows the EFFECTIVE name (typed, else the drawn title, else the registry default) and only\n    // pins state.bhName when the shopper actually changes it, so an untouched field keeps following\n    // the art and the drawn title (a horoscope's sign-title still lands unless overridden).\n    var effName = certValues(v).bhName;\n    // ONE HEADING, AND IT IS A FIELD LABEL. There used to be a block heading above this grid as well\n    // (\"Who is this for\") on top of the name field's own label (\"Recipient's name\"), which are the\n    // same thing said twice; the block heading was optional and emptying it was the fix, so prod kept\n    // both for as long as nobody emptied it there. Reported repeatedly. The second string is gone\n    // rather than blanked, so the pair cannot come back: every input in this grid carries its own\n    // label, the name's label is the heading, and the example name lives in the placeholder where an\n    // example belongs.\n    var nameGroup = '<div>'\n      + '<div style=\"display:grid;gap:12px;grid-template-columns:' + pfg + '\">'\n      + field(lbl(copy(C.recipientNameLabel), null, 'recipientNameLabel'), 'name', s.name,\n              copy(C.recipientNamePh), true, null, true)\n      + (registrationField(s.occ) ? '' :\n         dateField(lbl(copy(C.recipientDateLabel), copy(C.recipientDateHint), 'recipientDateLabel', 'recipientDateHint'), 'regDate', s.regDate))\n      + '<label style=\"display:flex;flex-direction:column;gap:6px;grid-column:1/-1\"><span style=\"font-size:' + LABEL + 'px;color:' + MUTED + '\">'\n      + lbl(copy(C.recipientBhnameLabel), copy(C.recipientBhnameHint), 'recipientBhnameLabel', 'recipientBhnameHint') + '</span>'\n      + '<input value=\"' + esc(effName) + '\" data-act=\"bhname\" data-def=\"' + esc(effName) + '\" maxlength=\"40\"'\n      + ' style=\"background:#0f0f12;border:1px solid #2b2b32;border-radius:8px;padding:11px 12px;color:' + INK + ';font-size:' + px(14) + 'px;outline:none\"></label>'\n      + '</div>'\n      + '<div style=\"margin-top:7px;font-size:' + LABEL + 'px;color:' + MUTED + '' + ov(STYLES.recipientBhnameNote) + '\">'\n      + esc(copy(C.recipientBhnameNote)) + '</div></div>';\n\n    // The \"Who is going to read this\" group that stood here (adult or child, a boolean, only on the\n    // path where the Registry writes the words) is gone with the audience (Amendment A).\n\n    // Only needed when WE write the message \u2014 hidden when the shopper writes their own.\n    var schrodGroup = '';\n    if (s.schrod) {\n      schrodGroup = '<div style=\"border-left:2px solid #e07b1f;padding-left:13px;display:flex;flex-direction:column;gap:13px\">'\n        + '<div><div style=\"display:grid;gap:12px;grid-template-columns:' + pfg + '\">'\n        + field(lbl(copy(C.fromLabel), copy(C.fromHint), 'fromLabel', 'fromHint'),\n                'from', s.from, copy(C.fromPh), false)\n        + field(lbl(copy(C.relLabel), copy(C.relHint), 'relLabel', 'relHint'),\n                'rel', s.rel, copy(C.relPh), false)\n        + '</div><div style=\"margin-top:7px;font-size:' + LABEL + 'px;color:' + MUTED + '' + ov(STYLES.voiceNote) + '\">'\n        + esc(copy(C.voiceNote)) + '</div></div>'\n        + sourceNote()\n        // No tone step when the occasion's list is explicitly empty (spec 025): the heading, the\n        // chips and the tone's own line all go, because a heading over nothing is worse than nothing.\n        + (tones\n            ? '<div><div style=\"font-size:' + LABEL + 'px;color:' + MUTED + ';margin-bottom:7px' + ov(STYLES.toneHeading) + '\">' + esc(copy(C.toneHeading)) + '</div>'\n              + '<div style=\"display:flex;flex-wrap:wrap;gap:8px\">' + tones + '</div>'\n              + '<div style=\"margin-top:8px;font-size:' + px(13) + 'px;color:' + MUTED + ';line-height:1.55' + ov(styleOf(v.tone.styles, v.tone.explanation ? 'explanation' : 'line')) + '\">' + (v.tone.explanation || esc(v.tone.line || '')) + '</div></div>'\n            : '')\n        // Under the tone, because \"I don't like this one\" is a reaction to the words, and the tone is\n        // the other lever on the same thing. Flipping to Inside 2 to read the result is one click away.\n        + (rerollControl()\n            // Centred on both customizers (operator, 2026-09-03).\n            ? '<div style=\"display:flex;flex-direction:column;gap:7px;align-items:center;text-align:center\">'\n              + '<div style=\"font-size:' + px(12) + 'px;color:' + MUTED + '' + ov(STYLES.rerollHeading) + '\">' + esc(copy(C.rerollHeading)) + '</div>'\n              + rerollControl()\n              + '<div style=\"font-size:' + px(11.5) + 'px;color:' + MUTED + '' + ov(STYLES.rerollNote) + '\">'\n              + copy(C.rerollNote)\n              + '</div></div>'\n            : '')\n        + '</div>';\n    }\n\n    // Controls first, then the card. Stacking them (rather than a side column) is what lets the three\n    // panels run the full width \u2014 at 44% each panel was too small to type on, which is the whole point.\n    // Everything the shopper sets lives in the left column; the right column is purely what they get.\n    // Splitting them (mode switch above, fields inside) left 764px of dead space beside the two panels.\n    var personalizeBody = '<div id=\"bhr-card-stage\">'\n      + cardStageHTML(v, writerGroup + nameGroup + evGroup + titleGroup + messageGroup + schrodGroup) + '</div>';\n    var s03 = step(n.b, [copy(C.toneTitle), 'toneTitle'], [copy(C.toneNote), 'toneNote'], personalizeBody);\n\n    // 04 art carousel\n    var cardW = v.m ? 'width:238px' : 'width:calc((100% - 28px) / 3)';\n    var track = v.m ? 'transform:translateX(-' + (v.car * 252) + 'px)' : 'transform:translateX(calc((100% - 28px) / -3 * ' + v.car + ' - ' + (v.car * 14) + 'px))';\n    var cards = ART.map(function (a, i) {\n      var on = s.art === i;\n      var glow = on ? '<span style=\"position:absolute;inset:0;border-radius:10px;box-shadow:inset 0 0 0 2px #e07b1f, inset 0 0 34px rgba(224,123,31,0.35);animation:photonGlow 2.6s ease-in-out infinite\"></span><span style=\"position:absolute;left:10px;top:10px;background:rgba(224,123,31,0.92);color:#0b0b0d;font-family:\\'Space Mono\\',monospace;font-size:' + px(9.5) + 'px;letter-spacing:0.14em;text-transform:uppercase;padding:4px 9px;border-radius:999px\">Registered</span>' : '';\n      return '<button data-act=\"art\" data-id=\"' + i + '\" style=\"flex:0 0 auto;padding:0;background:none;border:none;cursor:pointer;text-align:left;color:inherit;' + cardW + '\">'\n        + '<span style=\"position:relative;display:block;border-radius:10px;overflow:hidden;border:1px solid ' + (on ? '#e07b1f' : '#2b2b32') + ';background:#000;transition:all .2s ease;' + (on ? 'box-shadow:0 0 0 3px rgba(224,123,31,0.16)' : '') + '\">'\n        // 5:4, the masters' own aspect \u2014 the card shows the FULL artwork the customer buys, nothing\n        // cover-cropped. It was 3/2 (no recorded reason), which ate ~17% of the height and clipped\n        // the bottom-centre watermark by a different amount on the selected card.\n        //\n        // No scale() on selection. The old 1.06 zoom was pure emphasis, but inside an\n        // overflow-hidden cover frame a zoom IS a crop: the selected card's framing (and the\n        // watermark's position) shifted ~3% against its neighbours, which read as misalignment.\n        // The orange glow ring and the Registered chip carry the selection on their own.\n        + '<img src=\"' + a.src + '\" alt=\"\" style=\"display:block;width:100%;aspect-ratio:5/4;object-fit:cover\">' + glow\n        + '<span data-act=\"zoom\" data-id=\"' + i + '\" style=\"position:absolute;right:10px;bottom:10px;width:30px;height:30px;border-radius:8px;background:rgba(0,0,0,0.62);border:1px solid rgba(255,255,255,0.16);color:' + INK + ';display:flex;align-items:center;justify-content:center;font-size:' + px(13) + 'px\">&#9974;</span></span>'\n        // Name + code only. The `sub` line (\"Binary \u00B7 multi spectral\") is gone: it is derived from the\n        // image's own tags, so its length varies per card, and with the name/code row set\n        // space-between the third line gave every card a different visual weight \u2014 the rail read as\n        // ragged rather than as a set. It also told the shopper nothing they are choosing on.\n        // `sub` is still carried on the art record and still shown in the lightbox.\n        + '<span style=\"display:flex;justify-content:space-between;align-items:baseline;margin-top:9px;gap:8px\"><span style=\"font-size:' + px(13) + 'px;font-weight:500;color:' + (on ? '#e07b1f' : INK) + '\">' + esc(a.name) + '</span><span style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(10.5) + 'px;color:' + MUTED + '\">' + esc(a.code) + '</span></span>'\n        + '</button>';\n    }).join('');\n    // Quiet chevrons pinned to the outer edges \u2014 they sit outside the clipping viewport so they never cover\n    // the art, and stay dim until you hover the carousel. Dragging the track works too (see the pointer\n    // handlers): grab and throw on desktop, swipe on touch.\n    // Same nav treatment as the occasion marquee at the top of the page: 42px round buttons pinned to the\n    // edges, hidden until the carousel is hovered so they never sit over the artwork while you're looking.\n    var artArrow = function (act, side, glyph) {\n      return '<button data-act=\"' + act + '\" class=\"bhr-art-nav\" aria-label=\"' + (side === 'left' ? 'Previous' : 'Next') + '\" style=\"position:absolute;' + side + ':6px;top:calc((100% - 46px) / 2);transform:translateY(-50%);z-index:3;width:42px;height:42px;padding:0;border-radius:50%;border:1px solid rgba(255,255,255,0.18);background:rgba(10,10,13,0.72);color:' + INK + ';display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:' + px(24) + 'px;line-height:1;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)\">' + glyph + '</button>';\n    };\n    var artBody = '<div style=\"font-size:' + px(12.5) + 'px;color:' + MUTED + ';margin-bottom:14px' + ov(STYLES.gallerySub) + '\">' + esc(copy(C.gallerySub)) + '</div>'\n      + '<div class=\"bhr-art-frame\" style=\"position:relative\">'\n      + '<div data-artviewport=\"1\" style=\"overflow:hidden;cursor:grab\"><div style=\"display:flex;gap:14px;transition:transform .45s cubic-bezier(.2,.7,.2,1);' + track + '\">' + cards + '</div></div>'\n      + artArrow('prevArt', 'left', '&#8249;') + artArrow('nextArt', 'right', '&#8250;') + '</div>'\n      + '<div style=\"display:flex;margin-top:12px\"><button data-act=\"surprise\" style=\"margin-left:auto;font-size:' + px(12.5) + 'px;padding:0 16px;height:38px;border-radius:999px;background:none;border:1px solid #303037;color:' + MUTED + ';cursor:pointer' + ov(STYLES.surpriseLabel) + '\">' + esc(copy(C.surpriseLabel)) + '</button></div>';\n    var s04 = step(n.at, [copy(C.galleryTitle), 'galleryTitle'], v.art.name + ' \u00B7 ' + (s.art + 1) + ' of ' + ART.length, artBody);\n\n    // 06 add-ons\n    // Two across on mobile, three on desktop \u2014 anything beyond that scrolls rather than shrinking.\n    var addonPer = v.m ? 2 : 3;\n    var addonCardW = 'calc((100% - ' + (10 * (addonPer - 1)) + 'px) / ' + addonPer + ')';\n    var addonScrolls = v.addons.length > addonPer;\n    var addonMax = Math.max(0, v.addons.length - addonPer);\n    if (state.addonCar > addonMax) state.addonCar = addonMax;   // list shrank under us\n    var addons = v.addons.map(function (a) {\n      var on = s.addons.indexOf(a.id) > -1;\n      var all = sizesOf(a), sel = sizeOf(a), si = sizeIdx(a);\n      // POD add-ons (box present) composite the customer's art onto the mockup + show the art code badge.\n      // Non-POD add-ons just show the product image (a.image), or the mockup image if that's all we have.\n      // Mockup and box come from the SELECTED SIZE: a 252-piece puzzle and a 2000-piece one are different\n      // photographs whose print rectangles differ in aspect (1.286 vs 1.449).\n      // Any view at all means we have something product-shaped to show. Testing for a `box`\n      // meant pre-rendered photographs (which need no box) fell through to the plain product\n      // image and the whole mockup stage was skipped.\n      var vw = viewsOf(a), pod = vw.length > 0, visual;\n      if (pod) {\n        visual = mockupStage(a, v.art.src, '4/3')\n          + '<span style=\"position:absolute;left:7px;top:7px;z-index:3;font-family:\\'Space Mono\\',monospace;font-size:' + px(9) + 'px;letter-spacing:0.12em;text-transform:uppercase;color:' + INK + ';background:rgba(0,0,0,0.6);border:1px solid rgba(255,255,255,0.14);border-radius:999px;padding:3px 7px\">' + esc(v.art.code) + '</span>'\n          + '<span data-act=\"addonZoom\" data-id=\"' + a.id + '\" style=\"position:absolute;right:7px;top:7px;z-index:3;width:26px;height:26px;border-radius:7px;background:rgba(0,0,0,0.62);border:1px solid rgba(255,255,255,0.16);color:' + INK + ';display:flex;align-items:center;justify-content:center;font-size:' + px(12) + 'px;cursor:pointer\">&#9974;</span>';\n      } else {\n        visual = '<span style=\"display:block;width:100%;aspect-ratio:4/3;background:#ececed;border-radius:8px;overflow:hidden\">'\n          + '<img src=\"' + (a.image || '') + '\" alt=\"' + esc(a.name) + '\" style=\"width:100%;height:100%;object-fit:cover;pointer-events:none\"></span>';\n      }\n\n      // Size pills, only when there is a choice to make. These are nested inside the add-on button, so\n      // they stopPropagation in the handler \u2014 picking a size must not toggle the add-on off.\n      var sizePills = all.length < 2 ? '' :\n        '<span style=\"display:flex;flex-wrap:wrap;gap:5px\">' + all.map(function (sz, i) {\n          var cur = i === si;\n          return '<span data-act=\"addonSize\" data-id=\"' + a.id + '\" data-i=\"' + i + '\" role=\"button\" tabindex=\"0\"'\n            + ' style=\"cursor:pointer;font-size:' + px(10.5) + 'px;line-height:1;padding:5px 8px;border-radius:999px;white-space:nowrap;'\n            + 'background:' + (cur ? '#e07b1f' : '#1b1b20') + ';border:1px solid ' + (cur ? '#e07b1f' : '#34343c') + ';'\n            + 'color:' + (cur ? '#0b0b0d' : '#b9b9c2')\n            // Dimming alone reads as \"not selected\". Say sold out, or the shopper picks it and only\n            // learns at the cart.\n            + (sz.available === false ? ';opacity:.5;text-decoration:line-through' : '') + '\"'\n            + (sz.available === false ? ' title=\"' + esc(copy(C.outOfStock)) + '\"' : '') + '>'\n            + esc(sz.label) + (sz.available === false ? ' \u00B7 sold out' : '') + '</span>';\n        }).join('') + '</span>';\n\n      var sellable = addonSellable(a);\n      // Adding costs money, so it takes a deliberate press of a button that says so. The tile itself is\n      // NOT a click target: it was, and a stray click anywhere on a large card silently added an \u00A389\n      // item. The image opens the viewer instead, which is what someone poking at a product photo\n      // actually wants.\n      return '<div style=\"flex:0 0 auto;box-sizing:border-box;width:' + addonCardW + ';text-align:left;background:#101013;border:1px solid ' + (on ? '#e07b1f' : '#2b2b32') + ';border-radius:12px;padding:10px;color:inherit;display:flex;flex-direction:column;gap:8px;transition:all .18s ease;' + (on ? 'background:#17120c' : '') + '\">'\n        // width:100% is load-bearing: every child of this wrapper is absolutely positioned, so it has no\n        // intrinsic width, and the button's align-items is not `stretch` \u2014 without it the box collapses to\n        // 0x0 and the mockup silently disappears while still reporting as \"loaded\".\n        + '<span data-act=\"addonZoom\" data-id=\"' + a.id + '\" role=\"button\" tabindex=\"0\" aria-label=\"View ' + esc(a.name) + '\" style=\"display:block;position:relative;width:100%;align-self:stretch;cursor:zoom-in\">' + visual + '</span>'\n        + '<span style=\"display:flex;align-items:center;gap:8px\"><span style=\"font-size:' + px(13) + 'px;font-weight:500\">' + esc(a.name) + '</span></span>'\n        + sizePills\n        + shipsNote(a)\n        + '<span style=\"display:flex;align-items:center;gap:8px;padding-top:8px;margin-top:auto;border-top:1px solid #232329\">'\n        + '<span style=\"' + priceStyle() + '\">+' + money(sel.price) + '</span>'\n        + '<button data-act=\"addon\" data-id=\"' + a.id + '\"' + (sellable ? '' : ' disabled')\n        + ' aria-pressed=\"' + (on ? 'true' : 'false') + '\" style=\"margin-left:auto;font-size:' + px(12) + 'px;font-weight:600;letter-spacing:0.01em;padding:8px 14px;border-radius:8px;'\n        + (!sellable ? 'cursor:not-allowed;background:#1b1b20;border:1px solid #34343c;color:' + MUTED + ''\n            : on ? 'cursor:pointer;background:#2a2118;border:1px solid #e07b1f;color:#e07b1f'\n                 : 'cursor:pointer;background:#e07b1f;border:1px solid #e07b1f;color:#0b0b0d') + '' + ov(!sellable ? STYLES.outOfStock : null) + '\">'\n        + (!sellable ? esc(copy(C.outOfStock)) : on ? '&#10003; Added' : 'Add') + '</button></span></div>';\n    }).join('');\n\n    // The add-on row is a carousel on the same terms as the art carousel: a fixed number of cards\n    // visible, drag to throw, and edge chevrons that only appear once there is something off-screen.\n    // A grid silently hid the 4th product; this makes \"there is more\" visible.\n    var addonTrack = 'transform:translateX(calc(-' + state.addonCar + ' * (' + addonCardW + ' + 10px)))';\n    var addonBody = '<div class=\"bhr-addon-frame\" style=\"position:relative\">'\n      + '<div data-addonviewport=\"1\" style=\"overflow:hidden;' + (addonScrolls ? 'cursor:grab' : '') + '\">'\n      + '<div style=\"display:flex;gap:10px;align-items:stretch;transition:transform .45s cubic-bezier(.2,.7,.2,1);' + addonTrack + '\">'\n      + addons + '</div></div>'\n      + (addonScrolls ? navBtn('prevAddon', 'left', '&#8249;') + navBtn('nextAddon', 'right', '&#8250;') : '')\n      + '</div>';\n    // With no add-ons configured the step would render an empty grid, which reads as broken rather than\n    // as \"nothing on offer\" \u2014 so drop the step entirely instead.\n    var s06 = v.addons.length ? step(n.c, [copy(C.addonsTitle), 'addonsTitle'],\n      [fill(copy(C.addonsNote), { art: v.art.name }), 'addonsNote'],\n      addonBody) : '';\n\n    // Order: 01 product \u00B7 02 occasion \u00B7 03 choose black hole \u00B7 04 personalize (tone + details + recipient) \u00B7\n    // 05 add-ons. The event's required detail fields + \"who is this for\" now live inside step 04.\n    return '<div style=\"flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:14px\">' + s01 + occSection + s04 + s03 + s06 + '</div>';\n  }\n  // ---- missing-field flagging -------------------------------------------------------------------\n  // An alert() names the problem and then vanishes, leaving the shopper on a long form with no idea WHICH\n  // box to fill. The flag is held in module state so it survives the re-render, and it is shown in both\n  // places the shopper is looking: on the field itself, and under the button they just pressed.\n  var _missing = [];        // data-keys that are required and empty\n  var _missingMsg = '';     // the sentence shown under every Add to Cart button\n\n  var ERR = '#e0552f';\n  function errBox(key) {    // outline + glow for a flagged control\n    return _missing.indexOf(key) >= 0\n      ? 'border-color:' + ERR + ';box-shadow:0 0 0 3px rgba(224,85,47,0.28)'\n      : '';\n  }\n  function errNote(key, text) {\n    return _missing.indexOf(key) >= 0\n      ? '<div data-err-for=\"' + key + '\" style=\"font-size:' + px(11.5) + 'px;color:' + ERR + ';line-height:1.35' + ov(STYLES.fieldRequired) + '\">'\n        // The caller used to pass this and every required field got the NAME's message. flagMissing\n        // already knows why the field was flagged, so the message comes from there.\n        + esc(text || _missingMsg || 'Required') + '</div>'\n      : '';\n  }\n  /** Drop a field's flag the moment it is filled, without a full re-render that would steal focus. */\n  function clearFlag(key) {\n    var i = _missing.indexOf(key);\n    if (i < 0) return;\n    _missing.splice(i, 1);\n    var inp = mount.querySelector('[data-key=\"' + key + '\"]');\n    if (inp) { inp.style.borderColor = ''; inp.style.boxShadow = ''; }\n    var note = mount.querySelector('[data-err-for=\"' + key + '\"]');\n    if (note && note.parentNode) note.parentNode.removeChild(note);\n    if (!_missing.length) {\n      _missingMsg = '';\n      var ctas = mount.querySelectorAll('[data-err-cta]');\n      for (var j = 0; j < ctas.length; j++) {\n        if (ctas[j].parentNode) ctas[j].parentNode.removeChild(ctas[j]);\n      }\n    }\n  }\n\n  /** A field's label, and the grey qualifier after it.\n   *\n   *  Split because the qualifier is wrapped in a `<span>` carrying a hex colour, and an operator\n   *  editing \"who it's signed by\" in curator should not have to keep a colour intact to do it. The\n   *  words are the operator's; the em dash and the colour are the theme's. */\n  function lbl(text, qualifier, key, qkey) {\n    return '<span style=\"' + ov(key ? STYLES[key] : null) + '\">' + esc(text) + '</span>'\n      + (qualifier ? ' <span style=\"color:' + MUTED + ov(qkey ? STYLES[qkey] : null) + '\">&mdash; ' + esc(qualifier) + '</span>' : '');\n  }\n\n  function field(label, key, val, ph, full, maxlen, req) {\n    // `req` marks the field required. The asterisk is what a shopper reads; `required`/`aria-required` is\n    // what the browser and a screen reader read. The actual refusal lives in addToCart(), because this\n    // wizard never submits a form \u2014 a native validation attribute alone would block nothing.\n    var mark = req ? '<span style=\"color:#e07b1f\" aria-hidden=\"true\"> *</span>' : '';\n    return '<label style=\"display:flex;flex-direction:column;gap:6px;' + (full ? 'grid-column:1/-1' : '') + '\"><span style=\"font-size:' + LABEL + 'px;color:' + MUTED + '\">' + label + mark + '</span><input value=\"' + esc(val) + '\" data-act=\"text\" data-key=\"' + key + '\" placeholder=\"' + esc(ph) + '\"' + (maxlen ? ' maxlength=\"' + maxlen + '\"' : '') + (req ? ' required aria-required=\"true\"' : '') + '  style=\"background:#0f0f12;border:1px solid #2b2b32;border-radius:8px;padding:11px 12px;color:' + INK + ';font-size:' + px(14) + 'px;outline:none;' + errBox(key) + '\">' + errNote(key) + '</label>';\n  }\n  // A calendar field. Same data-act as a text field, so typing re-renders the certificate preview with\n  // the date the shopper chose; the browser supplies the picker and an ISO value or an empty string.\n  function dateField(label, key, val) {\n    return '<label style=\"display:flex;flex-direction:column;gap:6px;grid-column:1/-1\"><span style=\"font-size:' + LABEL + 'px;color:' + MUTED + '\">' + label + '</span><input type=\"date\" value=\"' + esc(val || '') + '\" data-act=\"text\" data-key=\"' + key + '\"'\n      + ' style=\"background:#0f0f12;border:1px solid #2b2b32;border-radius:8px;padding:11px 12px;color:' + INK + ';font-size:' + px(14) + 'px;outline:none;color-scheme:dark\"></label>';\n  }\n  function fieldArea(label, key, val, ph) {\n    return '<label style=\"display:flex;flex-direction:column;gap:6px;grid-column:1/-1\"><span style=\"font-size:' + LABEL + 'px;color:' + MUTED + '\">' + label + '</span><textarea data-act=\"text\" data-key=\"' + key + '\" rows=\"3\" placeholder=\"' + esc(ph) + '\" style=\"background:#0f0f12;border:1px solid #2b2b32;border-radius:8px;padding:11px 12px;color:' + INK + ';font-size:' + px(14) + 'px;outline:none;resize:vertical;font-family:inherit\">' + esc(val) + '</textarea></label>';\n  }\n\n  // One printed face, as a 3/2 box, so an image face and a rendered plate compose the same way.\n  function imgFace(src, fit) {\n    // The mockup backdrop, not white. Product photography here is transparent PNG over whatever sits\n    // behind it, and the card's ENVELOPE is white \u2014 on a white field it disappears and only the\n    // artwork reads. `mockupBg` is a theme setting so the shade stays tunable without a deploy.\n    // CFG.mockupBg, NOT C.mockupBg: the backdrop is a theme SETTING, not operator copy, so the section\n    // emits it beside `copy` rather than inside it. Read off `C` it was undefined at every render and\n    // this literal always won, which made the \"Product mockup backdrop\" setting do nothing to the\n    // shade drawn here (measured on the live store 2026-08-30). The `||` stays: a colour needs a value.\n    var mbg = CFG.mockupBg || '#191919';\n    if (!src) return '<div style=\"width:100%;aspect-ratio:3/2;background:' + mbg + '\"></div>';\n    return '<div style=\"position:relative;width:100%;aspect-ratio:3/2;background:' + mbg + ';overflow:hidden\">'\n      + '<img src=\"' + src + '\" alt=\"\" style=\"display:block;width:100%;height:100%;object-fit:' + (fit || 'cover') + '\"></div>';\n  }\n\n  // Two faces as one opened card. Order is the print-file order (front|back, inside1|inside2), which is\n  // also the order the panel editor uses, so the preview and the editor never disagree about which face\n  // is which.\n  function spreadHTML(left, right) {\n    return '<div style=\"width:100%;height:100%;box-sizing:border-box;padding:12px;display:flex;align-items:center;justify-content:center\">'\n      + '<div style=\"display:flex;width:100%;align-items:stretch;box-shadow:0 16px 44px rgba(0,0,0,0.55)\">'\n      +   '<div style=\"flex:1 1 50%;min-width:0\">' + left + '</div>'\n      +   '<div style=\"flex:0 0 1px;background:rgba(0,0,0,0.28)\"></div>'\n      +   '<div style=\"flex:1 1 50%;min-width:0\">' + right + '</div>'\n      + '</div></div>';\n  }\n\n  function renderRail() {\n    var v = vals(), s = state, pkg = v.pkg, occ = v.occ, tone = v.tone, art = v.art;\n    var slidesHtml = v.slides.map(function (sl, i) {\n      // Rendered HERE, not in vals(), because these need the completed `v`.\n      var inner;\n      if (sl.face === 'outside') {\n        inner = spreadHTML(imgFace(art.src, 'cover'),\n                           imgFace((CFG.assets && CFG.assets.cardBack) || '', 'contain'));\n      } else if (sl.face === 'open') {\n        inner = spreadHTML(certPlateHTML(v), insideTwoHTML(v));\n      } else if (sl.face === 'cert') {\n        inner = spreadHTML(certPlateHTML(v), imgFace(art.src, 'cover'));\n      } else if (sl.addon) {\n        var ad = findAddon(sl.addon);\n        inner = ad ? mockupStage(ad, art.src, '16/10', { noNav: true })\n                   : '<div style=\"width:100%;height:100%;background:#0e0e11\"></div>';\n      } else if (sl.img) {\n        inner = '<img src=\"' + sl.img + '\" alt=\"\" style=\"display:block;width:100%;height:100%;object-fit:cover;' + (sl.imgStyle || '') + '\">';\n      } else {\n        // Nothing to show. No slide should reach this \u2014 every entry above carries a face, an add-on or\n        // an image \u2014 so it is a quiet neutral panel rather than the hatched \"Mockup pending\" placard it\n        // used to be. A preview that announces its own gaps is worse than one that is simply shorter.\n        inner = '<div style=\"width:100%;height:100%;background:#0e0e11\"></div>';\n      }\n      return '<div style=\"flex:0 0 100%;position:relative;aspect-ratio:16/10\">' + inner + '</div>';\n    }).join('');\n    var dots = v.slides.map(function (sl, i) { return '<button data-act=\"slide\" data-id=\"' + i + '\" style=\"width:7px;height:7px;padding:0;border-radius:50%;border:none;cursor:pointer;transition:all .2s ease;' + (i === v.slide ? 'background:#e07b1f;transform:scale(1.35)' : 'background:#4a4a54') + '\"></button>'; }).join('');\n    var preview = '<div data-carousel=\"1\" style=\"background:#141417;border:1px solid #232329;border-radius:14px;overflow:hidden;display:flex;flex-direction:column;' + (v.m ? '' : 'flex:1.15 1 0;min-width:0') + '\">'\n      + '<div style=\"position:relative;background:#0e0e11;overflow:hidden\"><div style=\"display:flex;transition:transform .45s cubic-bezier(.2,.7,.2,1);transform:translateX(-' + (v.slide * 100) + '%)\">' + slidesHtml + '</div>'\n      + '<div style=\"position:absolute;left:12px;top:12px;font-family:\\'Space Mono\\',monospace;font-size:' + px(10) + 'px;letter-spacing:0.14em;color:' + INK + ';background:rgba(0,0,0,0.6);border:1px solid rgba(255,255,255,0.14);border-radius:999px;padding:4px 10px' + ov(v.slides[v.slide].key ? STYLES[v.slides[v.slide].key] : null) + '\">' + esc(v.slides[v.slide].label) + '</div>'\n      + '<div style=\"position:absolute;right:12px;top:12px;display:flex;align-items:center;gap:8px;background:rgba(0,0,0,0.6);border:1px solid rgba(255,255,255,0.14);border-radius:8px;padding:5px 9px 5px 5px\"><img src=\"' + art.src + '\" alt=\"\" style=\"width:36px;height:26px;object-fit:cover;border-radius:4px;display:block\"><span style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(10) + 'px;letter-spacing:0.12em;color:' + INK + '\">' + esc(art.code) + '</span></div>'\n      + '<div style=\"position:absolute;left:0;right:0;bottom:10px;display:flex;align-items:center;justify-content:center;gap:10px\"><button data-act=\"prevSlide\" style=\"width:30px;height:30px;padding:0;border-radius:50%;background:rgba(0,0,0,0.6);border:1px solid rgba(255,255,255,0.16);color:' + INK + ';display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:' + px(13) + 'px\">&#8592;</button><div style=\"display:flex;gap:6px\">' + dots + '</div><button data-act=\"nextSlide\" style=\"width:30px;height:30px;padding:0;border-radius:50%;background:rgba(0,0,0,0.6);border:1px solid rgba(255,255,255,0.16);color:' + INK + ';display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:' + px(13) + 'px\">&#8594;</button></div></div>'\n      + '<div style=\"padding:14px 16px 16px 16px;display:flex;flex-direction:column;gap:7px\"><div style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(10.5) + 'px;letter-spacing:0.18em;text-transform:uppercase;color:#e07b1f' + ov(occ ? STYLES.previewEyebrow : STYLES.previewEyebrowNone) + '\">' + esc(occ ? copy(C.previewEyebrow) : copy(C.previewEyebrowNone)) + '</div>'\n      + '<div style=\"font-size:' + px(18) + 'px;font-weight:500;line-height:1.25' + ov(occ ? STYLES.previewTitle : STYLES.previewTitleNone) + '\">' + (occ ? esc(fill(copy(C.previewTitle), { occasion: occ.name }))\n                : esc(copy(C.previewTitleNone))) + '</div>'\n      + '<div style=\"font-size:' + px(15) + 'px;color:' + MUTED + ';line-height:1.6' + ov(occ ? styleOf(occ.styles, 'blurb') : STYLES.previewBlurbNone) + '\">' + (occ ? occ.blurb + ' '\n                : esc(copy(C.previewBlurbNone)) + ' ')\n      + '<span style=\"' + ov(styleOf(tone.styles, 'line')) + '\">' + esc(tone.line) + '</span></div></div></div>';\n\n    var summaryRows = [\n      { k: 'Occasion', v: occ ? (v.exBits.length ? occ.name + ' \u00B7 ' + v.exBits.join(', ') : occ.name) : 'Not set', dim: !occ },\n      { k: 'Tone', v: tone.name, dim: false },\n      { k: 'Black hole', v: art.name + ' (' + art.code + ')', dim: false },\n      { k: 'Recipient', v: s.name || 'Not set', dim: !s.name },\n      { k: 'From', v: s.from || 'Anonymous', dim: false },\n      { k: 'Package', v: pkg.short, dim: false },\n      { k: 'Add-ons', v: v.chosen.length ? v.chosen.map(function (a) {\n          var sz = sizeOf(a); return sz.label ? a.name + ' (' + sz.label + ')' : a.name;\n        }).join(', ') : 'None', dim: !v.chosen.length }\n    ].map(function (r) { return '<div style=\"display:flex;justify-content:space-between;gap:14px;font-size:' + px(12.5) + 'px;padding:6px 0;border-bottom:1px solid #1e1e23\"><span style=\"color:' + MUTED + '\">' + esc(r.k) + '</span><span style=\"text-align:right;' + (r.dim ? 'color:' + MUTED + '' : '') + '\">' + esc(r.v) + '</span></div>'; }).join('');\n    var summary = '<div style=\"display:flex;flex-direction:column;gap:12px;' + (v.m ? '' : 'flex:1 1 0;min-width:0') + '\">'\n      + '<div style=\"flex:1 1 auto;background:#141417;border:1px solid #232329;border-radius:14px;padding:16px\"><div style=\"display:flex;align-items:center;gap:10px;margin-bottom:12px\"><span style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(10.5) + 'px;letter-spacing:0.18em;text-transform:uppercase;color:' + MUTED + '' + ov(STYLES.summaryTitle) + '\">' + esc(copy(C.summaryTitle)) + '</span><span style=\"margin-left:auto;font-family:\\'Space Mono\\',monospace;font-size:' + px(10.5) + 'px;color:#e07b1f\">' + esc(pkg.tag) + '</span></div>' + summaryRows + '</div>'\n      + '<div style=\"background:#141417;border:1px solid #232329;border-radius:14px;padding:14px 16px 16px 16px\"><div style=\"display:flex;justify-content:space-between;align-items:baseline\"><span style=\"font-size:' + px(13) + 'px;color:' + MUTED + '\">Total</span><span style=\"' + priceStyle(C.totalSize || 30, 500) + ';color:' + INK + '\">' + money(v.total) + '</span></div>'\n      + (function () {\n          // Say it on the button. A shopper who cannot buy should see that before clicking, not after.\n          var so = soldOut(v);\n          return '<button data-act=\"addToCart\"' + (so.length ? ' disabled' : '')\n            + ' style=\"width:100%;margin-top:12px;padding:14px;border-radius:10px;border:none;font-size:' + px(14) + 'px;font-weight:600;letter-spacing:0.01em;'\n            + (so.length ? 'cursor:not-allowed;background:#2b2b32;color:' + MUTED + '' : 'cursor:pointer;background:#e07b1f;color:#0b0b0d') + ov(so.length ? STYLES.outOfStock : STYLES.ctaLabel) + '\">'\n            + esc(so.length ? copy(C.outOfStock) : (copy(C.ctaLabel))) + '</button>'\n            + (so.length ? '<div style=\"margin-top:8px;font-size:' + px(12) + 'px;color:#e0863f;text-align:center' + ov(STYLES.sizeUnavailable) + '\">'\n                + esc(fill(copy(C.sizeUnavailable), { item: so[0] })) + '</div>' : '')\n            + (_missingMsg ? '<div data-err-cta style=\"margin-top:8px;font-size:' + px(12) + 'px;color:' + ERR + ';text-align:center;line-height:1.35\">' + esc(_missingMsg) + '</div>' : '');\n        })()\n      + '<div style=\"text-align:center;font-size:' + px(11) + 'px;color:' + MUTED + ';margin-top:9px' + ov(pkg.id === 'basic' ? STYLES.deliveryNoteCard : STYLES.deliveryNoteBox) + '\">' + esc(pkg.id === 'basic' ? copy(C.deliveryNoteCard)\n                             : copy(C.deliveryNoteBox)) + '</div>'\n      // Repeat the split-shipment warning at the point of commitment. The badge on the add-on card is easy\n      // to miss once it's been ticked and scrolled past, and \"where's the rest of my order\" is the single\n      // most avoidable support ticket here.\n      + (function () {\n        var sep = v.chosen.filter(function (a) { return a.shipsSeparately; });\n        if (!sep.length) return '';\n        var names = sep.map(function (a) { return a.name; }).join(' and ');\n        return '<div style=\"display:flex;gap:8px;margin-top:11px;padding-top:11px;border-top:1px solid #1e1e23;font-size:' + px(11) + 'px;line-height:1.5;color:' + MUTED + '' + ov(STYLES.shipsSeparatelyNote) + '\">'\n          + '<svg width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"#8b8b93\" stroke-width=\"1.5\" style=\"flex:0 0 auto;margin-top:2px\" aria-hidden=\"true\"><path d=\"M1 4.5h9v7H1z\"/><path d=\"M10 7h3l2 2.2v2.3h-5z\"/><circle cx=\"4\" cy=\"12.5\" r=\"1.4\"/><circle cx=\"11.7\" cy=\"12.5\" r=\"1.4\"/></svg>'\n          + '<span>' + esc(names) + ' ' + (sep.length > 1 ? 'ship' : 'ships') + ' separately &mdash; '\n          + esc(copy(C.shipsSeparatelyNote)) + '</span></div>';\n      })()\n      + '</div></div>';\n\n    return '<aside style=\"flex:0 0 auto;box-sizing:border-box;display:flex;gap:14px;' + (v.m ? 'flex-direction:column;width:100%' : 'width:100%;flex-direction:row;align-items:stretch') + '\">' + preview + summary + '</aside>';\n  }\n  function renderBar() {\n    var v = vals();\n    var _barSoldOut = soldOut(v).length > 0;\n    if (!v.m) { var b = document.getElementById('bhr-bar'); if (b) b.style.display = 'none'; return; }\n    var el = document.getElementById('bhr-bar'); if (!el) return;\n    el.style.display = 'flex';\n    el.innerHTML = '<img src=\"' + v.pkg.img + '\" alt=\"\" style=\"width:52px;height:52px;border-radius:8px;object-fit:cover;background:#0e0e11;flex:0 0 auto;' + (v.pkg.imgStyle || '') + '\"><div style=\"display:flex;flex-direction:column;min-width:0\"><span style=\"font-size:' + px(11.5) + 'px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis\">' + esc(v.pkg.short) + '</span><span style=\"' + priceStyle(Math.round((C.totalSize || 30) * 0.6), 500) + '\">' + money(v.total) + '</span><span style=\"font-size:' + px(10) + 'px;color:' + MUTED + ';white-space:nowrap;overflow:hidden;text-overflow:ellipsis\">' + esc(v.art.name + ' \u00B7 ' + (v.occ ? v.occ.name : 'No occasion') + (v.chosen.length ? ' \u00B7 +' + v.chosen.length : '')) + '</span></div><button data-act=\"addToCart\"' + (_barSoldOut ? ' disabled' : '') + ' style=\"flex:1;padding:13px 10px;border-radius:10px;border:none;font-size:' + px(13.5) + 'px;font-weight:600;' + (_barSoldOut ? 'cursor:not-allowed;background:#2b2b32;color:' + MUTED + '' : 'cursor:pointer;background:#e07b1f;color:#0b0b0d') + '' + ov(_barSoldOut ? STYLES.outOfStock : STYLES.ctaLabel) + '\">' + esc(_barSoldOut ? copy(C.outOfStock) : (copy(C.ctaLabel))) + '</button>'\n      + (_missingMsg ? '<div data-err-cta style=\"flex-basis:100%;font-size:' + px(11.5) + 'px;color:' + ERR + ';text-align:center;margin-top:6px;line-height:1.3\">' + esc(_missingMsg) + '</div>' : '');\n  }\n  // Gallery lightbox \u2014 an art-viewer, not a dialog: the frame hugs the artwork's own aspect ratio (no\n  // pillarboxing), navigation is the same quiet circular chevrons as the carousel, and there are exactly two\n  // actions \u2014 Select and Close. Drag/swipe works here too.\n  // Add-on viewer: the same product, big, with every calibrated angle reachable. Shares the portal\n  // element with the art viewer \u2014 only one can be open, and both need to escape the theme's stacking\n  // context, so giving them separate containers would just be two copies of the same portal trick.\n  function renderAddonLightbox() {\n    var el = document.getElementById('bhr-lightbox'); if (!el) return;\n    if (!state.alb) { el.style.display = 'none'; el.innerHTML = ''; return; }\n    var a = findAddon(state.alb.id);\n    if (!a) { state.alb = null; el.style.display = 'none'; el.innerHTML = ''; return; }\n    var v = vals(), vw = viewsOf(a), sel = sizeOf(a), all = sizesOf(a);\n    if (el.parentNode !== document.body) document.body.appendChild(el);\n    el.style.display = 'block';\n    var pills = all.length < 2 ? '' :\n      '<span style=\"display:flex;gap:6px;flex-wrap:wrap\">' + all.map(function (sz, i) {\n        var cur = i === sizeIdx(a);\n        return '<span data-act=\"albSize\" data-id=\"' + a.id + '\" data-i=\"' + i + '\" role=\"button\" tabindex=\"0\"'\n          + ' style=\"cursor:pointer;font-size:' + px(12) + 'px;line-height:1;padding:8px 12px;border-radius:999px;white-space:nowrap;'\n          + 'background:' + (cur ? '#e07b1f' : '#1b1b20') + ';border:1px solid ' + (cur ? '#e07b1f' : '#34343c') + ';'\n          + 'color:' + (cur ? '#0b0b0d' : '#b9b9c2') + '\">' + esc(sz.label || a.name) + ' &middot; <span style=\"font-family:' + (C.priceFont || \"'Space Mono', monospace\") + '\">' + money(sz.price) + '</span></span>';\n      }).join('') + '</span>';\n    var on = state.addons.indexOf(a.id) > -1;\n    el.innerHTML = '<div data-act=\"closeAlb\" class=\"bhr-lb-scrim\" style=\"position:fixed;inset:0;z-index:2147483000;background:rgba(6,6,8,0.94);-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:26px 20px;gap:13px;overflow:auto\">'\n      + '<button data-act=\"closeAlb\" aria-label=\"Close\" style=\"position:fixed;right:18px;top:18px;z-index:2;width:42px;height:42px;padding:0;border-radius:50%;border:1px solid rgba(255,255,255,0.18);background:rgba(10,10,13,0.72);color:' + INK + ';display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:' + px(17) + 'px;line-height:1\">&#10005;</button>'\n      + '<div data-act=\"albStage\" style=\"position:relative;width:min(1000px,94vw);display:flex;align-items:center;justify-content:center\">'\n      + mockupStage(a, v.art.src, '4/3', { navPx: 42, maxH: '62vh' }) + '</div>'\n      + '<div data-act=\"albStage\" style=\"display:flex;align-items:center;gap:16px;flex-wrap:wrap;justify-content:center;max-width:min(1000px,94vw);width:100%\">'\n        + '<div style=\"display:flex;flex-direction:column;gap:4px;min-width:0\">'\n          + '<div style=\"font-size:' + HEADING + 'px;font-weight:500;color:' + INK + '\">' + esc(a.name) + '</div>'\n          + '<div style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(11) + 'px;color:' + MUTED + ';letter-spacing:0.09em\">' + esc(v.art.code) + ' &middot; view ' + (viewIdx(a) + 1) + ' / ' + vw.length + '</div>'\n          + (a.shipsSeparately ? '<div style=\"font-size:' + px(11) + 'px;color:' + MUTED + '' + ov(STYLES.shipsSeparatelyNote) + '\">' + esc(copy(C.shipsSeparatelyNote)) + '</div>' : '')\n        + '</div>'\n        + '<div style=\"margin-left:auto;display:flex;align-items:center;gap:12px;flex-wrap:wrap\">' + pills\n        + '<button data-act=\"albToggle\" data-id=\"' + a.id + '\"' + (addonSellable(a) ? '' : ' disabled') + ' style=\"height:44px;padding:0 22px;border-radius:10px;border:none;font-size:' + px(13.5) + 'px;font-weight:600;' + (!addonSellable(a) ? 'cursor:not-allowed;background:#1b1b20;color:' + MUTED + '' : 'cursor:pointer;background:' + (on ? '#2a2118' : '#e07b1f') + ';color:' + (on ? '#e07b1f' : '#0b0b0d')) + '' + ov(!addonSellable(a) ? STYLES.outOfStock : null) + '\">' + (!addonSellable(a) ? esc(copy(C.outOfStock)) : on ? '&#10003; Added &middot; ' + money(sel.price) : 'Add &middot; ' + money(sel.price)) + '</button>'\n        + '<button data-act=\"closeAlb\" style=\"height:44px;padding:0 18px;border-radius:10px;border:1px solid #3a3a42;cursor:pointer;background:none;color:' + MUTED + ';font-size:' + px(13.5) + 'px\">Close</button></div></div></div>';\n  }\n\n  function renderLightbox() {\n    var el = document.getElementById('bhr-lightbox'); if (!el) return;\n    if (state.alb) return;                       // the add-on viewer owns the portal right now\n    if (state.lb === null) { el.style.display = 'none'; el.innerHTML = ''; return; }\n    var a = ART[state.lb], chosen = (state.lb === state.art);\n    // The section sits inside a themed stacking context (#root z-index:13, announcement bar above it), which\n    // buried the viewer's close button \u2014 clicks landed on the announcement bar. Portal the viewer to <body>\n    // so nothing in the theme can stack over it.\n    if (el.parentNode !== document.body) document.body.appendChild(el);\n    el.style.display = 'block';\n    var navBtn = function (act, side, glyph) {\n      return '<button data-act=\"' + act + '\" class=\"bhr-lb-nav\" aria-label=\"' + (side === 'left' ? 'Previous' : 'Next') + '\" style=\"position:absolute;' + side + ':10px;top:50%;transform:translateY(-50%);z-index:3;width:42px;height:42px;padding:0;border-radius:50%;border:1px solid rgba(255,255,255,0.18);background:rgba(10,10,13,0.72);color:' + INK + ';display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:' + px(24) + 'px;line-height:1;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)\">' + glyph + '</button>';\n    };\n    el.innerHTML = '<div data-act=\"closeLb\" class=\"bhr-lb-scrim\" style=\"position:fixed;inset:0;z-index:2147483000;background:rgba(6,6,8,0.94);-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:26px 20px;gap:13px;overflow:auto\">'\n      + '<button data-act=\"closeLb\" class=\"bhr-lb-close\" aria-label=\"Close\" style=\"position:fixed;right:18px;top:18px;z-index:2;width:42px;height:42px;padding:0;border-radius:50%;border:1px solid rgba(255,255,255,0.18);background:rgba(10,10,13,0.72);color:' + INK + ';display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:' + px(17) + 'px;line-height:1\">&#10005;</button>'\n      // stopPropagation via data-act=\"lbStage\": clicks inside the artwork must not close the viewer\n      + '<div data-act=\"lbStage\" data-lbdrag=\"1\" style=\"position:relative;width:min(1180px,94vw);height:74vh;display:flex;align-items:center;justify-content:center\">'\n      + '<img src=\"' + (a.full || a.src) + '\" alt=\"\" draggable=\"false\" style=\"display:block;max-width:100%;max-height:100%;width:auto;height:auto;border-radius:12px;border:1px solid #2b2b32;box-shadow:0 26px 70px rgba(0,0,0,0.6)\">'\n      + navBtn('lbPrev', 'left', '&#8249;') + navBtn('lbNext', 'right', '&#8250;') + '</div>'\n      + '<div data-act=\"lbStage\" style=\"display:flex;align-items:center;gap:16px;flex-wrap:wrap;justify-content:center;max-width:min(1180px,94vw);width:100%\">'\n        + '<div style=\"display:flex;flex-direction:column;gap:2px;min-width:0\">'\n          + '<div style=\"font-size:' + HEADING + 'px;font-weight:500;color:' + INK + '\">' + esc(a.name) + '</div>'\n          + '<div style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(11) + 'px;color:' + MUTED + ';letter-spacing:0.09em\">' + esc(a.code) + '</div></div>'\n        + '<div style=\"font-family:\\'Space Mono\\',monospace;font-size:' + px(11) + 'px;color:' + MUTED + ';margin-left:auto\">' + (state.lb + 1) + ' / ' + ART.length + '</div>'\n        + '<button data-act=\"lbSelect\" style=\"height:44px;padding:0 22px;border-radius:10px;border:none;cursor:pointer;background:' + (chosen ? '#2a2118' : '#e07b1f') + ';color:' + (chosen ? '#e07b1f' : '#0b0b0d') + ';font-size:' + px(13.5) + 'px;font-weight:600' + ov(chosen ? null : STYLES.artSelectLabel) + '\">' + (chosen ? '&#10003; Selected' : esc(copy(C.artSelectLabel))) + '</button>'\n        + '<button data-act=\"closeLb\" class=\"bhr-lb-exit\" style=\"height:44px;padding:0 18px;border-radius:10px;border:1px solid #3a3a42;cursor:pointer;background:none;color:' + MUTED + ';font-size:' + px(13.5) + 'px\">Close</button></div></div>';\n  }\n\n  // --- Panel lightbox ------------------------------------------------------------------------------\n  // A 6x4 panel at half the stage is ~443px, which puts the certificate's registry line at ~6px: it IS\n  // drawn, but the design sets that type at 0.05in cap height on a six-inch card, so at quarter scale it\n  // is unreadable. Enlarging is the only honest fix \u2014 scaling it up on the panel would misrepresent the\n  // print. cqw sizing means the same markup just gets bigger; nothing about the geometry changes.\n  function panelLbEl() {\n    var el = document.getElementById('bhr-panel-lb');\n    if (!el) { el = document.createElement('div'); el.id = 'bhr-panel-lb'; document.body.appendChild(el); }\n    // Its own portal rather than sharing #bhr-lightbox: that one is already contended between the art\n    // viewer and the add-on viewer, and a third claimant would have to know about both.\n    if (el.parentNode !== document.body) document.body.appendChild(el);\n    return el;\n  }\n\n  // The single definition of what the personalize step shows. FRONT is deliberately absent: the chosen\n  // black hole is already the subject of the carousel above, and repeating it only cost room from the two\n  // panels that actually get edited.\n  var PANEL_N = 2;\n  /**\n   * The sealed envelope that covers an inside face until the shopper opens it.\n   *\n   * Rendered OVER the real face rather than instead of it, so opening is a CSS state change on markup\n   * that is already there \u2014 nothing has to be built at click time, the plate behind is already laid\n   * out and fitted, and the reveal cannot flash an empty panel while it renders.\n   */\n  function envelopeHTML() {\n    var seal = (CFG.assets && CFG.assets.waxSeal) || '';\n    return '<button type=\"button\" data-act=\"openCard\" class=\"bhr-env' + (state.opened ? ' is-open' : '')\n      + '\" aria-label=\"Open the envelope\">'\n      + '<span class=\"bhr-env-seam l\"></span><span class=\"bhr-env-seam r\"></span>'\n      + '<span class=\"bhr-env-seam b\"></span>'\n      + '<span class=\"bhr-env-flap\"></span>'\n      + (seal ? '<span class=\"bhr-env-seal\"><img src=\"' + seal + '\" alt=\"\"></span>' : '')\n      + '<span class=\"bhr-env-hint\" style=\"' + ov(STYLES.envelopeHint) + '\">' + esc(copy(C.envelopeHint)) + '</span></button>';\n  }\n\n  /**\n   * The two inside faces.\n   *\n   * In \"we write it\" mode both are sealed until opened \u2014 ONE seal for the pair, not two. It is one\n   * card being opened, and making the shopper break a second seal to read the other half of a spread\n   * they have already opened is a puzzle, not a reveal. Writing your own message never seals: there is\n   * no surprise in copy you are typing yourself, and a cover over the panel would just be in the way.\n   */\n  function panelFaces(v) {\n    // Once opened it is not rendered at all, rather than rendered already-open. An `is-open` overlay\n    // re-created by the next render would replay its 900ms fade on every keystroke and tone change.\n    var seal = state.schrod && !state.opened ? envelopeHTML() : '';\n    return [\n      [esc(copy(C.panelOneCaption)), certPlateHTML(v) + seal, 'panelOneCaption'],\n      [esc(state.schrod ? copy(C.panelTwoWritten)\n                        : copy(C.panelTwoOwn)), insideTwoHTML(v) + seal, state.schrod ? 'panelTwoWritten' : 'panelTwoOwn']\n    ];\n  }\n\n  function renderPanelLightbox() {\n    var el = panelLbEl();\n    if (state.panel === null || state.panel === undefined) { el.style.display = 'none'; el.innerHTML = ''; return; }\n    var v = vals(), faces = panelFaces(v), f = faces[state.panel];\n    var hint = state.panel === 0 ? esc(copy(C.panelOneHint))\n             : (state.panel === 1 && !state.schrod) ? esc(copy(C.panelTwoHint)) : '';\n    var hintKey = state.panel === 0 ? 'panelOneHint' : 'panelTwoHint';\n    el.style.display = 'block';\n    el.innerHTML = '<div data-act=\"closePanel\" class=\"bhr-plb-scrim\">'\n      + '<button data-act=\"closePanel\" class=\"bhr-plb-close\" aria-label=\"Close\">&#10005;</button>'\n      + '<div data-act=\"plbStage\" class=\"bhr-plb-wrap\">'\n      +   '<div class=\"bhr-plb-face\">' + f[1] + '</div>'\n      +   '<div class=\"bhr-plb-bar\">'\n      +     '<button data-act=\"panelPrev\" class=\"bhr-plb-nav\" aria-label=\"Previous panel\">&#8249;</button>'\n      +     '<div class=\"bhr-plb-cap\"><b style=\"' + ov(STYLES[f[2]]) + '\">' + f[0] + '</b>' + (hint ? '<span style=\"' + ov(STYLES[hintKey]) + '\">' + hint + '</span>' : '') + '</div>'\n      +     '<button data-act=\"panelNext\" class=\"bhr-plb-nav\" aria-label=\"Next panel\">&#8250;</button>'\n      +   '</div></div></div>';\n    fitCertText(el); fitMessageBox(el); fitCardTitle(el);\n  }\n\n  // Themes routinely pin the header, and a plain scrollIntoView would tuck the section underneath it.\n  // Measure whatever is actually stuck to the top instead of guessing a height.\n  function stickyOffset() {\n    // [id*=\"header\"] matters: the live theme's sticky bar is #header-outer, a DIV whose classes\n    // (\"no-border-when-sticky has-shadow ready fixed\") contain no \"header\" \u2014 it matched nothing\n    // here, the offset read 0, and every advance landed 149px underneath it. The aim-hold's\n    // corrective ticks re-measure while scrolled (when the bar is actually fixed), so the right\n    // height applies even though the bar only becomes fixed mid-journey.\n    var els = document.querySelectorAll('header, .header, [data-sticky], [class*=\"header\"], [id*=\"header\"]');\n    var h = 0;\n    for (var i = 0; i < els.length; i++) {\n      var cs = getComputedStyle(els[i]), r = els[i].getBoundingClientRect();\n      if ((cs.position === 'fixed' || cs.position === 'sticky') && r.top <= 1 && r.height < 200)\n        h = Math.max(h, r.height);\n    }\n    return h;\n  }\n  // Move to whatever step actually FOLLOWS the given one. The numbering is not contiguous \u2014 occasion and\n  // tone share a section, so there is no step 02 in the DOM \u2014 and hardcoding the next id silently\n  // scrolled nowhere.\n  // Scroll to the step AFTER `id` \u2014 and HOLD the aim there briefly. One scroll is not enough: an\n  // advance usually races async arrivals (the occasion click fires the gallery fetch AND the\n  // pre-written copy fetch; each re-render reflows the page) and the destination drifts out from\n  // under a fire-and-forget scrollTo. So the target is re-pinned every beat until it settles \u2014\n  // smooth for the first glide, instant for corrections \u2014 and the FIRST sign of user input\n  // (wheel, touch, key) cancels the hold: the shopper always outranks the choreography.\n  var _aim = null;\n  function scrollAfterStep(id, holdMs) {\n    var steps = document.querySelectorAll('[id^=\"bhr-step-\"]');\n    var target = null;\n    for (var i = 0; i < steps.length - 1; i++) if (steps[i].id === id) { target = steps[i + 1].id; break; }\n    if (!target) return;\n    if (_aim) _aim.cancel();\n    var first = true, started = Date.now(), deadline = started + (holdMs || 2200);\n    var cancel = function () {\n      if (!_aim) return;\n      clearInterval(_aim.timer);\n      ['wheel', 'touchstart', 'keydown'].forEach(function (ev) { window.removeEventListener(ev, cancel); });\n      _aim = null;\n    };\n    ['wheel', 'touchstart', 'keydown'].forEach(function (ev) { window.addEventListener(ev, cancel, { passive: true }); });\n    var tick = function () {\n      var t = document.getElementById(target);          // re-query: renderAll replaces the node\n      if (!t || Date.now() > deadline) return cancel();\n      var top = Math.max(0, t.getBoundingClientRect().top + window.pageYOffset - stickyOffset() - 14);\n      // Corrections wait out the opening glide (~450ms), then land 'instant' \u2014 NEVER 'auto': the\n      // theme sets scroll-behavior:smooth on the root, which turns 'auto' into a fresh half-second\n      // glide, so 200ms corrections each RESTARTED the animation and the scroll never arrived.\n      // 'instant' overrides the CSS unconditionally.\n      if (first) {\n        window.scrollTo({ top: top, behavior: 'smooth' });\n      } else if (Date.now() - started > 650 && Math.abs(window.pageYOffset - top) > 6) {\n        window.scrollTo({ top: top, behavior: 'instant' });\n      }\n      first = false;\n    };\n    _aim = { timer: setInterval(tick, 200), cancel: cancel };\n    tick();\n  }\n\n  // Land the caret where the scroll lands. preventScroll matters: the smooth scroll owns the\n  // journey, and a bare focus() would yank the page there instantly and cancel it. Caret goes to\n  // the end so a shopper who already typed something resumes rather than overwrites.\n  //\n  // Asserted twice: once now, once after the smooth scroll settles \u2014 anything that grabs focus or\n  // repaints during the glide (the scroll runs ~450ms) would otherwise silently undo the first.\n  function focusField(key) {\n    var place = function () {\n      var inp = document.querySelector('[data-act=\"text\"][data-key=\"' + key + '\"]');\n      if (!inp || document.activeElement === inp) return;\n      try { inp.focus({ preventScroll: true }); } catch (e) { return; /* very old browsers: never yank the page */ }\n      try { var n = inp.value.length; inp.setSelectionRange(n, n); } catch (e2) { /* type=email etc. refuse; fine */ }\n    };\n    place();\n    setTimeout(place, 550);\n  }\n\n  function renderAll() {\n    document.getElementById('bhr-left').innerHTML = renderLeft();\n    document.getElementById('bhr-rail').innerHTML = renderRail();\n    renderBar(); renderLightbox(); renderAddonLightbox(); renderPanelLightbox(); fitCertText(); fitMessageBox(); fitCardTitle(); fitHeroName();\n  }\n  // The rail now contains real certificate + inside-2 plates, whose type is sized in JS from the\n  // measured plate width. Re-rendering without re-fitting left every field at its pre-JS cqw fallback,\n  // so paging the slideshow silently shrank the certificate text.\n  function renderRailOnly() {\n    var rail = document.getElementById('bhr-rail');\n    rail.innerHTML = renderRail();\n    renderBar();\n    fitCertText(rail); fitMessageBox(rail); fitCardTitle(rail);\n  }\n\n  /** Mark fields as missing, repaint so the outline, glow and notes appear, then go to the first one. */\n  function flagMissing(keys, msg) {\n    _missing = keys.slice();\n    _missingMsg = msg;\n    renderAll();                       // the flag is rendered by field()/detail(), so a repaint shows it\n    var first = mount.querySelector('[data-key=\"' + keys[0] + '\"]');\n    if (first) {\n      first.scrollIntoView({ behavior: 'smooth', block: 'center' });\n      setTimeout(function () { if (first.focus) first.focus(); }, 400);\n    }\n  }\n\n  /* ---------- add to cart ---------- */\n  // Anything selected that Shopify will refuse to sell. A Printful item should NEVER appear here:\n  // print-on-demand has no finite stock, so an unavailable POD variant means the variant is\n  // misconfigured (tracking inventory it does not have) \u2014 which is exactly how a metal print showed as\n  // sold out while Printful would have made it happily. Either way the shopper must not be able to buy\n  // it, and must be told why rather than finding out at checkout.\n  // ONLY the package \u2014 the thing actually being bought. If the card or box itself cannot be sold there\n  // is no order to place, so the CTA has to stop.\n  //\n  // An ADD-ON is deliberately NOT considered here. An out-of-stock extra must block ITSELF, never the\n  // whole order: refusing the sale of a card because a metal print is unavailable loses the sale over\n  // an item the shopper would happily drop. Add-ons are blocked at their own Add button, and filtered\n  // out of the cart payload as a backstop.\n  function soldOut(v) {\n    if (v.sizes && v.sizes[v.size] && v.sizes[v.size].available === false) {\n      return [v.pkg.short + (v.sizes[v.size].label ? ' ' + v.sizes[v.size].label : '')];\n    }\n    return [];\n  }\n\n  /** Is the size this add-on is currently showing sellable? */\n  function addonSellable(a) {\n    var sz = sizeOf(a);\n    return !(sz && sz.available === false);\n  }\n\n  // ONE add at a time, across BOTH call sites. The CTA exists twice \u2014 in the summary and in the sticky\n  // bar \u2014 so disabling the clicked button left the other one live, and two quick clicks added the card\n  // twice. A module-level latch is what actually guards the request; the button state is only feedback.\n  var _adding = false;\n\n  // A second bundle for the SAME print is never what anyone means. Every line in a bundle carries\n  // _image_id, so one existing line for this black hole means the whole thing is already in the cart \u2014\n  // and a duplicate cannot be fulfilled anyway, because the image is a one-of-one that gets marked sold.\n  function cartHasPrint(imageId) {\n    return fetch('/cart.js', { headers: { Accept: 'application/json' }, credentials: 'same-origin' })\n      .then(function (r) { return r.ok ? r.json() : null; })\n      .then(function (c) {\n        if (!c || !c.items) return false;            // cannot read the cart: do not block the sale\n        return c.items.some(function (it) {\n          var pr = it.properties || {};\n          return String(pr._image_id || '') === String(imageId);\n        });\n      })\n      .catch(function () { return false; });\n  }\n\n  function addToCart(btn) {\n    var v = vals(), s = state;\n    var occ = v.occ, tone = v.tone, art = v.art, pkg = v.pkg;\n    // Required occasion detail (birthday age, horoscope sign, \u2026) must be filled before checkout.\n    if (v.ex) {\n      var miss = v.ex.fields.filter(function (f) { return f.required && !state.extra[f.key]; });\n      if (miss.length) {\n        flagMissing(miss.map(function (f) { return f.key; }),\n                    fill(copy(C.detailMissing),\n                         { occasion: occ.name,\n                           fields: miss.map(function (f) { return f.label; }).join(' and ') }));\n        return;\n      }\n    }\n    // The recipient's name is required for every occasion and both packages. It is printed on the\n    // certificate and used throughout the generated copy, so an order without one cannot be fulfilled\n    // without going back to the customer. Checked here rather than per-occasion because it is not an\n    // occasion detail \u2014 it is the one field every order needs.\n    if (!(s.name || '').trim()) {\n      flagMissing(['name'], copy(C.needName));\n      return;\n    }\n    // The age gate, enforced where it can actually refuse. A `required` attribute blocks nothing here:\n    // this wizard never submits a form. An unparseable or absent age must NOT fall through to \"adult\" \u2014\n    // that silent default is the entire failure this field exists to prevent.\n    // Refuse anything Shopify will not sell, and say which item \u2014 \"could not add to cart\" at the end\n    // of a five-step wizard tells the shopper nothing about what to change.\n    var out = soldOut(v);\n    if (out.length) {\n      alert(fill(out.length > 1\n        ? copy(C.soldOutMany)\n        : copy(C.soldOutOne),\n        { items: out.join(' and ') }));\n      return;\n    }\n    if (_adding) return;                       // a second click while the first request is in flight\n    _adding = true;\n    var ctas = mount.querySelectorAll('[data-act=\"addToCart\"]');\n    for (var ci2 = 0; ci2 < ctas.length; ci2++) { ctas[ci2].disabled = true; ctas[ci2].textContent = copy(C.adding); }\n    function releaseCTAs(msg) {\n      _adding = false;\n      var again = mount.querySelectorAll('[data-act=\"addToCart\"]');\n      for (var k = 0; k < again.length; k++) { again[k].disabled = false; again[k].textContent = msg; }\n    }\n    var bundle = 'bhr-' + Date.now().toString(36) + Math.random().toString(36).slice(2, 8);\n    // A STABLE mockup url for the cart thumbnail: the shopper's OWN black hole composited into the\n    // product, which is the right picture on the last screen before payment. It points at the app\n    // proxy, NOT at a signed CF url, because a signed one expires long before a cart does.\n    //\n    // The old reasoning here was \"without it the cart falls back to the variant image, which is a\n    // magenta calibration plate\". That is no longer true and was never a good reason: plates were\n    // detached from every variant on 2026-08-25 and the two package variants now carry real product\n    // photography, so the fallback is correct and this is an upgrade rather than a rescue.\n    var mockupUrl = art.id ? (GALLERY_PATH + '/mockup?image=' + encodeURIComponent(art.id)) : '';\n\n    // ONLY ASK FOR A MOCKUP THAT EXISTS. `mockupSkus` is the list of skus this image has been\n    // composited for, and it arrives with the gallery pull \u2014 so whether a request would 404 is known\n    // here, before the property is written.\n    //\n    // This is not a nicety. `_mockup` wins over `line_item.image` in the cart, and it is an <img src>:\n    // once written, a 404 renders a BROKEN IMAGE and Liquid cannot fall through to the variant image\n    // it already skipped. On 2026-08-25 sending `&sku=BHR-CARD-4X6` \u2014 correct, and the fix for a\n    // greeting card showing a metal print \u2014 made the worker 404 exactly as designed, and the cart\n    // showed a broken link. The checkout page was unaffected throughout, because it never asks for a\n    // mockup and reads the variant image directly.\n    function hasMockup(sku) {\n      return !!(sku && art.mockupSkus && art.mockupSkus.indexOf(sku) > -1);\n    }\n    var props = {\n      _bundle_id: bundle, _image_id: art.id || art.code,\n      Occasion: occ ? occ.name : 'Just Because',\n      'Black hole': art.name + ' (' + art.code + ')',\n      Recipient: s.name || '', From: s.from || 'Anonymous', Relationship: s.rel || ''\n      // `_audience` used to be carried here for the order worker to re-check the claimed copy against\n      // (ADR-0017 \u00A78). There is no audience since Amendment A; a cart that still holds the property\n      // from before is accepted and ignored downstream, never rejected.\n    };\n    // NO SKU, NO _mockup. An unfiltered /mockup request is answered with whichever scene the image\n    // happens to have first, and for a greeting-card order that was a metal print \u2014 in the cart and\n    // on the checkout page. The worker is strict when a SKU is named and deliberately permissive when\n    // one is not, because an unfiltered request has claimed nothing; a CART LINE has claimed a\n    // product, so it must always name it. Without a sku the cart falls through to the variant image,\n    // which is a real product photo rather than a picture of something else.\n    if (mockupUrl && hasMockup(v.pkgSku)) props._mockup = mockupUrl + '&sku=' + encodeURIComponent(v.pkgSku);\n    // Inside message: written by us in a tone (\"Schrodinger's Card/Box\"), or written by the customer.\n    // THE WORDS GO ON THE ORDER EITHER WAY.\n    //\n    // This used to send the text only on the customer-written branch; the Registry-written branch sent\n    // \"Written by us \u2014 cheeky tone\" and nothing else. That is now the DEFAULT branch, so the actual\n    // message on the card was reaching the order for the minority case and vanishing for the majority.\n    // A reprint could not reproduce the card, and nobody would find out until two copies of one order\n    // were compared.\n    //\n    // `_text_id` is provenance, not the source of truth: the pool row can be retitled, rewritten or\n    // retired, so the registry stores the words themselves and this only says where they came from.\n    var drawn = drawnPair(v);\n    if (s.schrod) {\n      props.Tone = tone.name;\n      props['Inside'] = 'Written by us \u2014 ' + tone.name + ' tone';\n      props.Message = drawn.message;\n      if (drawn.id) props['_text_id'] = String(drawn.id);\n    } else {\n      props['Inside'] = 'Customer-written';\n      props.Message = msgText(s.msg);\n      if (hasHtml(s.msg)) props['_message_html'] = s.msg;\n    }\n    // Freeze what the certificate showed. The date especially: re-deriving it at fulfilment would print\n    // a different day than the customer previewed if the order is worked the next morning.\n    var cv = certValues(v);\n    props['Black hole name'] = cv.bhName;\n    props['Registry no'] = cv.regId;\n    props['Registered on'] = cv.regOn;\n    // Optional, and only for occasions whose artwork carries a title strip. Sent only when set: an\n    // empty strip is exactly what the plate already looks like, but a blank cart property reads as a\n    // mistake. WITHOUT THIS the title was collected and previewed but never reached fulfilment.\n    var ttl = (s.cardTitle || '').trim().slice(0, TITLE_MAX);\n    if (ttl && (CFG.inside2Title || {})[s.occ]) props['Card title'] = ttl;\n    if (v.sizes) props['Card size'] = v.sizes[v.size].label;\n    v.exBits.forEach(function (b, i) { props['Detail ' + (i + 1)] = b; });\n    // Also send each occasion field under its OWN name. \"Detail 1\" tells fulfilment nothing \u2014 the\n    // horoscope plate is chosen by the SIGN, and a positional label loses which field it even was.\n    if (v.ex && v.ex.fields) {\n      v.ex.fields.forEach(function (f) {\n        var val = state.extra[f.key];\n        if (!val) return;\n        props[(f.label || f.key).replace(/<[^>]*>/g, '').trim()] = val;\n        // ALSO under the field's own key, hidden (`_` prefix), because the label is presentation.\n        // The server identifies the field by key and validates it against the occasion's contract;\n        // reading the label instead would mean an operator rewording a question in the Shopify admin\n        // silently stopped a field being recognised, on live orders, with nothing to see.\n        props['_d_' + f.key] = val;\n      });\n    }\n    // The category the reading is about (spec 025 FR-016): under the step's own heading for people,\n    // and under its key for the order contract, exactly as the occasion fields are sent.\n    if (HOLEO && currentCategory()) {\n      props[copy(C.holeoCategoryTitle).replace(/<[^>]*>/g, '').trim()] = categoryLabel(currentCategory());\n      props['_d_category'] = currentCategory();\n    }\n    var items = [{ id: v.pkgVariantId, quantity: 1, properties: props }];\n    v.chosen.forEach(function (a) {\n      var sz = sizeOf(a);\n      // Backstop for a stale selection (availability changed while the wizard was open). Shopify would\n      // reject the WHOLE /cart/add for one bad line, so the extra is dropped and the order still lands.\n      if (sz && sz.available === false) return;\n      // The real cloudflare id, SAME as the main line \u2014 art.code is a display mark, and sending it\n      // here made order-worker ledger a junk \"sale\" of the code string per add-on (and on #BHR1016,\n      // the junk row won the UNIQUE(order_number) slot and the real image's never-resell row was\n      // silently dropped). With the uuid, the add-on line links to the same sold_images row instead.\n      var props = { _bundle_id: bundle, _image_id: art.id || art.code, _addon: '1' };\n      // Each add-on gets ITS OWN sku's mockup, so a puzzle line and a mug line do not share a picture.\n      if (mockupUrl && hasMockup(sz.sku)) props._mockup = mockupUrl + '&sku=' + encodeURIComponent(sz.sku);\n      // Record the size on the line item. Printful needs it to pick a catalog variant, and support\n      // needs it to answer \"which puzzle did they order\" without joining back to the variant table.\n      if (sz.label) props._size = sz.label;\n      items.push({ id: sz.variantId, quantity: 1, properties: props });\n    });\n    cartHasPrint(art.id || art.code).then(function (dupe) {\n      if (dupe) {\n        releaseCTAs(copy(C.ctaLabel));\n        alert(fill(copy(C.duplicate),\n                   { art: art.name }));\n        window.location.href = '/cart';\n        return;\n      }\n      return fetch('/cart/add.js', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ items: items }) })\n      .then(function (r) {\n        if (r.ok) {\n          // Cart-lock the chosen one-of-one so no one else can buy it while it sits in this cart.\n          if (art.id) { try { fetch(GALLERY_PATH + '/reserve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ cloudflare_id: art.id, cart_id: bundle, session: BHR_SID }) }); } catch (e) { /* non-fatal */ } }\n          window.location.href = '/cart';\n        } else { return r.json().then(function (d) { throw new Error(d.description || copy(C.addFailed)); }); }\n      })\n      .catch(function (e) { alert(e.message); releaseCTAs(copy(C.ctaLabel)); });\n    });\n  }\n\n  /* ---------- events ---------- */\n  /* ---------- art carousel drag (desktop grab-and-throw, touch swipe) ---------- */\n  // Same grab-and-throw as the art carousel. Kept separate rather than generalised because the two\n  // differ in what a release means: the art carousel also CHANGES SELECTION as it scrolls, the add-on\n  // row only scrolls.\n  var addonDrag = null;\n  mount.addEventListener('pointerdown', function (e) {\n    if (e.button && e.button !== 0) return;\n    var vp = e.target.closest && e.target.closest('[data-addonviewport]'); if (!vp) return;\n    var track = vp.firstElementChild, card = track && track.firstElementChild; if (!card) return;\n    var step = card.getBoundingClientRect().width + 10;\n    addonDrag = { x0: e.clientX, dx: 0, moved: false, track: track, step: step,\n                  base: -(state.addonCar * step), vp: vp };\n    track.style.transition = 'none';\n    vp.style.cursor = 'grabbing';\n  });\n  window.addEventListener('pointermove', function (e) {\n    if (!addonDrag) return;\n    addonDrag.dx = e.clientX - addonDrag.x0;\n    if (Math.abs(addonDrag.dx) > 4) addonDrag.moved = true;\n    addonDrag.track.style.transform = 'translateX(' + (addonDrag.base + addonDrag.dx) + 'px)';\n  });\n  window.addEventListener('pointerup', function () {\n    if (!addonDrag) return;\n    var d = addonDrag; addonDrag = null;\n    d.track.style.transition = ''; d.vp.style.cursor = 'grab';\n    if (!d.moved) return;\n    artSuppressClick = true;                     // a drag must not also tick an add-on\n    setTimeout(function () { artSuppressClick = false; }, 60);\n    var vv = vals(), per = vv.m ? 2 : 3;\n    state.addonCar = Math.max(0, Math.min(Math.max(0, vv.addons.length - per),\n                                          state.addonCar + Math.round(-d.dx / d.step)));\n    renderAll();\n  });\n\n  // The track is index-positioned, so a drag moves it freely then snaps to the nearest card on release.\n  var artDrag = null, artSuppressClick = false;\n  mount.addEventListener('pointerdown', function (e) {\n    if (e.button && e.button !== 0) return;\n    var vp = e.target.closest && e.target.closest('[data-artviewport]'); if (!vp) return;\n    var track = vp.firstElementChild, card = track && track.firstElementChild; if (!card) return;\n    var step = card.getBoundingClientRect().width + 14;   // card + gap\n    artDrag = { x0: e.clientX, dx: 0, moved: false, track: track, step: step, base: -(state.car * step), vp: vp };\n    track.style.transition = 'none';\n    vp.style.cursor = 'grabbing';\n  });\n  window.addEventListener('pointermove', function (e) {\n    if (!artDrag) return;\n    artDrag.dx = e.clientX - artDrag.x0;\n    if (Math.abs(artDrag.dx) > 4) artDrag.moved = true;\n    artDrag.track.style.transform = 'translateX(' + (artDrag.base + artDrag.dx) + 'px)';\n  });\n  window.addEventListener('pointerup', function () {\n    if (!artDrag) return;\n    var d = artDrag; artDrag = null;\n    d.track.style.transition = ''; d.vp.style.cursor = 'grab';\n    if (!d.moved) return;\n    artSuppressClick = true;                       // a drag must not also select/open a card\n    setTimeout(function () { artSuppressClick = false; }, 60);\n    state.car = Math.max(0, Math.min(vals().maxStart, state.car + Math.round(-d.dx / d.step)));\n    renderAll();\n  });\n\n  // Basic image-lifting deterrents, delegated so every art <img> the templates render \u2014 grid,\n  // carousel, lightbox, previews \u2014 is covered without touching each string. Not protection (the\n  // pixels are on screen; nothing stops a screenshot) \u2014 this only removes the two zero-effort\n  // paths: right-click \u2192 save image, and drag-out. The art is watermarked and served at web\n  // resolution through expiring signed URLs; these listeners are just the last layer of \"not\n  // worth the bother\". Scoped to the customizer so the rest of the page behaves normally.\n  ['contextmenu', 'dragstart'].forEach(function (evt) {\n    mount.addEventListener(evt, function (e) {\n      if (e.target && e.target.tagName === 'IMG') e.preventDefault();\n    });\n  });\n  // The lightbox lives outside the mount (document-level overlay), so it needs its own guard.\n  document.addEventListener('contextmenu', function (e) {\n    if (e.target && e.target.tagName === 'IMG' && e.target.closest('#bhr-lightbox')) e.preventDefault();\n  });\n\n  mount.addEventListener('click', function (e) {\n    if (artSuppressClick) { e.preventDefault(); e.stopPropagation(); return; }\n    var el = e.target.closest('[data-act]'); if (!el) return;\n    var act = el.getAttribute('data-act'), id = el.getAttribute('data-id');\n    var v = vals();\n    var advanceTo = null;\n    var focusAfter = null;   // data-key of the input the advance should hand the caret to\n    switch (act) {\n      // Picking the product is a commitment, not a browse \u2014 carry them on rather than leaving the next\n      // step below the fold. Changing the SIZE deliberately does not advance; that is a comparison.\n      case 'pkg': state.pkg = id; state.slide = 0; advanceTo = 'bhr-step-' + STEP_N.p; break;\n      case 'extraPick': state.extra[el.getAttribute('data-key')] = id; break;\n      case 'size': state.size = +id; break;\n      case 'occ':\n        // A standalone occasion's chip is a door to its own page, never a selection here.\n        for (var oi = 0; oi < OCC.length; oi++) {\n          if (OCC[oi].id === id && OCC[oi].standalone && MODE === 'black-holes' && OCC[oi].url) {\n            window.location.assign(OCC[oi].url); return;\n          }\n        }\n        state.occ = state.occ === id ? (locked ? state.occ : null) : id;\n        state.extra = {}; seedExtraDefaults(); loadGallery(state.occ);\n        // The new occasion may not offer the tone that is selected, and a selection no chip shows is\n        // worse than a changed one \u2014 it draws from a bucket this occasion does not have.\n        clampTone();\n        // A Registry-written-only occasion overrides the writer toggle the moment it is chosen \u2014\n        // arriving at horoscope with \"I'll write it myself\" still set would preview a horoscope\n        // card with no horoscope on it.\n        if (writerLocked() && !state.schrod) { state.schrod = true; ensureDrawn(); }\n        state.drawn = null; fetchDrawn();\n        // Same forward-carry as product and art: choosing an occasion advances to the black hole\n        // step. Only on SELECT \u2014 clicking the active chip to deselect must not scroll anywhere.\n        // The aim-hold in scrollAfterStep rides out the gallery + drawn-copy fetches reflowing\n        // the page after this click.\n        if (state.occ === id) advanceTo = 'bhr-step-' + STEP_N.a;\n        break;\n      case 'tone': state.tone = id; state.drawn = null; fetchDrawn(); break;\n      case 'category': state.category = id; state.drawn = null; fetchDrawn(); break;\n      case 'acrostic': state.acrosticShown = !state.acrosticShown; break;\n      // The lock wins over a stale button: the writer group hides \"self\" when locked, but a click\n      // racing an occasion change could still deliver one.\n      case 'writer': if (writerLocked() && id !== 'schrod') break;\n        state.schrod = (id === 'schrod'); if (state.schrod) ensureDrawn(); break;\n      // Breaking the seal. Deliberately does NOT re-render: the flap opens by transitioning a class on\n      // the element that is already there, and a re-render would hand CSS a brand-new element already\n      // at its end state, which transitions from nothing and simply appears open. Both envelopes are\n      // opened together \u2014 one card, one seal.\n      case 'openCard': {\n        if (state.opened) return;\n        state.opened = true;\n        var envs = mount.querySelectorAll('.bhr-env');\n        for (var ei = 0; ei < envs.length; ei++) envs[ei].classList.add('is-open');\n        return;\n      }\n      // Draws another inside message, and turns the preview to the face that just changed rather than\n      // leaving them to find it. Located by FACE, not by index: the box package's slides are box,\n      // certificate and art print, with no inside spread at all, and a hardcoded 1 would have turned\n      // it to the certificate and shown nothing new.\n      case 'reroll':\n        if (!drawMessage()) return;\n        // Ask the pool for a different one, excluding what is on screen. drawMessage() above still\n        // advances the local counter, which is what the button's remaining-count and the placeholder\n        // fallback read.\n        fetchDrawn({ reroll: true });\n        // The envelope seals again (operator, 2026-09-03): a new message is opened fresh, the way the\n        // first one was, rather than swapped in under an open flap.\n        state.opened = false;\n        for (var ri = 0; ri < v.slides.length; ri++) {\n          if (v.slides[ri].face === 'open') { state.slide = ri; break; }\n        }\n        break;\n      case 'fmt':\n        document.execCommand(el.getAttribute('data-cmd'), false, null);\n        var ce = mount.querySelector('[data-act=\"cardmsg\"]');\n        if (ce) { state.msg = cleanMsg(ce.innerHTML); ce.focus(); }\n        return;\n      // Clicking a card both selects it and opens the big view \u2014 one click to choose AND inspect.\n      // Choosing the black hole is the same commitment as choosing the product: carry the shopper\n      // on to Personalize (tone + recipient) rather than leaving it below the fold. scrollAfterStep\n      // goes to the step AFTER the one named, so this lands on 04 with the Recipient's name in view.\n      // No lightbox on select any more (state.lb stays untouched): a click chooses and moves on;\n      // the zoom icon on every card is the deliberate way into the viewer.\n      case 'art': state.art = +id; advanceTo = 'bhr-step-' + STEP_N.at; focusAfter = 'name'; break;\n      case 'zoom': e.stopPropagation(); state.lb = +id; renderLightbox(); return;\n      case 'prevArt': state.car = Math.max(0, state.car - 1); state.art = Math.max(0, state.art - 1); break;\n      case 'nextArt':\n        state.car = Math.min(v.maxStart, state.car + 1); state.art = Math.min(ART.length - 1, state.art + 1);\n        if (state.car >= v.maxStart - 1) loadMore();\n        break;\n      case 'surprise': var i = Math.floor(Math.random() * ART.length); state.art = i; state.car = Math.min(v.maxStart, Math.max(0, i - 1)); break;\n      // Size pills sit INSIDE the add-on button. closest('[data-act]') resolves to the pill first, so the\n      // toggle below never fires \u2014 picking a size changes the size, it does not add or remove the add-on.\n      // Deliberately does not auto-select: someone comparing a 252-piece against a 2000-piece is shopping,\n      // not committing, and silently adding \u00A340 to their total on a price check would be hostile.\n      case 'addonSize':\n        state.addonSize[id] = +el.getAttribute('data-i');\n        // Switching an ADDED add-on to a sold-out size would silently carry an unsellable line into the\n        // cart. Drop the selection instead \u2014 the size is still browsable, it just is not added.\n        if (state.addons.indexOf(id) > -1) {\n          var _sa = findAddon(id);\n          if (_sa && !addonSellable(_sa)) state.addons = state.addons.filter(function (x) { return x !== id; });\n        }\n        break;\n      case 'addonView': state.addonView[id + '@' + sizeIdx(findAddon(id))] = +el.getAttribute('data-i'); break;\n      case 'addonViewPrev': case 'addonViewNext': {\n        var _a = findAddon(id); if (!_a) return;\n        var _n = viewsOf(_a).length; if (_n < 2) return;\n        var _k = id + '@' + sizeIdx(_a), _i = viewIdx(_a);\n        state.addonView[_k] = (_i + (act === 'addonViewNext' ? 1 : _n - 1)) % _n;\n        break;\n      }\n      case 'addonZoom': state.alb = { id: id, i: viewIdx(findAddon(id)) }; renderAddonLightbox(); return;\n      case 'prevAddon': state.addonCar = Math.max(0, state.addonCar - 1); break;\n      case 'nextAddon': state.addonCar = Math.min(Math.max(0, v.addons.length - (v.m ? 2 : 3)), state.addonCar + 1); break;\n      case 'addon':\n        var on = state.addons.indexOf(id) > -1;\n        // Refuse to ADD a sold-out size; removing one is always allowed.\n        if (!on) { var _na = findAddon(id); if (_na && !addonSellable(_na)) return; }\n        state.addons = on ? state.addons.filter(function (x) { return x !== id; }) : state.addons.concat(id);\n        break;\n      case 'addToCart': addToCart(el); return;\n      case 'prevSlide': state.slide = (state.slide + v.slides.length - 1) % v.slides.length; renderRailOnly(); bhrAutoStart(); return;\n      case 'nextSlide': state.slide = (state.slide + 1) % v.slides.length; renderRailOnly(); bhrAutoStart(); return;\n      case 'slide': state.slide = +id; renderRailOnly(); bhrAutoStart(); return;\n      default: return;\n    }\n    renderAll();\n    if (advanceTo) scrollAfterStep(advanceTo);\n    if (focusAfter) focusField(focusAfter);\n  });\n  // lightbox controls (rendered outside mount, on document)\n  document.addEventListener('click', function (e) {\n    var el = e.target.closest('[data-act]'); if (!el) return;\n    var act = el.getAttribute('data-act');\n    // Add-on viewer. Its nav shares data-act names with the panel's, so those cases are handled by the\n    // mount-scoped handler; only the controls that exist solely in the viewer live here.\n    if (act === 'closeAlb') { state.alb = null; renderAddonLightbox(); renderAll(); return; }\n    if (act === 'albStage') { e.stopPropagation(); return; }\n    if (act === 'albSize') {\n      e.stopPropagation();\n      var _a = findAddon(state.alb && state.alb.id); if (!_a) return;\n      state.addonSize[_a.id] = +el.getAttribute('data-i');\n      renderAddonLightbox(); return;\n    }\n    if (act === 'albToggle') {\n      e.stopPropagation();\n      var _id = el.getAttribute('data-id'), _on = state.addons.indexOf(_id) > -1;\n      if (!_on) { var _la = findAddon(_id); if (_la && !addonSellable(_la)) return; }\n      state.addons = _on ? state.addons.filter(function (x) { return x !== _id; }) : state.addons.concat(_id);\n      renderAddonLightbox(); return;\n    }\n    if (state.alb && (act === 'addonView' || act === 'addonViewPrev' || act === 'addonViewNext')) {\n      e.stopPropagation();\n      var _a2 = findAddon(el.getAttribute('data-id')); if (!_a2) return;\n      var _n2 = viewsOf(_a2).length, _k2 = _a2.id + '@' + sizeIdx(_a2);\n      state.addonView[_k2] = act === 'addonView' ? +el.getAttribute('data-i')\n        : (viewIdx(_a2) + (act === 'addonViewNext' ? 1 : _n2 - 1)) % _n2;\n      renderAddonLightbox(); return;\n    }\n    if (act === 'openPanel') { e.stopPropagation(); state.panel = +el.getAttribute('data-id'); renderPanelLightbox(); return; }\n    if (act === 'plbStage') { e.stopPropagation(); return; }\n    if (act === 'closePanel') {\n      state.panel = null; renderPanelLightbox();\n      // Values typed in the viewer only reached state; the panels behind it are stale until now.\n      renderCardStage(); return;\n    }\n    if (act === 'panelPrev' || act === 'panelNext') {\n      e.stopPropagation();\n      state.panel = (state.panel + (act === 'panelNext' ? 1 : PANEL_N - 1)) % PANEL_N;\n      renderPanelLightbox(); return;\n    }\n    if (act === 'closeLb') { state.lb = null; renderLightbox(); }\n    else if (act === 'lbPrev') { e.stopPropagation(); state.lb = (state.lb + ART.length - 1) % ART.length; renderLightbox(); }\n    else if (act === 'lbNext') {\n      e.stopPropagation();\n      if (state.lb >= ART.length - 1 && !_galleryEnd) {\n        loadMore(function () { if (state.lb < ART.length - 1) state.lb++; renderLightbox(); });\n        return;\n      }\n      state.lb = (state.lb + 1) % ART.length; renderLightbox();\n    }\n    // Selecting from the viewer advances the same way a card click does \u2014 the commitment is the\n    // same act, so it must not matter which door it came through.\n    else if (act === 'lbSelect') { e.stopPropagation(); state.art = state.lb; state.car = Math.min(vals().maxStart, Math.max(0, state.lb - 1)); state.lb = null; renderAll(); scrollAfterStep('bhr-step-' + STEP_N.at); focusField('name'); }\n  });\n  // Lightbox drag/swipe \u2014 same gesture as the carousel; a short throw moves one image.\n  var lbDrag = null;\n  document.addEventListener('pointerdown', function (e) {\n    var stage = e.target.closest && e.target.closest('[data-lbdrag]'); if (!stage) return;\n    lbDrag = { x0: e.clientX, moved: false, img: stage.querySelector('img') };\n  });\n  document.addEventListener('pointermove', function (e) {\n    if (!lbDrag) return;\n    var dx = e.clientX - lbDrag.x0;\n    if (Math.abs(dx) > 4) lbDrag.moved = true;\n    if (lbDrag.img) { lbDrag.img.style.transition = 'none'; lbDrag.img.style.transform = 'translateX(' + (dx * 0.35) + 'px)'; }\n  });\n  document.addEventListener('pointerup', function (e) {\n    if (!lbDrag) return;\n    var d = lbDrag; lbDrag = null;\n    if (d.img) { d.img.style.transition = 'transform .25s ease'; d.img.style.transform = ''; }\n    if (!d.moved || state.lb === null) return;\n    var dx = e.clientX - d.x0;\n    if (Math.abs(dx) < 40) return;\n    if (dx < 0) {\n      if (state.lb >= ART.length - 1 && !_galleryEnd) { loadMore(function () { if (state.lb < ART.length - 1) state.lb++; renderLightbox(); }); return; }\n      state.lb = (state.lb + 1) % ART.length;\n    } else {\n      state.lb = (state.lb + ART.length - 1) % ART.length;\n    }\n    renderLightbox();\n  });\n\n  // On document, not mount: the panel lightbox is portaled to <body>, so a mount-scoped listener would\n  // never see typing inside it.\n  document.addEventListener('input', function (e) {\n    var el = e.target.closest('[data-act=\"text\"],[data-act=\"extra\"],[data-act=\"cardmsg\"],[data-act=\"certfield\"],[data-act=\"bhname\"]'); if (!el) return;\n    var act = el.getAttribute('data-act');\n    if (act === 'bhname') {\n      // Pin the name ONLY when it differs from the default the field was rendered with \u2014 an\n      // untouched (or retyped-identical) field keeps following the art and the drawn title.\n      var bv = el.value;\n      state.bhName = bv.trim() === (el.getAttribute('data-def') || '').trim() ? '' : bv;\n      renderRailOnly(); renderCardStage();\n      return;\n    }\n    if (act === 'cardmsg') {\n      // The on-card message: sync state + the char counter only \u2014 DON'T re-render the card, or the caret jumps.\n      state.msg = cleanMsg(el.innerHTML);\n      var len = msgLen(state.msg), c = document.getElementById('bhr-msg-count');\n      if (c) { c.textContent = len + '/' + MSG_MAX; c.style.color = len > MSG_MAX ? '#c0392b' : MUTED; }\n      // Mirror into the card preview directly. Re-rendering the panel would work, but this runs on every\n      // keystroke and rebuilding the stage would drop the caret out of the field being typed in.\n      var prev = document.querySelectorAll('.bhr-i2-msg');\n      for (var pi = 0; pi < prev.length; pi++) {\n        prev[pi].innerHTML = state.msg;\n        if (len) prev[pi].classList.remove('bhr-i2-empty'); else prev[pi].classList.add('bhr-i2-empty');\n      }\n      fitMessageBox();\n      renderRailOnly();\n      return;\n    }\n    if (act === 'certfield') {\n      // A hot area on the certificate. Re-fit THIS field only: re-rendering the plate would drop the\n      // caret mid-word. certTo is not its own field \u2014 it is the recipient the rest of the form uses.\n      var ck = el.getAttribute('data-key'), ctxt = el.textContent;\n      if (ck === 'certTo') {\n        state.name = ctxt;\n        // The recipient also has a form input above. Push the value across directly rather than\n        // re-rendering, which would blur the field being typed in.\n        var ni = mount.querySelector('[data-act=\"text\"][data-key=\"name\"]');\n        if (ni && ni.value !== ctxt) ni.value = ctxt;\n      } else {\n        state[ck] = ctxt;\n        // The name also has a form input now. Same mirror as certTo: push across, never re-render.\n        if (ck === 'bhName') {\n          var bi = mount.querySelector('[data-act=\"bhname\"]');\n          if (bi && bi.value !== ctxt) bi.value = ctxt;\n        }\n      }\n      var cf = certField(ck);\n      if (cf) el.style.fontSize = certSize(ctxt, cf).toFixed(3) + 'cqw';\n      renderRailOnly();\n      return;\n    }\n    // Update the rail summary + the step-04 card mockup, but NOT the whole left panel \u2014 so the field keeps focus.\n    var _k = el.getAttribute('data-key');\n    if (el.value && String(el.value).trim()) clearFlag(_k);\n    if (act === 'text') { state[_k] = el.value; renderRailOnly(); renderCardStage(); }\n    else { state.extra[_k] = el.value; renderRailOnly(); renderCardStage(); }\n  });\n  // Keep the message selection when clicking B/I so execCommand applies to the highlighted text.\n  mount.addEventListener('mousedown', function (e) { if (e.target.closest && e.target.closest('[data-act=\"fmt\"]')) e.preventDefault(); });\n  mount.addEventListener('change', function (e) {\n    var el = e.target.closest('[data-act=\"extra\"]'); if (!el) return;\n    // renderAll (not just the rail) so the 02\u00B7 detail sub-step re-evaluates its required-missing highlight\n    // + gating on blur / select-change. (Live typing uses the 'input' handler above to keep field focus.)\n    state.extra[el.getAttribute('data-key')] = el.value; renderAll();\n  });\n\n  /* ---------- preview carousel auto-advance ---------- */\n  // Flip the preview slides every AUTO_MS. Pauses while the cursor is over the carousel, when the tab is\n  // hidden, or if the user prefers reduced motion. Manual nav (arrows/dots) restarts the timer so it never\n  // double-advances right after a click.\n  var AUTO_MS = 5000, autoPaused = false;\n  var prefersReduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n  function bhrAutoStop() { if (window._bhrAuto) { clearInterval(window._bhrAuto); window._bhrAuto = null; } }\n  function bhrAutoStart() {\n    bhrAutoStop();\n    if (prefersReduce || vals().slides.length <= 1) return;\n    window._bhrAuto = setInterval(function () {\n      if (autoPaused || document.hidden) return;\n      var n = vals().slides.length; if (n <= 1) return;\n      state.slide = (state.slide + 1) % n; renderRailOnly();\n    }, AUTO_MS);\n  }\n  mount.addEventListener('mouseover', function (e) { autoPaused = !!(e.target.closest && e.target.closest('[data-carousel]')); });\n  mount.addEventListener('mouseleave', function () { autoPaused = false; });\n\n  window.addEventListener('resize', function () { clearTimeout(window._bhrRz); window._bhrRz = setTimeout(renderAll, 150); });\n\n  // A mockup overlay whose pixel dimensions were never recorded (the legacy single-mockup fallback, or\n  // a view added without w/h) shapes its frame from the image itself as soon as it decodes. The art is\n  // positioned in percentages OF THAT FRAME, so until the frame has the overlay's real aspect the two\n  // layers disagree and the art sits off the print.\n  //\n  // Capture phase: `load` does not bubble, so a listener on document only sees it on the way down.\n  document.addEventListener('load', function (e) {\n    var img = e.target;\n    if (!img || img.tagName !== 'IMG' || img.getAttribute('data-fit') !== '1') return;\n    var frame = img.parentNode;\n    if (!frame || !img.naturalWidth || !img.naturalHeight) return;\n    var sa = parseFloat(frame.getAttribute('data-sa')) || (4 / 3);\n    var fa = img.naturalWidth / img.naturalHeight;\n    frame.style.aspectRatio = img.naturalWidth + '/' + img.naturalHeight;\n    // Same axis binding as the declared-w/h path: bind the constraining axis, derive the other.\n    if (fa >= sa) { frame.style.width = '100%'; frame.style.height = 'auto'; }\n    else { frame.style.height = '100%'; frame.style.width = 'auto'; }\n    img.removeAttribute('data-fit');   // renderAll() re-emits the attribute; never re-measure in place\n  }, true);\n  seedExtraDefaults();\n  // The section's default occasion may itself be Registry-written-only; the lock applies from the\n  // first paint, not from the first occasion click.\n  if (writerLocked()) state.schrod = true;\n  renderAll();\n  // Shrink-to-fit measures with canvas, which does NOT wait for webfonts \u2014 the first paint sizes the\n  // certificate against a fallback metric, so the registry number can be mis-fitted until Nebula lands.\n  if (document.fonts && document.fonts.ready) document.fonts.ready.then(function () { renderCardStage(); fitHeroName(); });\n  bhrAutoStart();\n  loadGallery(state.occ);   // swap the static art for the live per-occasion gallery once it loads\n  // The Registry writing the inside is the DEFAULT now, so the curated pair is wanted on first paint,\n  // not on first interaction. The card renders immediately with the fallback and repaints when the\n  // real copy lands \u2014 a blank panel while a fetch resolves is worse than one that improves.\n  ensureDrawn();\n})();\n"],
  "mappings": "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",
  "names": ["fill", "pick", "vals", "navBtn", "props", "step"]
}
